MCP client setup¶
Evidentia ships a Model Context Protocol (MCP) server that exposes its gap
analysis, control lookup, CONMON, TPRM, POA&M, and signed-artifact verification
surface as 15 tools an AI agent can call directly. This guide gets that
server running and wires it into the MCP hosts you actually use (Claude Desktop
and Claude Code) so an agent can drive Evidentia on your behalf. It
covers the evidentia mcp command group (serve, doctor, cimd-migrate), the
canonical stdio transport those hosts speak, and the optional per-client
scope-gating registry.
Prerequisites¶
- Evidentia installed with the
mcpextra, which pulls in the MCP Python SDK 2.2 and its typed server API (see Installation):
pip install "evidentia[mcp]"
# or, as an isolated tool on your PATH:
uv tool install "evidentia[mcp]"
- The
evidentiacommand resolvable on your PATH. Confirm it:
If evidentia is not found, your virtualenv's Scripts/ (Windows) or bin/
(POSIX) directory is not active — re-activate it, or invoke the server as
python -m evidentia.cli.main mcp serve.
Note on the examples below. The
evidentia ...invocations assume Evidentia is on your PATH (the normalpip install/uv tool installoutcome). If you are running from a source checkout you can prefix them withuv run(e.g.uv run evidentia mcp doctor); the flags and output are identical.
Step 1 — Confirm the server is launch-ready (mcp doctor)¶
Before wiring anything into a host, run the built-in preflight. mcp doctor
imports the MCP SDK, loads the bundled catalog registry, constructs the MCP
server (which registers every tool), and confirms the core tools are present. It
exits 0 on success and 1 on any failure, with a diagnostic on stderr.
Example output using only the bundled catalogs:
Evidentia MCP doctor: PASS
• MCP SDK: importable
• Catalog registry: 106 frameworks loaded
• MCP server: 15 tools registered
If you see 1 with an import error instead, the mcp extra is missing — re-run
the install from Prerequisites. mcp doctor takes no flags
beyond --help.
Step 2 — Understand the transport (and why you won't run serve by hand)¶
The server is launched with evidentia mcp serve. It blocks until the client
disconnects — it is a long-running server, not a one-shot command — so in
normal use you do not run it yourself in a terminal. Instead, you register the
launch command with an MCP host (Steps 4–6) and the host spawns, talks to, and
tears down the server for you over stdio.
evidentia mcp serve --help documents the transports and bind options:
| Flag | Default | Purpose |
|---|---|---|
--transport, -t {stdio\|sse\|http} |
stdio |
stdio is the canonical MCP transport used by Claude Desktop, Claude Code, etc. sse (server-sent events) and http (streamable-http) are the non-local transports for browser-based agents and remote clients. |
--host |
127.0.0.1 |
Bind address for HTTP / SSE only. Binding all interfaces with 0.0.0.0 requires an authenticated reverse proxy and an explicit --allow-root for file-path tools. |
--port, -p |
8765 |
Bind port for HTTP / SSE only. 8765 is chosen to avoid colliding with evidentia serve's default 8000. |
--allow-root PATH |
unset | Bounds file-path tool inputs (gap_analyze, gap_diff) to a directory; out-of-root paths surface as a tool error rather than crashing the server. Strongly recommended for non-loopback HTTP/SSE. Unset is appropriate for stdio + loopback. |
--cimd-registry FILE |
unset | Loads a per-client scope registry (see Step 6). Pair with --default-client-id on stdio. |
--default-client-id TEXT |
unset | Fallback identity when request metadata has no client_id, or its value is null or an empty string. A request identity takes precedence on every transport. Use a slug in the CIMD registry. |
Do not run
evidentia mcp serve(stdio) in a foreground terminal to "test" it — with no client attached it simply waits for stdin and appears to hang. Usemcp doctor(Step 1) to verify readiness instead. If you want to prove the server boots, start it on an HTTP port in the background — for exampleevidentia mcp serve --transport http --port 8799logsUvicorn running on http://127.0.0.1:8799and then accepts connections — and stop it when you're done.
SSE and Streamable HTTP use a 4 MiB request-body limit. The legacy HTTP transport keeps stateful sessions with a 1,800-second idle timeout and a 10,000-session limit. SDK Host/Origin checks apply to loopback binds. For a network bind, configure proxy authentication, rate limits and file-path bounds for the intended clients; binding a socket does not establish trust.
Step 3 — Pick the launch command your host will run¶
Every MCP host config below boils down to one command + args pair. For Evidentia over stdio that is:
- command:
evidentia - args:
["mcp", "serve", "--transport", "stdio"]
--transport stdio is the default, so ["mcp", "serve"] is equivalent; passing
it explicitly documents intent and survives any future default change. If
evidentia is not on the host process's PATH, use an absolute path to the
console script (for example the Scripts/evidentia.exe inside your virtualenv on
Windows, or bin/evidentia on POSIX) as the command.
Step 4 — Wire it into Claude Desktop¶
Claude Desktop reads claude_desktop_config.json (on Windows:
%APPDATA%\Claude\claude_desktop_config.json; on macOS:
~/Library/Application Support/Claude/claude_desktop_config.json). Add an
evidentia entry under mcpServers:
{
"mcpServers": {
"evidentia": {
"command": "evidentia",
"args": ["mcp", "serve", "--transport", "stdio"]
}
}
}
Restart Claude Desktop. The 15 Evidentia tools are listed. The native catalog tool also requires the explicit scope grant described below.
If
evidentiaisn't found, Claude Desktop launches the command with its own environment, which may not include your virtualenv's scripts directory. Replace"command": "evidentia"with the absolute path to the console script — e.g."command": "C:\\path\\to\\.venv\\Scripts\\evidentia.exe"on Windows or"command": "/path/to/.venv/bin/evidentia"on POSIX. (JSON requires the doubled backslashes on Windows.)
Step 5 — Wire it into Claude Code¶
Claude Code registers MCP servers from the command line. Pass the launch command
after the -- separator:
Everything after -- is the literal command Claude Code will spawn over stdio.
To scope the registration to one project rather than your user config, add
--scope project, which writes a .mcp.json at the project root that you can
commit:
// .mcp.json
{
"mcpServers": {
"evidentia": {
"command": "evidentia",
"args": ["mcp", "serve", "--transport", "stdio"]
}
}
}
Confirm the server is registered and reachable with claude mcp list.
The
command/argskeys are the standard MCP server contract and are identical across these hosts. Other hosts that consume the samemcpServersshape work the same way. If a particular host uses a config key Evidentia does not document here, consult that host's own MCP documentation rather than guessing the key — the launch command itself (evidentia mcp serve --transport stdio) does not change.
Step 6 — (Optional) Gate tools per client with CIMD¶
The original fourteen tools retain their existing no-registry behavior. The new
get_catalog_native tool always requires a configured registry and an explicit
literal get_catalog_native grant; a wildcard does not grant it. For
multi-client deployments you can restrict which tools a given client may call
with a CIMD (Client ID Metadata Document) registry — a JSON file mapping each
client_id to a space-separated allowlist of tool names in its scope.
// cimd-registry.json
{
"version": 1,
"clients": {
"claude-desktop": {
"client_id": "claude-desktop",
"client_name": "Claude Desktop",
"scope": "list_frameworks get_control gap_analyze gap_diff",
"redirect_uris": [],
"policy_uri": null,
"tos_uri": null
},
"readonly-agent": {
"client_id": "readonly-agent",
"client_name": "Read-only research agent",
"scope": "list_frameworks get_control",
"redirect_uris": [],
"policy_uri": null,
"tos_uri": null
}
}
}
Point the server at the registry and configure a fallback identity. Request
metadata client_id takes precedence, including over stdio. Missing, null or
empty-string metadata uses this fallback; malformed non-string values are
denied instead of inheriting it:
Bash / Linux / macOS
evidentia mcp serve --transport stdio \
--cimd-registry cimd-registry.json \
--default-client-id claude-desktop
PowerShell (Windows)
evidentia mcp serve --transport stdio `
--cimd-registry cimd-registry.json `
--default-client-id claude-desktop
An empty scope means deny-all; tool names not in the allowlist are denied.
With a registry loaded, missing, unknown, malformed and out-of-scope identities
receive protocol error -32602 before a handler or signer runs. Each registry
decision creates one scope audit event.
CIMD is metadata + scope, not authentication. A client that bypasses the transport's auth can claim any
client_id. On stdio, trust is UID-based; for HTTP/SSE you must wire transport auth (reverse-proxy mTLS or bearer tokens) so clients cannot impersonate each other's entries.
Migrating an older registry¶
If you built a CIMD registry before the four conmon_* tools shipped, those
tools are default-rejected for your clients until you grant them.
evidentia mcp cimd-migrate adds the conmon_* tool set to each client's
scope. It is idempotent (a tool already present is reported as no-change) and
rewrites the file in place — preview first with --dry-run:
Real dry-run output against a registry whose claude-desktop client predates the
CONMON tools:
CIMD migration plan (DRY RUN) for cimd-registry.json:
+ claude-desktop: adding ['conmon_check_state', 'conmon_health', 'conmon_list_cadences', 'conmon_next_due'] (final scope: ['conmon_check_state', 'conmon_health', 'conmon_list_cadences', 'conmon_next_due', 'gap_analyze', 'gap_diff', 'get_control', 'list_frameworks'])
Dry run: registry file NOT modified. Re-run without --dry-run to apply.
Drop --dry-run to write the change. Restrict it to one client with
--client-id <slug>, or grant a different tool set with
--tools 'tool_a tool_b' for future tool additions.
Optional output signatures¶
When EVIDENTIA_MCP_SIGN_OUTPUTS is enabled, configure
EVIDENTIA_MCP_SIGNER_FACTORY with a callable signer factory. An invalid
factory, including one returning None, causes a tool error. An exception
inside the signer retains the existing envelope with signature=null and a
signing_error; clients requiring signed evidence must reject that result.
The envelope is carried in result metadata under evidentia/signed-tool-output.
Its signature authenticates the payload only: the delivered structured JSON
object, or the established content-only result list. It does not authenticate
the envelope tool name or timestamp, outer error flag, unrelated metadata, or
display content when the structured object is signed. Verify a present signature
with verify_tool_output and consume its authenticated payload. The signing wrapper leaves future custom non-object structured results and
SDK input-request control flow unsigned. The modern SDK path can carry these
shapes; legacy schema validation rejects them. The fourteen registered tools
declare object outputs. See the
API contract.
The 15 MCP tools¶
Tools are exposed in registration order. Purposes are from the MCP tools reference, which is auto-generated from the live codebase and is authoritative for the exact signatures.
| # | Tool | Purpose |
|---|---|---|
| 1 | list_frameworks |
List the bundled compliance catalogs + their metadata. |
| 2 | get_control |
Return the raw catalog entry for a single control. |
| 3 | gap_analyze |
Run a gap analysis against a local control inventory. |
| 4 | gap_diff |
Diff two gap analysis reports. |
| 5 | conmon_list_cadences |
List bundled continuous-monitoring cadences. |
| 6 | conmon_next_due |
Compute the next-due date for a single CONMON cadence. |
| 7 | conmon_check_state |
Read a state-file + report attention-state per cadence. |
| 8 | conmon_health |
Return the CONMON health report for a state-file. |
| 9 | gap_analyze_sarif |
Run gap analysis + return the report as a SARIF 2.1.0 log. |
| 10 | collect_ocsf |
Ingest OCSF JSON from a local file → SecurityFinding list. |
| 11 | tprm_vendor_list |
List every vendor in the local TPRM store. |
| 12 | poam_list |
List every POA&M in the local store. |
| 13 | verify_signed_artifact |
Verify an OSCAL Assessment Result file's signatures + digests. |
| 14 | conmon_series |
Read a cadence evidence series from the local evidence store. |
The tool surface is append-only within a major version: new tools may be added, but existing names, parameters, and return shapes are not removed or changed incompatibly before the next major release.
What's next¶
- Full flag and signature reference: MCP tools
and CLI reference →
evidentia mcp. - Verify an OSCAL artifact: the
verify_signed_artifacttool checks the artifact signatures described in Sign and verify evidence. MCP result signatures have the separate payload contract described above. - Drive the CONMON tools end-to-end: CONMON deployment.
Got stuck?¶
evidentia: command not found(in the terminal or from a host) — the install succeeded but the scripts directory is not on PATH. Re-activate your virtualenv, run the server aspython -m evidentia.cli.main mcp serve, or set the host'scommandto the absolute path of theevidentiaconsole script.mcp doctorexits 1 with an import error — themcpextra is missing. Install it:pip install "evidentia[mcp]".evidentia mcp serveseems to hang — that is expected for stdio with no client attached; it is waiting on stdin. Don't run it by hand — let the host spawn it, and usemcp doctorto verify readiness.- A host launches but no Evidentia tools appear — the host couldn't spawn the
command. Check that
command/argsare correct for that host and thatevidentiaresolves in the host process's environment (use an absolute path if unsure), then restart the host. --no-stdioerrors out — that flag is a removed-in-v1.0 backward-compat shim; use--transport stdio(the default) instead.- CIMD client's
conmon_*calls are rejected — the registry predates those tools; runevidentia mcp cimd-migrate <registry> --dry-run, then apply it.
Grant native catalog reads explicitly¶
Add get_catalog_native to a specific client scope only when that client should
read the complete native source bundle. The request takes framework_id and
bundle_sha256, with no paths or URLs. A missing registry, identity or grant
is denied before source loading and signing. A changed generation must be
selected again; the tool does not substitute newer content.
Default cimd-migrate behavior keeps existing grants and does not add this tool.
Use the explicit --tools selection when preparing a reviewed grant change.