Coverage MCP
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Coverage MCPshow me coverage changes since last snapshot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Coverage MCP
Coverage MCP is a local coverage history server for people who run tests often and need to know:
did coverage go up or down after this run?
which files changed coverage?
which exact lines regressed or improved?
what was the baseline when this worktree started?
can an LLM answer coverage questions without reading huge coverage reports or source files?
It runs locally, stores coverage snapshots in DuckDB, exposes a dashboard, and provides MCP tools for LLM clients.
What Problem It Solves
Coverage reports are usually large, format-specific artifacts. They are hard for humans to diff and wasteful for LLMs to read directly.
Coverage MCP turns those reports into small queryable records:
overall snapshot coverage
file-level coverage
exact line-level coverage
branch and function counters when the report has them
time-series history by minute-level timestamp
frozen baseline references for worktrees
The intended workflow is explicit: run tests, generate coverage, then call the MCP tool or REST endpoint to ingest that report.
Related MCP server: codecov-mcp-server
What Coverage Details Include
Coverage details are normalized into four levels:
project: repo path/key, latest snapshot, snapshot count, branch count, latest line and branch rates
snapshot: timestamp, branch, commit SHA, suite, format, totals, rates, parser warnings
file: covered/total lines, covered/total branches, covered/total functions, per-file rates
line: line number, hits when available, covered/missed state, branch/function counters on that line
When the report format is lossy, the snapshot keeps a warning. For example, Go coverprofiles report blocks, Istanbul reports statements, and LLVM reports segments.
Install The Server
Coverage MCP currently installs from GitHub:
python -m pip install "coverage-mcp @ git+https://github.com/appunni-m/coverage-mcp.git@main"For development from this checkout:
python -m pip install -e '.[dev]'Python 3.12 or newer is required.
Update The Server
The agent plugin and the Python server are updated separately. Updating
testing@codegen-marketplace does not download or restart Coverage MCP.
For a Git-installed server, stop the running process and update it:
python -m pip install --upgrade \
"coverage-mcp @ git+https://github.com/appunni-m/coverage-mcp.git@main"For an editable development checkout:
git -C /path/to/coverage-mcp pull --ff-only
python -m pip install -e '/path/to/coverage-mcp[dev]'Restart coverage-mcp after updating. The existing .coverage-mcp/coverage.duckdb
is not replaced, so snapshots, run history, approvals, and worktree baselines
remain available.
Confirm the new process loaded the expected release:
curl http://127.0.0.1:59471/healthThe response includes the running version and active db_path.
Start The Shared Server
Start one server from the main checkout, not one server per worktree:
cd /path/to/main-checkout
coverage-mcpVerify it:
curl http://127.0.0.1:59471/healthDashboard:
http://127.0.0.1:59471/MCP endpoint:
http://127.0.0.1:59471/mcp/Default database:
<main-repository>/.coverage-mcp/coverage.duckdbCoverage MCP resolves Git's shared repository root before choosing the default database. Starting it from main or
from any linked worktree therefore opens the same DuckDB. This preserves baseline and worktree lineage without
committing local history. The .coverage-mcp/ directory should remain ignored by Git.
Do not start another Coverage MCP process from each worktree. Every agent and worktree should connect to this one server so DuckDB has one writer and one continuous project history.
Override host, port, or DB:
COVERAGE_MCP_HOST=127.0.0.1 \
COVERAGE_MCP_PORT=8765 \
COVERAGE_MCP_DB=/path/to/coverage.duckdb \
coverage-mcpInstall In An Agent
The testing plugin in
codegen-marketplace includes the Coverage MCP connection and
agent instructions for approved test runs, bounded summaries, artifact ingestion, and worktree comparisons.
The plugin expects Coverage MCP at http://127.0.0.1:59471/mcp/. Start the server before opening a new agent session.
The plugin installs only:
the
use-coverage-mcpskillthe HTTP MCP connection metadata
plugin documentation and prompts
It does not install the Python server, start a background process, or copy the DuckDB. Upgrade the plugin for agent instructions and connection changes; upgrade Coverage MCP for parser, storage, API, dashboard, or performance changes.
Codex
codex plugin marketplace add appunni-m/codegen-marketplace
codex plugin add testing@codegen-marketplaceStart a new Codex thread after installation. To install only the MCP connection without the testing skill:
codex mcp add coverage-mcp --url http://127.0.0.1:59471/mcp/Claude Code
claude plugin marketplace add appunni-m/codegen-marketplace
claude plugin install testing@codegen-marketplaceStart a new Claude Code session after installation. To install only the MCP connection:
claude mcp add --transport http --scope user coverage-mcp http://127.0.0.1:59471/mcp/Pi
Pi intentionally has no built-in MCP client, so install the testing skill and the MCP adapter:
git clone https://github.com/appunni-m/codegen-marketplace.git
pi install ./codegen-marketplace/plugins/testing
pi install npm:pi-mcp-adapter
node ./codegen-marketplace/plugins/testing/scripts/install-pi-mcp.mjsRestart Pi after installing the adapter. The installer merges Coverage MCP into
~/.config/mcp/mcp.json; it does not replace other configured MCP servers. In Pi, MCP tools are accessed through the
adapter's mcp proxy tool.
Confirm Agent Access
Ask the agent:
Use coverage-mcp to list the registered test commands for this project.If no command is registered, give the agent the complete test command, working directory, and artifact paths, then explicitly approve that exact registration. After a run, ask:
Run the approved test suite, ingest its coverage artifact, and tell me whether this worktree improved against its
frozen baseline.Quick Workflow
Generate a coverage report from your test tool.
Ingest the report into Coverage MCP.
Open the dashboard or ask your MCP client for summaries, file details, changed lines, and history.
Example with LCOV:
curl -X POST http://127.0.0.1:59471/api/ingest \
-H 'content-type: application/json' \
-d '{
"report_path": "coverage/lcov.info",
"format": "lcov",
"repo_path": "/path/to/repo",
"branch": "main",
"suite": "unit"
}'AGENTS.md Snippet
Projects using Coverage MCP can place this small policy in their AGENTS.md:
## Coverage MCP
- Reuse the repository's single Coverage MCP server and shared DuckDB. Never copy the database into a worktree or set
`COVERAGE_MCP_DB` to a worktree-local path.
- Register a new worktree once with `register_worktree(path, base_ref, name)` before its first coverage run. Keep the
returned `worktree_id`; its frozen baseline defines the lineage for that worktree.
- Run tests through an existing human-approved command with `run_command_profiled`. If no approved command exists,
ask for explicit approval before registering one.
- Ingest generated coverage with the actual worktree path as `repo_path`, its branch/commit, and a stable suite name.
- Use `worktree_progress(worktree_id, suite)` or `compare_to_baseline(worktree_id=...)` to report whether line, branch,
function, and region coverage improved. Do not compare one worktree's snapshots to another worktree.
- Keep suite names stable: each suite is compared with the matching base snapshot that existed when the worktree was
registered, never with a later reference-branch run.
- Treat the reference branch trend (normally `main`) as project health. Treat each worktree trend as independent
progress from its frozen reference baseline.The same operation through MCP:
ingest_coverage(
report_path="coverage/lcov.info",
format="lcov",
repo_path="/path/to/repo",
branch="main",
suite="unit"
)Use format="auto" when you want Coverage MCP to detect the report type.
Approved Run Ledger
Coverage MCP can also record test runs. It does not require a YAML suite file.
Instead, a human explicitly registers the full command string once, including cwd and expected artifacts. Registration requires approval fields:
register_test_command(
name="condition",
command="make -C pillow-rs-freetype test-unified-condition-coverage",
cwd="/path/to/repo",
artifact_paths={
"llvm_json": "pillow-rs-freetype/target/coverage/unified-condition-summary.json",
"missing_lines": "pillow-rs-freetype/target/coverage/unified-condition-missing-lines.txt"
},
human_approved=true,
approved_by="your-name",
approval_note="approved exact condition coverage command"
)After that, agents run only the registered command id or name:
run_command_profiled(command_ref="condition", max_summary_lines=80)Each run is stored as an immutable ledger record:
exact command
cwd
repo key/path
branch and commit SHA when known
start/end time and duration
exit code and status
full stdout/stderr log paths
bounded parsed summary
registered artifact paths
The MCP response does not return full raw logs by default. It returns a bounded summary and tells you where the full logs are stored. Managed commands run outside the MCP event loop, so dashboards, health checks, coverage insights, and other agents remain responsive during long test suites. The server serializes managed commands to avoid running multiple expensive suites concurrently.
Object Topology
Coverage MCP does not store topology as a separate table. It computes topology from each object's own fields and returns it inline.
Examples:
project topology: repo key/path, snapshot count, command count, run count, latest snapshot
command topology: project, command id/name, cwd, approval metadata, artifact kinds
run topology: project, command id/name, run id/status, runtime branch/commit, artifact paths
snapshot topology: project, snapshot id, suite, format, report path, branch/commit
worktree topology: project, worktree path/head, baseline ref and baseline snapshot
This means a registered command is project-specific because registration stores repo_key and repo_path from its approved cwd. Runs carry more detailed topology because they also store runtime branch/commit, logs, status, and artifacts.
Supported Coverage Formats
Format | Use | Notes |
LCOV |
| Lines, branches, functions |
coverage.py JSON |
| Lines and branch arcs |
Cobertura XML |
| Lines and branch counts |
JaCoCo XML |
| Java/Kotlin/JVM line, instruction, branch counters |
Istanbul/nyc JSON |
| Statements become line records; branches/functions kept separately |
Go coverprofile |
| Block ranges expanded to lines |
LLVM JSON export |
| Segments become line records; branch, function, and aggregate region coverage are preserved |
Some formats are lossy when normalized. For example, Go reports blocks, Istanbul reports statements, and LLVM reports segments. Coverage MCP stores warnings on snapshots when it has to approximate line records.
MCP Usage Guide
Connect your MCP client to:
http://127.0.0.1:59471/mcp/The most common tools are:
project_summaries
Lists known projects with their latest coverage and snapshot counts.
project_summaries(limit=100)Use this first when you want to know which project has what coverage.
register_test_command
Registers an approved command that can be run later by id or name.
register_test_command(
name="unit",
command="pytest tests/unit",
cwd="/path/to/repo",
artifact_paths={"lcov": "coverage/lcov.info"},
human_approved=true,
approved_by="your-name",
approval_note="approved unit test command"
)Registration fails unless human_approved is true and approval metadata is present.
list_registered_commands
Lists approved command records, newest first.
list_registered_commands(limit=50)run_command_profiled
Runs a registered command and returns a bounded profile.
run_command_profiled(command_ref="unit", max_summary_lines=80)The response includes pass/fail, exit code, duration, key counters, selected error/tail excerpts, full log paths, and artifact paths.
It also includes the exact completion time plus freshness fields such as
age_seconds: 603 and age: "10 minutes 3 seconds ago".
latest_run
Returns the latest bounded run result, optionally for one registered command.
latest_run(command_ref="unit", max_summary_lines=80)Use this before rerunning a suite. The age and age_seconds fields make it
clear whether the previous result is fresh enough for the current task.
run_result
Returns a bounded summary for a previous run.
run_result(run_id="...", max_summary_lines=80)latest_artifact
Finds the latest artifact of a given kind for a command.
latest_artifact(command_ref="unit", kind="lcov")object_topology
Returns the computed topology for an object.
object_topology(object_kind="command", object_ref="unit")
object_topology(object_kind="run", object_ref="run-id")
object_topology(object_kind="snapshot", object_ref="snapshot-id")
object_topology(object_kind="project", object_ref="/path/to/repo")ingest_coverage
Stores a coverage report as an immutable snapshot.
ingest_coverage(report_path, format="auto", repo_path=None, suite="default")Use this after every test run that produces a coverage artifact.
coverage_summary
Gets a compact overall summary for a snapshot or the latest known snapshot.
coverage_summary()
coverage_summary(snapshot_id="...")
coverage_summary(repo_path="/path/to/repo", branch="main")coverage_files
Lists files in a snapshot, lowest line coverage first.
coverage_files(snapshot_id="...", limit=50)Use this when you want the LLM to find weak files without reading the whole report.
coverage_file
Shows one file's coverage and, by default, its line records.
coverage_file(snapshot_id="...", file_path="src/app.py")coverage_insights
Returns prioritized investigation items for a snapshot.
coverage_insights(snapshot_id="...")
coverage_insights(
snapshot_id="current-snapshot-id",
baseline_snapshot_id="baseline-snapshot-id"
)The insight output is deterministic and data-driven. It can flag:
files with zero line coverage
files with low line coverage
files with low branch coverage
parser warnings from lossy formats
overall regressions against a baseline
files that regressed against a baseline
exact lines that became uncovered
compare_to_baseline
Compares two snapshots or compares a worktree's current snapshot against its frozen baseline.
compare_to_baseline(
snapshot_id="current-snapshot-id",
baseline_snapshot_id="baseline-snapshot-id"
)For a registered worktree:
compare_to_baseline(worktree_id="...")worktree_progress
Returns one registered worktree's frozen baseline, exact-path trend, latest point, and line/branch/function/region deltas. This is the preferred compact answer to "did this worktree improve coverage?"
worktree_progress(worktree_id="...", suite="unit")changed_lines
Returns exact line-level coverage changes between two snapshots.
changed_lines(
snapshot_id="current-snapshot-id",
baseline_snapshot_id="baseline-snapshot-id",
only_regressions=true
)Use this when you want the LLM to report only the lines that became uncovered.
line_history
Shows coverage history for one file path and line number.
line_history(file_path="src/app.py", line_number=42)History is path-based. Renames are not tracked.
source_context
Reads a bounded source range from the repository for a covered file.
source_context(
snapshot_id="...",
file_path="src/app.py",
start=35,
end=50
)Use this only when coverage metadata is not enough. The response is capped so an LLM does not pull a large source file by accident.
Worktree Baselines
The design goal is reproducible baseline comparison.
When you register a worktree, Coverage MCP stores a reference to one baseline snapshot:
curl -X POST http://127.0.0.1:59471/api/worktrees/register \
-H 'content-type: application/json' \
-d '{
"path": "/path/to/worktree",
"base_ref": "main",
"name": "feature-login"
}'MCP equivalent:
register_worktree(
path="/path/to/worktree",
base_ref="main",
name="feature-login"
)That worktree stores baseline_snapshot_id. Later uploads to main do not change this baseline automatically. This lets you ask, "what changed compared with the base coverage when this worktree started?"
All linked worktrees share one project identity and one database, but each registered worktree is a separate progress lane. A lane contains its frozen reference snapshot followed only by snapshots ingested from that exact worktree path after registration. Branch names alone are not used to join lanes.
Dashboard
The dashboard at http://127.0.0.1:59471/ shows:
project selector with latest coverage for each project
latest snapshot summary
lineage-scoped multi-series trends for every available dimension: line, branch, function, and region
investigation queue with high/medium/info items
searchable file navigator ranked by missed lines, branch gaps, and baseline regressions
editor-style source coverage with hit counts, branch gaps, and baseline changes in the gutter
focused views for uncovered regions, partial branches, and changed coverage, with surrounding source context
coverage overview rail and previous/next gap navigation for large files
file diagnosis with jumpable uncovered regions and per-line history across snapshots
automatic comparison with the preceding project snapshot, with an explicit baseline selector when another reference is needed
It uses the same REST API and DuckDB storage as the MCP tools.
The trend selector has two kinds of views:
Reference:
mainshows only that branch and suite over time. It represents the health of the common parent tree.Worktree:
<name>starts at the worktree's frozen baseline and then shows only runs from that worktree. Its label reports independent metric deltas such asLine +1.2 pporBranch -0.5 pp. Baselines are frozen separately for each suite.
The graph never connects points from different worktrees. This follows the same reference-branch model used by GitHub coverage comparisons.
The investigation layout follows established coverage workflows rather than treating coverage as a spreadsheet:
an explorer plus editor gutter and uncovered-region navigation, as used by VS Code test coverage
changed-code coverage beside the source diff, as used by Codacy's coverage view
separate line and condition coverage, following Sonar's coverage metric definitions
explicit visibility for coverage changes outside edited lines, based on Codecov's indirect-change model
The first viewport is designed to answer the main operational questions in one pass:
which project am I looking at?
what is the latest line and branch coverage?
is coverage moving up or down?
what should I investigate first?
REST API
Useful endpoints:
GET /api/projectsPOST /api/commands/registerGET /api/commandsGET /api/commands/{command_ref}POST /api/runs/profiledGET /api/runs/latestGET /api/runs/{run_id}GET /api/artifacts/latestGET /api/topology/{object_kind}/{object_ref}POST /api/ingestPOST /api/worktrees/registerGET /api/worktrees/{worktree_id}/progressGET /api/snapshotsGET /api/snapshots/latestGET /api/snapshots/{snapshot_id}/insightsGET /api/snapshots/{snapshot_id}/filesGET /api/snapshots/{snapshot_id}/files/{file_path}GET /api/trendGET /api/compareGET /api/changed-linesGET /api/line-historyGET /api/source-lines
Storage Model
Snapshots are immutable. Each ingest creates a new snapshot with:
timestamp and minute bucket
repo path and repo key
branch and commit SHA when known
suite name
normalized file records
normalized line records
line, branch, function, and region totals when supplied by the report format
Registered commands and runs are immutable too. Changing a command means registering a new approved command record. Run stdout/stderr are written under the database directory's runs/ folder, and the database stores the paths plus bounded parsed summaries.
Topology is derived, not separately stored. The same immutable rows power both direct object responses and object_topology.
DuckDB is used because this is local-first and query-heavy. There is no background daemon or external time-series database.
Test Coverage
The test suite covers:
parser normalization for all supported formats
exact line, branch, function, and aggregate region counters
auto-detection for all supported formats
lossy-format warnings
parser error paths
DuckDB snapshot storage and baseline comparison
approved command registration and run ledger storage
bounded profiled command summaries
artifact registration and lookup
computed topology for projects, commands, runs, snapshots, and artifacts
FastAPI ingest/list endpoints
project summaries and coverage insights
MCP tool calls for command registration/runs, ingest, summary, project listing, insights, file listing, and file drill-down
Local quality gates:
pytest -q
ruff check .
mypy coverage_mcp
coverage run -m pytest -q
coverage report -mThe coverage configuration measures the coverage_mcp package and fails below 100%.
To run the same gates through tox:
toxLicense
MIT. See LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/appunni-m/coverage-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server