Skip to content
CodArchthe living map of the architecture
ESEN

MCP for agents

CodArch exposes its model to agents through a local MCP server over stdio. It does not analyse code inside MCP: it reads an already generated cc.json snapshot and, if it exists, the diff’s report.json. Everything it returns is a read of the snapshot, except map_screenshot, which also leaves a PNG in the repo. That way the agent sees the same facts as the CLI, the map and the PR comment.

The server is not a codarch subcommand: it is a separate binary, codarch-mcp, that the agent starts over stdio.

  1. A snapshot:

    .codarch/snapshot.cc.json
    npm run analyze -- .
  2. Optionally, a diff report:

    Ventana de terminal
    npm run diff -- base.cc.json head.cc.json -o .codarch/report.json

    In the GitHub Action, the artefacts land in .codarch/action-artifacts/head/snapshot.cc.json and .codarch/action-artifacts/report.json.

Without a report, the map and the metrics work; change and violation queries answer available: false with a reason, instead of inventing data.

The launcher resolves tsx from the repository itself, so it can be invoked from any directory:

Ventana de terminal
node apps/mcp/bin/codarch-mcp.mjs \
--root . \
--snapshot .codarch/snapshot.cc.json \
--report .codarch/report.json

It is a stdio server: it does not print a prompt or exit. stdout is reserved for JSON-RPC; status messages go to stderr. To see the help:

Ventana de terminal
npm run mcp -- --help

Do not use npm run mcp as the MCP client command: npm can write notices to stdout and break the protocol. Use the launcher with node or the equivalent direct command.

Generic example (Claude Desktop, Cursor or another MCP client with JSON configuration). Replace C:/path/repo with the absolute path of your checkout:

{
"mcpServers": {
"codarch": {
"command": "node",
"args": [
"C:/path/repo/apps/mcp/bin/codarch-mcp.mjs",
"--root", "C:/path/repo",
"--snapshot", ".codarch/snapshot.cc.json",
"--report", ".codarch/report.json"
]
}
}
}

The --snapshot and --report paths are relative to --root. If the client supports cwd, you can use relative paths and omit --root, but the launcher does not depend on it.

To skip loading a report:

"args": ["C:/path/repo/apps/mcp/bin/codarch-mcp.mjs", "--root", "C:/path/repo", "--no-report"]
OptionDefaultUse
--root <dir>cwdProject root and base for relative paths
-s, --snapshot <file>.codarch/snapshot.cc.jsoncc.json 2.x snapshot (or normalisable 1.x)
-r, --report <file>.codarch/report.jsonDiff report; if it does not exist, it carries on without it
--no-report—Do not load a report
--head-report <file>.codarch/head-report.jsonChanges since the last commit; wins over --report when present
--no-head-report—Do not load that report
-h, --help—Help
-v, --version—Version

An explicit --report or --head-report that does not exist is an error. The default report being absent is not.

The HEAD report describes the working tree against its last commit, which is what the app shows in Changes; that is why it is preferred over report.json, which describes a PR. The get_architecture_map response says in reportSource where the changes come from (head, report or none).

CodeMeaning
0Help or version printed, or the server ended normally.
1Invalid option, or the snapshot could not be loaded or the server could not start.

All input paths are relative to the project. A file id and the root name as a prefix (my-project/src/a.ts) are also accepted. Absolute paths and .. are rejected.

Compact tree of folders and files with size, maximum complexity, risk and changes.

ParameterTypeDefaultDescription
folderstringrootFolder to start from
depth1–62Levels of descendants
limit1–10020Maximum children per folder
includeFilesbooleantrueInclude file leaves

Each folder declares files (all its descendants), childFolders, metrics.size, metrics.maxComplexity, metrics.risk and, if there is a report, changes with added, changed, removed, hotspots and violations. Children that do not fit in limit are summarised in truncated.

The response carries two identities: checksum, which depends on code, and historyChecksum, which depends on history (empty if the snapshot was measured without git). Heat can change without the former changing.

Ranking of files by risk or by a snapshot metric.

ParameterTypeDefaultDescription
scopesnapshot | diffsnapshotCurrent values or report deltas
metricstringriskrisk or a metric present in the snapshot
folderstringrootFilter by folder
limit1–10010Number of results
minValuenumber0Exclusive minimum value

In scope: "diff" the metric is decided by the report (hotspotMetric); if you pass another one, the tool fails with a clear message. Diff hotspots include base, head and delta.

Dependents (who imports it) and/or dependencies (what it imports) of a file or folder.

ParameterTypeDefaultDescription
pathstring—Path or id of the file/folder
directiondependents | dependencies | bothdependentsDirection of the walk
depth1–82Maximum hops
limit1–20050Impacted nodes

Returns the nodes with depth, directions, risk and, if there is a report, their change status. It includes cycle membership, related violations and summary.truncated.

Lists the report’s violations, separating introduced, existing and resolved.

ParameterTypeDefaultDescription
statusall | introduced | existing | resolvedallStatus
severityall | info | warn | errorallSeverity
typeall | forbidden | threshold | cyclesallRule type
rulestring—Exact rule name
limit1–10020Results

Only introduced violations with error severity block the diff gate; MCP shows them all so the agent can explain previous debt without confusing it with a new failure.

The lint the project actually has: detected systems, their active rules and their findings.

ParameterTypeDefaultDescription
pathstringrootFolder or file to show findings for
rulestring—A specific rule, as named by its tool
severityall | error | warn | infoallFinding severity
limit1–20020Listed findings

It reads the .codarch/lint.repmod.json left by codarch lint and serve, next to the snapshot; it does not run tools. It returns systems (name, configuration, active rules with their severity and the note saying why it was not measured or its rules could not be enumerated), tools (the ones that measured), summary, the scope’s files and total, rules with each rule’s count and findings with file, rule, severity, line, column and message, errors first and then by path and line. limit trims the list without changing total. The count is the same one the CLI and the app show: an info is a finding, but it adds to neither errors nor warnings.

With no artifact it does not claim the lint is clean: it returns available: false with the reason, because not measured is not the same as no findings.

The repo’s configuration, read the same way the CLI reads it: the .codarch.yml and the addons it declares. No parameters.

  • file: the file read (usually .codarch.yml); null if there is none;
  • profile: the domain profile the team chose, if any;
  • layers: the effective layers with their glob patterns;
  • rules: the effective rules, each with its source (config, profile or addon:<name>; the team’s wins);
  • ignore: the patterns the repo excludes from the analysis;
  • addons: the declared addons with their profiles and their saved views (the same short state the app’s URL uses);
  • errors: the addons that could not be loaded.

If the file declares an addon that is not in addons/, the tool does not fail: it returns what it could read and explains it in reason.

Migration plan to another language: how much is left, where and how it has changed.

ParameterTypeDefaultDescription
folderstringrootLimit the plan to a folder
limit1–10015Files with the most debt

Returns summary (status by language and by category js/rust/bridge/native, total debt, FFI crossings and bridge files), topDebt (the files with the most debt, with their language, status and crossings) and changes (if there is a report.json: the files whose debt grew or shrank, and the total debt delta). If the snapshot does not have the migration lens, available is false and it says so.

How much code is copied and between whom: the snapshot’s duplication lens and, if there is a report.json, what changes against the base.

ParameterTypeDefaultDescription
pathstringrootFolder or file to show pairs for
limit1–10020Pairs and changes listed

Returns summary —duplicated and repeated lines, proportion over the scope’s rloc and affected files—, pairs with both ends of each pair, its similarity and its lines, totalPairs, and changes with added, removed and diverging, the lines gained or lost and their counts. A pair counts in the scope when both its files are inside; the one crossing the border belongs to the parent folder. Without the lens, available is false and it says so: unmeasured is not the same as clean.

The repository’s timeline: the snapshots saved with codarch analyze --history.

ParameterTypeDefaultDescription
snapshotstring—Specific snapshot: part of its date or checksum
limit1–10010Maximum entries

Without snapshot it returns the timeline (date, checksum, files, rloc, debt, heat and the most touched files). With snapshot it also returns that snapshot.

The life of a symbol across the history: when it was born, how it was renamed or moved, how many times its complexity changed and when it disappeared. It also returns the repo’s heat: the most rewritten symbols ✓.

ParameterTypeDefaultDescription
symbolstring—The symbol: function, class or type name; without it, only heat
limit1–5010Maximum chains

Without symbol it returns the repo’s heat and no chains. With symbol it searches only symbol chains, by current name or path or by those of any previous version: a rename or a move does not hide the symbol. limit caps the chains and goes up to 50.

The map, as a PNG. It is the only tool that is not read-only: it writes the image into .codarch/shots/ and declares it with readOnlyHint: false.

ParameterTypeDefaultDescription
areastringrlocMetric that decides each box’s area
colorstringriskrisk, structure, a metric or churn
width160–40961400Width in pixels
height160–4096900Height in pixels

It returns two blocks: the image (image/png, so the client paints it) and a JSON with the file, the slot, the bytes and the summary —project, area, colour, legend scale and the largest cells with their path, area and value—. The image carries the names of the largest cells and of the folders, with the package’s own bitmap font; the scale and the numbers live in the summary.

There are two slots, map-1.png and map-2.png: the capture takes the free one and, with both taken, overwrites the oldest. The previous one stays there, which is what you compare against. An area or colour the snapshot does not have returns isError with the message about the missing metric.

A file or folder’s sheet:

  • metrics, risk and the file’s risk ranking;
  • incoming and outgoing edges with weight and type-only;
  • runtime cycle (membership and size);
  • status in the diff, changes and hotspot;
  • violations that mention the path.
  • lint: totals for the scope (errors, warnings, info, findings, files), or null if not measured.

For a folder it aggregates its files, shows the highest-risk ones and summarises the edges leaving or entering the set. limit (1–50, default 5) controls the detail edges and files.

  • Read-only. There are no tools to analyse, write rules, create snapshots or modify the repository. It reads the snapshot, the report and, if they exist, the repo’s configuration and lint artifact.
  • No network. It does not query GitHub; for a PR, point it at the artefacts already on disk.
  • No invented prose. The server returns JSON with the observed fields. The agent decides how to explain it.
  • Deterministic. The same snapshot and report produce the same result; no timestamps are added.
  • Verified cycles. They are computed with SCC over the snapshot’s edges, not copied from optional metrics.
  • Folder aggregation. Size = sum; complexity = maximum; risk = maximum. Only direct children appear at each level.
  • Explicit truncation. truncated says how many children or nodes were left out. The limits prevent giant responses; they do not change the underlying data.
  • Errors. A non-existent path, an unknown metric or an invalid report return isError with an actionable message; they do not return silent partial data.
apps/mcp/
├── bin/codarch-mcp.mjs launcher without npm noise
├── src/store.ts snapshot/report index, paths, risk, cycles, aggregates
├── src/tools.ts the fifteen queries
├── src/server.ts MCP registration and input schemas
├── src/index.ts stdio entry and options
└── test/ 51 tests, including in-memory transport

The server loads and indexes once; calls work in memory. npm test covers the tools, the server and the in-memory MCP transport. There is also a manual stdio test against the action’s artefacts.

The codarch suggest query: it deduces from the graph which layers the code already has and which rules would protect them. It returns the fragment for .codarch.yml with its configVersion, the detected layers (with their patterns, how many files each has and what depends on them), the folders that fit no layer, the catalogue profiles that fit best and which of that profile’s rules the repo breaks today.

A layer’s size counts files, not dependencies: a one-file layer says one even when several edges cross it.

It proposes; the team decides. Rules come in as a warning.

The codarch profiles catalogue: each profile with what project it is for, its layers and its rules with the severity they come in with. A profile is chosen in .codarch.yml with profile: <id>.

The codarch verify check: every symbol in the snapshot must be the latest version of its chain. If the body hash is not the chain’s, the snapshot and the history are telling different stories. It returns checked, projectHead and the mismatches with their reason; without history, available: false and the reason.

It uses the snapshot the server already loaded, not a second read from disk.

  • Remote HTTP/SSE server, authentication or multi-repo.
  • Automatic refresh when the snapshot changes; the server must be restarted or another process started.
  • Analysis tools, or tools that write rules or change the code. The only one that writes anything is map_screenshot, and it only leaves the capture’s PNG.
  • Symbol-level navigation; nodes are files.
  • Publishing the npm package. For now it runs from the checkout.