TestAtlas

A queryable, semantic map of your .NET test-automation solution — in one SQLite file, served to your AI agent over MCP.

Zero config  ·  No AI  ·  No network  ·  Deterministic

TestAtlas.Mcp on NuGet TestAtlas.Cli on NuGet Model Context Protocol — listed Glama — listed .NET 8.0 MIT license

TestAtlas on Glama: license, quality and maintenance grades

11 MCP tools
resolve_step · step_catalog · impact · search_steps · search_scenarios · get_scenario · get_step_definition · list_tags · list_endpoints · project_dependencies · stats

The problem · See it in action · Quick start · MCP · Commands · Fresh maps · Roadmap

--- ## The problem Large test-automation solutions are hard to navigate — for humans *and* for AI agents. Asked to automate a new story, an agent can't see which steps already exist, where similar code lives, or what conventions the solution follows — so it duplicates steps and misplaces code. TestAtlas indexes the solution once into a single SQLite map and answers those questions precisely: deterministically, offline, without a model or a network call. --- ## See it in action Index the bundled 8-project sample once — `testatlas index samples/SampleShop/SampleShop.sln` — then ask it questions from the terminal. Every number below is real output from that run: ```console $ testatlas stats sampleshop.db TestAtlas map: sampleshop.db (schema v5) totals: 8 project(s), 15 class(es), 36 method(s), 14 step definition(s) class kinds: api_client 7 page_object 4 step_class 4 gherkin: 4 feature(s), 5 scenario(s), 16 step(s) bound steps: 16 · unbound: 0 · ambiguous: 0 endpoints: 3 (3 call site(s)) ``` …or let your agent ask them over MCP. Here an agent checks whether a step it is about to write already exists — `resolve_step` answers with the definitions that would bind it, or the closest near-misses to reuse instead: ```jsonc // agent → testatlas: resolve_step { "text": "I add the product to my cart" } { "status": "none", // nothing binds this exact text — don't invent it from scratch: "suggestions": [ // these existing steps are the closest, ranked by shared terms { "expression": "product (.*) is added to the cart with quantity (.*)", "keyword": "When", "location": "SampleShop.Tests.Api/Steps/CatalogApiSteps.cs:34" }, { "expression": "the cart is not empty", "keyword": "Then", "location": "SampleShop.Tests.Api/Steps/CatalogApiSteps.cs:43" } // …8 more ] } ``` Live sample outputs, committed from that same solution: **[HTML report](https://htmlpreview.github.io/?https://github.com/Karzone/TestAtlas/blob/main/docs/sample-report.html)** (features, scenarios, bindings, class kinds, endpoints) · **[dependency map](https://htmlpreview.github.io/?https://github.com/Karzone/TestAtlas/blob/main/docs/sample-map.html)** (the eight projects in layers — click one to see what it uses, what uses it, and which tests a change can reach). (GitHub serves `.html` as source, so the links route through htmlpreview.github.io — or download from [`docs/`](docs/) and open locally.) ## What you get TestAtlas statically analyses the solution and emits `codemap.db` — projects and their dependency edges, Gherkin features/scenarios/steps, step definitions and their bindings (bound / unbound / ambiguous), page objects, API clients, helpers, test classes, and the call/usage edges connecting them — then turns that map into answers: | | Capability | What you get | |:--:|---|---| | 🧩 | **Reuse-first authoring** | `resolve_step` — would this phrase bind an existing definition? `step_catalog` — the reusable step vocabulary with placeholders + allowed values | | 💥 | **Impact** | Blast radius — the scenarios affected by changing a class, method, step, or endpoint | | 🔍 | **Search** | FTS5 over step definitions + scenarios — *"does a step for this already exist?"* | | 🔌 | **MCP** | All of it served to an AI agent over stdio — precise answers in a few hundred tokens, no context stuffing | | 📊 | **Report & map** | Self-contained HTML drill-down of the whole map + a layered, searchable project-dependency graph | | 📈 | **Stats** | Entity counts, class-kind breakdown, binding coverage, diagnostics | All of it **offline, deterministic, and reproducible** — same input, same map, every time. --- ## 🚀 Quick start > **Requires** the [.NET SDK 8.0+](https://dotnet.microsoft.com/download). On a corporate machine > where `dotnet tool install` fails with **401**, see > [docs/troubleshooting.md](docs/troubleshooting.md). **1 — Install** the CLI (and the MCP server, if you'll connect an agent): ```bash dotnet tool install --global TestAtlas.Cli dotnet tool install --global TestAtlas.Mcp ``` **2 — Index** your solution. This produces the map (`./codemap.db`) that every query, report, and MCP answer reads — nothing works without it: ```bash testatlas index path/to/YourSolution.sln ``` No need to build or restore the solution first — indexing is a syntax-only pass, so an unrestored checkout maps fine. Point `index` at a folder (or nothing) and it auto-discovers a single `.sln`/`.csproj` there. **3 — Query it:** ```bash testatlas stats testatlas search "login" testatlas report # writes codemap.html testatlas map # writes codemap-map.html ``` …and to serve it to your AI agent, continue to [MCP setup](#-use-it-from-an-ai-agent-mcp).
Or run from source (no install) ```bash git clone https://github.com/Karzone/TestAtlas.git cd TestAtlas dotnet build TestAtlas.sln dotnet run --project src/CodeMap.Cli -- index path/to/YourSolution.sln ```
--- ## 🔌 Use it from an AI agent (MCP) TestAtlas ships an MCP server — `testatlas-mcp` — that serves the map to any MCP-aware client (Visual Studio / VS Code Copilot, Claude Code, and others) over stdio JSON-RPC. The agent asks a precise question and gets an exact, structured answer straight from the `.db` — instead of stuffing source files into its context window. Prerequisites: **both tools installed and a map built** — steps 1–2 of the [Quick start](#-quick-start). Then register the server: **Visual Studio / VS Code** (GitHub Copilot agent mode) — add to your `.mcp.json` (`%USERPROFILE%\.mcp.json` or `\.mcp.json`): ```json { "servers": { "testatlas": { "type": "stdio", "command": "testatlas-mcp", "args": ["C:\\path\\to\\codemap.db"] } } } ``` **Pass the map path explicitly** (as above, or via a `TESTATLAS_DB` env var) — most agents launch the server from their own working directory, not your solution folder, so relying on auto-discovery leaves the server with no map: it starts and lists its tools, but every call answers with an error saying how to supply one (releases before 0.1.11 exited with `code 2` instead). In Visual Studio you can also use **Tools picker → `+` → Add custom MCP server** to write this entry for you. On the .NET 10 SDK you can skip the install and use `"command": "dnx", "args": ["TestAtlas.Mcp", "--yes", "C:\\path\\to\\codemap.db"]` — `dnx` fetches and runs the server on demand. **Claude Code — as a plugin** (server, a skill that says when to use which tool, `/testatlas:index`, `/testatlas:report`, and a session-start check that tells Claude when the map is missing or stale): ```bash claude plugin marketplace add Karzone/TestAtlas claude plugin install testatlas@testatlas ``` The plugin starts `testatlas-mcp` with no arguments, so it serves the `codemap.db` at the root of whatever project the session is opened in — build it with `/testatlas:index`; from 0.1.12 the server picks the map up on the next call, with nothing to reconnect. Both tools must be on the PATH (`dotnet tool install --global TestAtlas.Cli`, then the same for `TestAtlas.Mcp`). The plugin lives in [`claude-plugin/`](claude-plugin/). **Claude Code — one server, no plugin:** ```bash claude mcp add testatlas -- testatlas-mcp path/to/codemap.db claude mcp list # the testatlas row should read: ✔ Connected ``` By default the server is registered for the **current project** (`--scope local`). Add `--scope user` to make it available in every project on your machine, or `--scope project` to share the registration with your team via a committed `.mcp.json`. > [!IMPORTANT] > MCP clients load servers **at session start** — if you register mid-session, restart your agent > session before the `testatlas` tools appear. To confirm it's actually being used (and not > silently ignored), run the checks in > [docs/troubleshooting.md](docs/troubleshooting.md#the-agent-doesnt-seem-to-use-testatlas). **Tools exposed:** - `resolve_step` — resolve a Gherkin phrase to the existing step definition(s) that would bind it (regex/cucumber, keyword-agnostic). `exact` / `ambiguous` / `none` (+ near-match suggestions ranked by shared terms). Reuse-first authoring: don't write a step that already exists. - `step_catalog` — the reusable step vocabulary with extracted placeholders and allowed values (cucumber `{type}`, regex `(a|b)` enums). Compose scenarios from what exists. - `impact` — blast radius of a change: the scenarios affected by a given class, method, step definition, or endpoint. - `search_steps` — full-text search over step definitions (expression text + method + class name). - `search_scenarios` — full-text search over scenarios (feature + scenario name + step text + tags). - `get_scenario` — full detail of scenario(s) by name: feature, tags, kind, example-row count, and the ordered steps. - `get_step_definition` — full detail of step definition(s) by expression: keyword, params, C# class/method/signature, and the scenarios that use it. - `list_tags` — the tag taxonomy with per-tag scenario counts, most-used first — tag new scenarios consistently. - `list_endpoints` — the HTTP endpoints the suite calls, each with verb, route, and scenario blast radius (highest-reach first). - `project_dependencies` — the implied project dependency graph (depends-on / depended-on-by), e.g. *"what depends on the Party project?"*. - `stats` — summary counts: projects, classes, methods, class-kind breakdown, endpoints, and edge tallies. Retrieval runs locally against the SQLite file — deterministic, offline, and a few hundred tokens per answer. Protocol details in [`specs/codemap-mcp.md`](specs/codemap-mcp.md); registration from source and every failure mode in [docs/troubleshooting.md](docs/troubleshooting.md). --- ## 📖 Commands | Command | What it does | | --- | --- | | `index []` | Analyse a `.sln`/`.csproj` and write the map (default `./codemap.db`). | | `stats []` | Entity counts per project, unbound/ambiguous steps, diagnostics. | | `search [] ` | FTS5 full-text search over step definitions and scenarios. | | `impact [] --class\|--method\|--step\|--endpoint ` | Blast radius: scenarios affected by changing an entity. | | `report []` | Write a self-contained HTML drill-down of the map. | | `map []` | Write a self-contained project dependency graph (HTML). | | `validate []` | Check a file is a supported TestAtlas map. |
Options & exit codes
**`index`**  `--output ` · `--config ` · `--include ` (repeatable) · `--exclude ` (repeatable) · `--verbose` · `--quiet` **`search`**  `--steps` (step definitions only) · `--scenarios` (scenarios only) **Exit codes**  `0` ok · `1` completed with warnings · `2` fatal · `3` bad arguments Run `testatlas --help` for the full usage text.
A typical session
```bash # Index the solution (no build needed — the pass is syntax-only) testatlas index YourSolution.sln --output atlas.db # Before writing a new step — does one already exist? testatlas search atlas.db "add a product to the cart" --steps # About to change a shared client — what will it hit? testatlas impact atlas.db --class ProductsApiClient # Share human-readable snapshots testatlas report atlas.db --html atlas.html testatlas map atlas.db --html atlas-map.html ```
About the bundled sample (SampleShop)
[`samples/SampleShop`](samples/SampleShop) is a self-contained **8-project** solution mixing API tests and UI tests, so the map has plenty of connected nodes — real `HttpClient` API clients, real Selenium `IWebDriver` page objects, and Reqnroll suites driving both: ```text ┌─▶ Api.Catalog ──┐ Tests.Api ────────────┼─▶ Api.Cart ──┤ Tests.E2E ──┬─────────┴─▶ Api.Identity ──┼─▶ Core (ApiClientBase : HttpClient) └─▶ Ui.Pages ─────────────────┘ (PageBase : IWebDriver) Tests.Ui ────▶ Ui.Pages ──────────────────▶ Core ``` Reproduce the committed sample outputs yourself: ```bash testatlas index samples/SampleShop/SampleShop.sln --output sampleshop.db testatlas report sampleshop.db --html docs/sample-report.html testatlas map sampleshop.db --html docs/sample-map.html ```
--- ## 🔄 Keeping the map fresh Answers are deterministic — but only as fresh as the map, so re-index on *change*, not on a timer. A full re-index is a single static pass (**seconds**), and its cost scales with solution size, not with how much changed: - **Locally** — `python scripts/check-map-age.py` tells you when your map drifted; a version-controlled `post-merge` git hook can warn automatically after every pull. - **In CI (team model)** — re-index on every merge to main and publish the `.db` to a shared feed (never commit it — it's a build artifact). Then teammates and agents only need **`TestAtlas.Mcp`** locally: download the shared map and point `TESTATLAS_DB` at it — no local `TestAtlas.Cli` or indexing required. (Index locally only to include your own *uncommitted* branch work.) Details — the staleness checker, the git hook, and copy-paste CI recipes (GitHub Actions + Azure DevOps with a Universal feed) — in **[docs/keeping-the-map-fresh.md](docs/keeping-the-map-fresh.md)**. --- ## 🧹 Uninstall Two separate things — remove them in this order, so the editor isn't launching a server whose binary just vanished: 1. **Remove the MCP registration** — delete the `testatlas` block from your `.mcp.json` (`\.mcp.json` or `%USERPROFILE%\.mcp.json`), then restart Visual Studio / VS Code. (Or just toggle it off in the agent's tools/wrench picker to keep it for later.) 2. **Uninstall the tools** — they're .NET global tools, not editor add-ins: ```bash dotnet tool uninstall --global TestAtlas.Mcp dotnet tool uninstall --global TestAtlas.Cli dotnet tool list --global # confirm they're gone ``` 3. **(Optional)** delete the `codemap.db` map file — it's just data, nothing else references it. --- ## 🎯 Design tenets - **Zero config** — a useful map on an unseen solution, no config file required. - **Solution agnostic** — heuristic, overridable detection; no company-specific assumptions. - **Deterministic & offline** — same input ⇒ byte-equivalent logical content; no network, no AI. - **Graceful degradation** — solutions without Gherkin still yield a useful map. - **Public schema as contract** — a versioned SQLite schema, so downstream consumers keep working even if a third party swaps in their own indexer. The project folders use the indexer's working name (**CodeMap**); the shipped tools and packages are **TestAtlas**. Full specs: [`specs/codemap-indexer.md`](specs/codemap-indexer.md) · [`specs/codemap-mcp.md`](specs/codemap-mcp.md). Repo layout: [CONTRIBUTING.md](CONTRIBUTING.md#project-layout). --- ## 🗺 Roadmap - [x] **Indexer CLI** — C# indexer + documented, versioned SQLite schema - [x] **HTML visualization** — self-contained report + project map generated from the db - [x] **MCP server** — `testatlas-mcp` exposes the map to AI agents over stdio JSON-RPC (11 tools) - [ ] **Second-language indexer** — same schema, contract-tested **Deliberately not planned** (see [design tenets](#-design-tenets)): LLM-assisted analysis inside the indexer, network calls at index/query time, running or generating tests, and semantic (compilation-based) analysis that would require a restored build. Releases and per-version notes live on the [releases page](https://github.com/Karzone/TestAtlas/releases); current distribution channels in [docs/DISTRIBUTION.md](docs/DISTRIBUTION.md). --- ## 📄 License [MIT](LICENSE) © 2026 Karthik Kalaiyarasu