MCP Server for C++ Code Coverage

The covdbg MCP server lets an AI coding agent measure native C++ coverage on Windows and read the results through structured tools.

Start the server

The server is part of the covdbg executable:

covdbg mcp

Configure your MCP client to launch covdbg with the argument mcp, using your project as its working directory. The server uses standard input and output, with one JSON object per line. It is not an HTTP service. discover searches the directory the server was started in; pass --workspace <dir> when the client cannot start it inside the project.

--query-timeout <ms> sets how long one query statement may run (from covdbg 1.5.0); see Query limits.

For a client that reads a project .mcp.json file:

{
  "mcpServers": {
    "covdbg": {
      "command": "covdbg",
      "args": ["mcp"]
    }
  }
}

The executable must be on the client's PATH, or command must name its full path. Configuration file names and registration steps depend on the client.

To give query statements more time than the default 5000 ms, add the parameter to args:

{
  "mcpServers": {
    "covdbg": {
      "command": "covdbg",
      "args": ["mcp", "--query-timeout", "30000"]
    }
  }
}

Claude Code

Register the local stdio server from your project directory:

claude mcp add covdbg -- covdbg mcp

Check the installed client's help for supported scope options and inspect existing MCP settings before changing them. After connecting, call guide before starting a coverage run. For help with setup, use the AI quick-start prompt.

Prerequisites for a run

  • Windows and an existing executable with PDB debug symbols.
  • A developer sign-in through covdbg login, or COVDBG_PROJECT_TOKEN in the server environment for CI.
  • A .covdbg.yaml beside the target executable, or an explicit config_path in the run call.

Read the server's guide before measuring. Without a topic it explains the workflow. The topics config, excludes, baseline, merging, uncovered, children, and libraries cover writing a .covdbg.yaml (from covdbg 1.5.1 with exclude_lines and the marker comments that leave single lines out, see Excluding Lines), keeping the CRT and Windows SDK out of the report, static-library code no test binary links, measuring a whole suite, finding dead code with SQL, targets that do their work in a child process, and code that lives in a DLL. A poorly scoped configuration can produce misleading coverage.

The improvement loop

  1. Call guide, then discover to find executables and existing databases.
  2. Call run with a target and configuration. It returns a run session immediately.
  3. Call wait_run until it finishes. Each call returns after at most 30 seconds. A successful result includes a coverage session ID.
  4. Call files to rank uncovered files, then code to read a file's uncovered segments with context.
  5. Have the agent edit tests using its own coding tools, run the tests, and measure again.
  6. Review both the test result and coverage change. Close sessions when finished.

The MCP server does not edit source or generate tests itself. It supplies the measurements and context that the connected coding agent can use.

Tool reference

Tool Purpose Main inputs
guide Read workflow and configuration guidance Optional topic
discover Find executables and coverage databases Optional root
run Start a coverage run target (a path, or a name found on PATH as the command line finds its program); optional target_arguments, config_path, output_path, follow_children
wait_run Wait briefly or collect the completed result session_id; optional timeout_seconds
cancel_run Terminate a run session_id
open_coverage Open an existing database read-only path
files Rank files by uncovered lines session_id; optional limit, max_coverage_percent
code Read uncovered source segments with context session_id, file_path
query Run one read-only SQL statement session_id, sql; optional max_rows
merge Combine databases input_paths, output_path
close Release a run or coverage session session_id

From covdbg 1.5.1, run looks a bare target up in the working directory, then on PATH, with the extensions in PATHEXT, as described in Finding the Program. The run, and its result, name the executable by the full path found.

Pass a filePath returned by files directly to code. Missing source is reported explicitly. query rejects writes and statements such as ATTACH that reach outside the open database.

Set follow_children on run when the target is a launcher: a script host, a shell, or a test runner that spawns the process doing the real work. Without it only the launcher is measured. It is off by default because every child is instrumented, and a target that shells out repeatedly pays for each one; the children guide topic explains the cost. It has the same effect as --follow-children on the command line or settings.follow_children in .covdbg.yaml.

From covdbg 1.5.1, modules: in .covdbg.yaml selects the executables too, and the libraries guide topic says so: with modules: include:, the target, and each followed child's executable, is measured only when a pattern selects it (include: ["mylib.dll", "mylib_tests.exe"]), and modules: exclude: leaves an executable out. modules: include: ["mylib.dll"] measures the library alone, as OpenCppCoverage's --modules mylib.dll does, which is what you want when the test runner compiles in sources the library has too. An executable left out still runs: its libraries are measured, and its children followed. See Shared Library Patterns.

From covdbg 1.5.1, the config guide topic also says how targets: entries are matched: target: is the executable's file name, compared as Windows compares file names, without regard to case, and of two entries that differ only in case the first in the file counts, all of it, while covdbg warns about the other on stderr and in the log. The libraries topic says that files: and modules: patterns ignore case as Windows does, letters outside ASCII included. See Target Matching.

Query limits

From covdbg 1.5.0. query bounds what a statement may cost as well as what it may touch, so one runaway statement cannot hang the server, which answers one call at a time.

  • Time. A statement still running at the time limit is stopped, and the call returns an error saying so: the query was stopped after running longer than its time limit of 5000 ms; narrow it with a WHERE clause or a LIMIT, and avoid unbounded recursive CTEs and large cross joins. The session stays open and usable. Recursive CTEs are allowed; bound them with a WHERE on the recursive step, because an unbounded one, or a large cross join, reaches the limit.
  • Size. A statement may be at most 100 KiB of SQL, nest expressions at most 250 deep, combine at most 100 SELECT terms in one compound, use LIKE or GLOB patterns of at most 1000 bytes, and build no single string or blob over 16 MiB. Going past one fails the call with an error naming the limit.

The time limit is 5000 ms by default. Set it with covdbg mcp --query-timeout <ms> or the environment variable COVDBG_MCP_QUERY_TIMEOUT_MS in the server's environment, in whole milliseconds from 1 to 600000; the parameter takes precedence over the variable. An invalid or out-of-range --query-timeout is a usage error: covdbg prints, for example, --query-timeout: Value 0 not in range [1 - 600000] and exits with code 1 without starting the server. An invalid value in the variable is ignored and the default applies, as for covdbg's other environment variables. The query tool's description, which your MCP client shows the agent, states the limit in force.

These limits apply to query alone. The statements the server runs for its other tools are not bounded this way.

Sessions and outputs

Run IDs begin with run-; open coverage IDs begin with covdb-. Sessions last for the server process. A successful wait_run opens the output database automatically. The server holds up to 32 open coverage sessions and 8 runs in flight. A run takes a slot only while it is running; a finished run keeps its result but no longer counts, so a suite of many short runs needs no close between them.

A wait_run call blocks for at most 30 seconds, whatever timeout_seconds asks for, because the server answers one call at a time and a longer wait would keep cancel_run unreachable. If its response says stillRunning, the run is still going: call again. Completed outcomes distinguish success, nothing_measured, license_failure, and error. nothing_measured (no_functions_to_track before covdbg 1.5.1) means the target ran, but no function passed the coverage filter, or modules: left the target out, and the database covdbg wrote is empty: widen the .covdbg.yaml includes, select the target under modules: include:, or check that the target has debug information.

From covdbg 1.5.1, each run starts inside a Windows job object, so the target and every process that covdbg or the target starts belong to the run. cancel_run ends all of them at once, each with exit code 1. close on a run that is still going does the same, and when the server process ends, Windows ends the run's processes with it. Before, cancel_run ended covdbg and its target, and a process either of them had started kept running until close. When the server cannot set up the job, it starts nothing, and run fails with an error that begins The coverage run could not be started: and gives the reason. A server that itself runs in a job, as under a CI runner or an IDE, puts the run's job inside that one, so the outer job's cleanup still covers the run.

By default, runs use distinct temporary output files. An explicit output_path selects a destination. COVDBG_OUTPUT selects a fixed default location; avoid reusing one location across a suite because later runs can overwrite earlier results. Merge the separate databases instead.

Important workflow boundaries

  • Coverage success is not test success. When a run finishes, wait_run reports covdbg's own exit code and an outcome read from it: success means covdbg measured the run and wrote its database, not that the tests passed. The server does not pass --propagate-exit-code, so the target's exit code is not in the result; read the test runner's verdict in outputLines. On the command line and in CI, --propagate-exit-code makes covdbg exit with the target's code (see Exit Codes).
  • Cancellation loses the coverage. The database is written when the run completes; cancelling a run produces no coverage database.
  • The server launches a target. It cannot attach to an already running process or pause at a breakpoint for inspection.
  • Source context is returned to your AI client. A local MCP server does not imply the client's model processes that context locally.
  • A database of an older schema version is rejected: open_coverage returns an error naming both versions, such as Database schema version 8 is older than this build supports (9), and no migration exists. Regenerate the coverage database with this version of covdbg. covdbg 1.5.1 writes version 9, and refuses every database written by covdbg 1.5.0 or earlier: record the coverage again. See Databases from Earlier Versions.

To get set up with an AI agent, see the AI quick start. For shared reports and CI, see coverage reports.