brick/docs/architecture/mcp.md
trvon d292b9f3f2
feat: add brick_callers and brick_uncalled caller-status queries
Agents asking "is this function used?" get resolved, unknown, or
unreferenced per function instead of a bare zero in-degree. Unknown lists
why callers may exist: same-name unresolved call sites (excluding foreign
receivers and macros), name references (callbacks, address-taken, macro
bodies), virtual/trait-impl/external-base/outside-class members, framework
attributes, implicit protocol invocations, entry points, test code,
incomplete parses, and, unless assume_closed_world is set, exported or
external-linkage functions. Unreferenced is a review candidate with an
explicit heuristic/compiler evidence basis, never a dead-code proof.

The queries are read-only over validated schema-4 models and return
complete canonical nodes and edges plus metrics.resolution coverage.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 15:12:13 -06:00

108 lines
4.8 KiB
Markdown

# Read-only MCP queries
Brick exposes a thin Model Context Protocol server over an existing Brick JSON
artifact:
```sh
cargo run -- mcp brick.json
```
The server uses MCP protocol `2025-06-18` over newline-delimited JSON-RPC 2.0
on standard input/output. Standard output contains protocol messages only. The
client must complete `initialize` and `notifications/initialized` before listing
or calling tools.
The server does not scan source, import reports, render HTML, or alter the
artifact. Versioned Brick JSON remains the product boundary.
## Compatibility and result contract
Every query result has `query_schema_version: 1`, the input
`building_schema_version`, `query`, `root`, the sole `repository_id`, and the
exact scan `scope`. The server rejects artifacts unless they satisfy the
current schema-v4 contract. It also rejects duplicate node or edge IDs,
node/edge ID collisions, edges with missing endpoints, and edges without an
evidence record.
All returned nodes and edges are complete canonical records. Edge evidence
therefore retains every lane, backend, producer-local confidence value,
provenance string, and attribute. Queries never promote Syntactic, Heuristic,
or Imported evidence to Symbolic evidence.
Request envelopes require JSON-RPC 2.0, a string method, a string or integer
request ID when present, and object-valued params when present. Malformed
requests receive JSON-RPC Invalid Request; malformed notifications produce no
response. Tool arguments reject unknown fields. A malformed call is a JSON-RPC
invalid params error. A well-formed query for a missing entity is a normal MCP
tool result with `isError: true`.
## Tools
### `brick_impact`
Required input: `node_id`. Optional `direction` is `dependents` (default) or
`dependencies`; optional `max_depth` is a non-negative integer (default 1).
Traversal uses only `calls`, `imports`, and `inherits` edges. The result returns
the complete start node, impacted nodes, and traversed dependency edges.
Containment, definition, finding, renderer, and layout relationships are not
impact evidence.
### `brick_cycles`
No input fields. Returns deterministic strongly connected components over
`calls`, `imports`, and `inherits`, including self-loops. Each cycle has a
stable query-local ID plus complete member nodes and internal edges. These are
structural observations, not runtime or verifier proofs.
### `brick_bridges`
No input fields. Returns dependency edges whose removal disconnects their
endpoints in the weak undirected dependency graph. Parallel or reverse
relationships prevent either individual edge from being labeled a bridge.
The result declares `graph_semantics: weak-undirected-dependency` and includes
each complete edge and endpoint node.
### `brick_evidence`
Required input: `entity_id`. An edge lookup returns the complete edge and both
endpoint nodes. A node lookup returns the complete node and all incident edges
in stable-ID order.
### `brick_callers`
Required input: `node_id` (a function). Optional `assume_closed_world`
(default false). Returns `report` with the complete function node, `status`,
`basis`, `reasons`, and complete resolved caller edges, plus the language's
`metrics.resolution` coverage and a fixed `caveat`.
- `resolved`: at least one resolved caller edge in any lane.
- `unknown`: no resolved caller, but the model records why one may exist:
`unresolved-call-sites` (same-name unresolved sites, with counts by
`source.unresolved-reason` and example provenance; sites on foreign-typed
receivers and macros are excluded), `referenced-by-name` (callback or
address-taken candidate), `virtual`, `trait-impl`, `external-base`,
`framework-attribute`, `implicit-invocation`, `outside-class-member`,
`parse-incomplete`, `entry-point`, `test-code`, and,
unless `assume_closed_world`, `exported` or `external-linkage`.
- `unreferenced`: neither. This is a review candidate, not proof of dead code.
`basis` is `compiler` only when Imported call evidence covers the function's
file; otherwise `heuristic`.
### `brick_uncalled`
Optional `language`, `assume_closed_world` (default false), `include_unknown`
(default false), and `limit` (default 100). Returns per-language status counts,
`unreferenced_total`, and `unreferenced` reports ordered by path, line, and ID;
with `include_unknown`, also `unknown_total` and `unknown` reports. Use
`assume_closed_world: true` only when the scan covers the complete program.
## Determinism and limits
Nodes, edges, cycles, and bridges are ordered by stable identity, independent
of input node/edge ordering. The bridge query is intentionally simple and can
be quadratic in the number of dependency edges; it is an inspection surface,
not a replacement for offline metrics. The server keeps one validated model in
memory and provides no write, filesystem, source-scan, renderer, or policy
mutation tool.