TestAtlas.Mcp
0.1.1
dotnet tool install --global TestAtlas.Mcp --version 0.1.1
dotnet new tool-manifest
dotnet tool install --local TestAtlas.Mcp --version 0.1.1
#tool dotnet:?package=TestAtlas.Mcp&version=0.1.1
nuke :add-package TestAtlas.Mcp --version 0.1.1
<h1 align="center">πΊοΈ TestAtlas</h1>
<p align="center"> <strong>A queryable, semantic map of your .NET test-automation solution β in one SQLite file.</strong> </p>
<p align="center"> <em>Zero config Β· No AI Β· No network Β· Deterministic</em> </p>
<p align="center"> <img alt="status" src="https://img.shields.io/badge/status-v0.1%20draft-orange"> <a href="https://www.nuget.org/packages/TestAtlas.Cli"><img alt="nuget" src="https://img.shields.io/nuget/v/TestAtlas.Cli?logo=nuget&label=NuGet&color=004880"></a> <img alt="dotnet" src="https://img.shields.io/badge/.NET-8.0-512BD4?logo=dotnet&logoColor=white"> <img alt="output" src="https://img.shields.io/badge/output-SQLite-003B57?logo=sqlite&logoColor=white"> <img alt="mcp" src="https://img.shields.io/badge/MCP-ready-7C3AED"> <img alt="license" src="https://img.shields.io/badge/license-MIT-blue"> </p>
<p align="center"> <a href="#-quick-start">Quick start</a> Β· <a href="#-commands">Commands</a> Β· <a href="#-use-it-from-an-ai-agent-mcp">MCP</a> Β· <a href="#-see-it-on-a-real-sample">Sample</a> Β· <a href="#-keeping-the-map-fresh">Keeping fresh</a> Β· <a href="#-roadmap">Roadmap</a> </p>
What it does
TestAtlas statically analyses a .NET test-automation solution and emits a semantic map β
codemap.db, a single SQLite file β that captures:
- Projects and their dependency edges
- Gherkin features, scenarios, and steps
- Step definitions and their bindings (bound / unbound / ambiguous)
- Page objects, API clients, helpers, and test classes
- The call and usage edges that connect them all
β¦and turns that map into precise answers:
| Capability | What you get | |
|---|---|---|
| π | Search | FTS5 over step definitions + scenarios β "does a step for this already exist?" |
| π₯ | Impact | Blast radius β the scenarios affected by changing a class, method, step, or endpoint |
| π | Report | A self-contained HTML drill-down of the whole map |
| πΈοΈ | Map | A self-contained project-dependency graph (HTML) |
| π | MCP | Serve the map to an AI agent over stdio β no context stuffing |
| π | Stats | Entity counts, class-kind breakdown, binding coverage, diagnostics |
All of it offline, deterministic, and reproducible β same input, same map, every time.
The indexer spec uses "CodeMap" as the working name for the tool/CLI (testatlas verb,
codemap.db output). The repository and product are TestAtlas.
Why
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 where similar code lives, which steps already exist, or what conventions the solution follows. So it duplicates steps and misplaces code.
TestAtlas indexes the solution once and hands both people and agents a structured map to answer those questions β deterministically, without a model or a network call.
π Quick start
Requires .NET SDK 8.0+
Install the CLI as a global .NET tool from NuGet:
dotnet tool install --global TestAtlas.Cli
β¦then, from any directory:
# Index a solution β produces ./codemap.db
testatlas index path/to/YourSolution.sln
# Explore it
testatlas stats
testatlas search "login"
testatlas report # writes codemap.html
Run index with no path and TestAtlas auto-discovers a single .sln/.csproj in the current
directory. The map is written atomically to ./codemap.db.
<details> <summary><b>Or run from source</b> (no install)</summary>
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
</details>
π Commands
| Command | What it does |
|---|---|
index [<path>] |
Analyse a .sln/.csproj and write the map (default ./codemap.db). |
stats [<db>] |
Entity counts per project, unbound/ambiguous steps, diagnostics. |
search [<db>] <query> |
FTS5 full-text search over step definitions and scenarios. |
impact [<db>] --class\|--method\|--step\|--endpoint <target> |
Blast radius: scenarios affected by changing an entity. |
report [<db>] |
Write a self-contained HTML drill-down of the map. |
map [<db>] |
Write a self-contained project dependency graph (HTML). |
validate [<db>] |
Check a file is a supported TestAtlas map. |
<details> <summary><strong>Options & exit codes</strong></summary>
<br>
index --output <file> Β· --config <file> Β· --include <glob> (repeatable) Β· --exclude <glob> (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.
</details>
π§ Example workflow
# 1. (Optional) Build the solution β see the note below; the map is the same either way
dotnet build YourSolution.sln
# 2. Index it
testatlas index YourSolution.sln --output atlas.db
# 3. Before writing a new step β does one already exist?
testatlas search atlas.db "add a product to the cart" --steps
# 4. About to change a shared client β what will it hit?
testatlas impact atlas.db --class ProductsApiClient
# 5. Share a human-readable snapshot
testatlas report atlas.db --html atlas.html
You do not need to build the solution before indexing it. TestAtlas is a syntax-only pass β
it never asks Roslyn for a compilation or a semantic model β so a solution whose NuGet packages
have never been restored indexes fine. Gherkin is parsed from the .feature files themselves,
and step definitions are read from the [Given]/[When]/[Then] attributes in your source;
the code-behind a build generates (*.feature.cs under obj/) is deliberately skipped, so
building produces nothing the indexer consumes. Build first only if you want the solution
compiled for your own reasons.
π Use it from an AI agent (MCP)
TestAtlas ships an MCP server β testatlas-mcp β that serves the map to any MCP-aware client
(Claude Code, and other agents) 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.
It's published on NuGet as an MCP-server package (TestAtlas.Mcp), so MCP-aware editors can
discover and launch it. The map path is optional β the server auto-discovers a codemap.db
(or atlas.db) in the working directory, or reads the TESTATLAS_DB environment variable.
Visual Studio / VS Code (GitHub Copilot agent mode) β add to your .mcp.json (%USERPROFILE%\.mcp.json
or <SolutionDir>\.mcp.json):
{
"servers": {
"testatlas": {
"type": "stdio",
"command": "dnx",
"args": ["TestAtlas.Mcp", "--yes"]
}
}
}
dnx (from the .NET 10 SDK) fetches and runs the server on demand β no pre-install. Launch it from a
folder that holds your codemap.db and it's picked up automatically; otherwise append the path as a
final arg. In Visual Studio you can also use Tools picker β + β Add custom MCP server to write
this entry for you.
Claude Code β install the global tool and register it:
dotnet tool install --global TestAtlas.Mcp
claude mcp add testatlas -- testatlas-mcp # run where a codemap.db lives, or append a path
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.
<details> <summary><b>Or run from source</b> (no install)</summary>
dotnet build src/CodeMap.Mcp -c Release
# on Windows the binary is TestAtlas.Mcp.exe; on macOS/Linux it's TestAtlas.Mcp
claude mcp add testatlas -- src/CodeMap.Mcp/bin/Release/net8.0/TestAtlas.Mcp.exe path/to/codemap.db
</details>
Tools exposed:
statsβ summary counts: projects, classes, methods, class-kind breakdown, endpoints, and edge tallies.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).list_endpointsβ the HTTP endpoints the suite calls, each with verb, route, and scenario blast radius (highest-reach first).
MCP clients load servers at session start. If you register the server mid-session, restart
your Claude Code / agent session before the testatlas tools appear.
Retrieval runs locally against the SQLite file β deterministic, offline, and a few hundred
tokens per answer instead of feeding the whole solution to the model. Protocol details in
specs/codemap-mcp.md.
π See it on a real sample
The repo ships a self-contained sample solution β samples/SampleShop β a
realistic 8-project layout that mixes API tests and UI tests, so the map has plenty of
connected nodes and exercises both API-client mapping (real HttpClient clients) and page-object
mapping (real Selenium IWebDriver pages):
βββΆ Api.Catalog βββ
Tests.Api βββββββββββββΌββΆ Api.Cart βββ€
Tests.E2E βββ¬ββββββββββ΄ββΆ Api.Identity βββΌββΆ Core (ApiClientBase : HttpClient)
βββΆ Ui.Pages ββββββββββββββββββ (PageBase : IWebDriver)
Tests.Ui βββββΆ Ui.Pages βββββββββββββββββββΆ Core
| Project | Role |
|---|---|
| Core | base types every client/page inherits (highest in-degree β biggest node) |
| Api.Catalog / Api.Cart / Api.Identity | HttpClient-based API clients |
| Ui.Pages | Selenium page objects (Login / Checkout / Product) |
| Tests.Api / Tests.Ui / Tests.E2E | Reqnroll suites whose steps drive the clients and pages |
Two committed outputs, generated by the tool from that solution β the map shows 8 projects and 11 dependencies:
π Sample report β features, scenarios, step bindings, class kinds, API endpoints <br> πΈοΈ Sample dependency map β the eight projects and the edges between them
GitHub serves .html as raw source, so the links above route through htmlpreview.github.io.
You can also download docs/sample-report.html /
docs/sample-map.html and open them locally.
<details> <summary>Reproduce them yourself</summary>
<br>
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
</details>
π Keeping the map fresh
TestAtlas answers are deterministic β but only as fresh as the map. Re-index whenever source changes so a query never returns a deterministically stale answer.
Check whether a map is stale
python scripts/check-map-age.py [path/to/map.db] # defaults to ./codemap.db, then ./atlas.db
It reads the map's generated_utc + solution_path, then scans authored source
(*.cs / *.feature) for anything modified since β ignoring generated files
(*.feature.cs, *.g.cs, *.designer.cs), bin/obj, and any nested solution.
| Exit code | Meaning |
|---|---|
0 |
fresh β no source changes since the map was built |
1 |
stale β re-run testatlas index |
2 |
no map β nothing to check |
(Python 3, stdlib only β runs on Windows, macOS, Linux.)
Warn automatically after every pull (git hook)
A version-controlled post-merge hook runs the check after each merge / git pull β it only
prints, never blocks:
git config core.hooksPath scripts/hooks # enable once, per clone
The hook auto-detects codemap.db / atlas.db at the repo root, or point it explicitly with
export TESTATLAS_DB=/path/to/your/map.db.
How often to re-index
A full re-index is a single static pass β seconds β and its cost scales with solution size, not with how much changed. So re-index on change, not on a timer:
- Locally β the hook tells you when your map drifted; run
testatlas indexwhen it does. - In CI β re-index on every merge to your main branch and publish the map as a build artifact
(don't commit the binary
.db).
High churn (many tests added daily) is not a performance problem β each pass is a fixed cost,
so just re-index more often. If a pass ever gets slow on a very large solution, scope it with
--include / --exclude.
Re-index in CI (any provider)
Three steps: install the tool β run testatlas index β publish the .db artifact.
<details> <summary><strong>GitHub Actions</strong> β <code>.github/workflows/testatlas.yml</code></summary>
<br>
name: TestAtlas map
on:
push:
branches: [ main ]
jobs:
map:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- run: dotnet tool install --global TestAtlas.Cli
- run: testatlas index YourSolution.sln --output codemap.db
- uses: actions/upload-artifact@v4
with:
name: testatlas-map
path: codemap.db
</details>
<details> <summary><strong>Azure DevOps</strong> β <code>azure-pipelines.yml</code></summary>
<br>
trigger:
branches:
include: [ main ]
pool:
vmImage: ubuntu-latest
steps:
- task: UseDotNet@2
inputs:
packageType: sdk
version: '8.0.x'
- script: dotnet tool install --global TestAtlas.Cli
displayName: Install TestAtlas
- script: testatlas index YourSolution.sln --output codemap.db
displayName: Index solution
- publish: codemap.db
artifact: testatlas-map
</details>
Any other CI (GitLab CI, Jenkins, TeamCity, CircleCI) follows the same three steps.
π Project layout
TestAtlas/
ββ src/
β ββ CodeMap.Core/ # analysis engine, model, SQLite storage, HTML builders
β ββ CodeMap.Cli/ # thin CLI wrapper β packs as the `testatlas` dotnet tool
β ββ CodeMap.Mcp/ # MCP server β packs as `testatlas-mcp`
ββ tests/
β ββ CodeMap.Tests/ # unit / integration tests
β ββ fixtures/ # synthetic Reqnroll / SpecFlow / broken-solution shims
ββ samples/ # real projects to point the tool at (SampleShop, ReqnrollLoginDemo)
ββ docs/ # committed sample report + dependency map (HTML)
ββ scripts/ # check-map-age.py + git hooks (map freshness / staleness)
ββ specs/ # codemap-indexer.md, codemap-mcp.md β the full specifications
ββ TestAtlas.sln
See specs/codemap-indexer.md for the complete specification:
entity model, classification heuristics, CLI surface, SQLite schema contract, performance
targets, and acceptance criteria.
π― 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.
πΊοΈ Roadmap
- Indexer CLI β C# indexer + documented, versioned SQLite schema (v0.1)
- HTML visualization β self-contained report + project map generated from the db
- MCP server β
testatlas-mcpexposes the map to AI agents over stdio JSON-RPC - Second-language indexer β same schema, contract-tested
π License
MIT Β© 2026 Karthik Kalaiyarasu
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.