MCP supply-chain risk scanner (nova mcp)

Part of the NovaFabric CLI reference. Both nova and novafabric run the same binary.

MCP supply-chain risk scanner (v0.25.1, E-9)

OWASP LLM Top 10 supply-chain checks for MCP server manifests (ADR-0069). Both commands parse a JSON or YAML manifest that describes an MCP server and its exposed tools.

Reference: src/novafabric/cli/mcp_.py, src/novafabric/mcp_scanner/.

nova mcp scan

Scan an MCP server manifest for OWASP LLM supply-chain risks. Exits 0 if no findings at or above --threshold; exits 1 on violations; exits 2 if the manifest file is not found.

nova mcp scan MANIFEST [--threshold {HIGH,MEDIUM,LOW}]
Argument / Flag Default Description
MANIFEST (required) Path to MCP server manifest (JSON or YAML)
--threshold {HIGH,MEDIUM,LOW} HIGH Minimum severity that causes a non-zero exit. Tab-completion available via nova --install-completion.
# Fail CI on HIGH or above (default)
nova mcp scan mcp-server.json

# Fail on any finding (even LOW)
nova mcp scan mcp-server.yaml --threshold LOW

Prints a Rich table with columns: Tool, Category, Severity, Message. Also prints the overall risk level and total finding count.

nova mcp risk-report

Generate a structured OWASP LLM risk report for an MCP server manifest.

nova mcp risk-report MANIFEST [--format rich|json]
Argument / Flag Default Description
MANIFEST (required) Path to MCP server manifest (JSON or YAML)
--format rich Output format: rich (human-readable) or json (machine-readable)
# Human-readable summary
nova mcp risk-report mcp-server.json

# JSON output for downstream tooling
nova mcp risk-report mcp-server.json --format json

JSON output includes per-tool risk scores and per-finding evidence strings. Exits 2 if the manifest file is not found.

nova mcp card (experimental, NF-039 / SEP-1649)

Publish and validate the MCP Server Card — the SEP-1649 discovery document an MCP registry or client fetches from /.well-known/mcp.json to learn an endpoint's protocol version, capabilities and auth without connecting.

nova mcp card show                                   # what nova serve publishes
nova mcp card show --json --base-url https://nova.example
nova mcp card validate card.json
nova mcp card validate https://nova.example/.well-known/mcp.json

Generated, never hand-written. The card is built from the live server configuration, so it cannot drift from what the server actually does — a discovery document that has drifted is worse than none, because a client trusts it precisely for being authoritative.

What it reports:

nova serve publishes the card at GET /.well-known/mcp.json, unauthenticated by design — gating a discovery document behind the auth it describes would make it undiscoverable. It carries only non-secret facts.

Validation is strict about structure and permissive about unknown keys: SEP-1649 is an evolving format, so an unrecognised field is forward-compatibility, but a missing required field means a client cannot rely on the document.

Exit codes: 0 (valid), 1 (invalid card), 2 (unreadable file/URL).

nova mcp conformance (experimental, NF-038)

Replay MCP conformance vectors and assert wire compatibility with the 2026-07-28 release.

nova mcp conformance tests/mcp_conformance/vectors/
nova mcp conformance tests/mcp_conformance/vectors/ --json

Each vector pins a wire behaviour against the capture shape it must produce. They exist because MCP capture is evidence: a spec drift that silently changes what gets recorded fails no ordinary test — the code runs, the capsule writes, and the damage only appears when someone tries to replay an exchange months later and the turn structure is gone. On failure the vector's why field is printed, so a reader learns what breaks in the product rather than just which assertion tripped.

Shipped vectors cover: a two-round SEP-2322 elicitation (rounds 1,1,2,2 under one exchange id), concurrent interleaved exchanges (grouping must key off JSON-RPC id, never arrival order), Tasks-as-extension passthrough, and a leg with no id (which must not be captured, since correlating it under a fabricated id would invent a grouping).

Exit codes: 0 (all passed), 1 (a vector failed), 2 (no vectors found — a suite with no vectors proves nothing).

The mcp-conformance CI lane runs this plus nova mcp card validate on every PR touching proxy/, capture/hooks/_mcp.py, mcp/, or tests/mcp_conformance/.