Skip to main content
The WARDEN MCP server exposes the knowledge base and agent crew as a set of tools. Any Model Context Protocol client can call them: Claude, Cursor, Continue, a custom agent loop, or anything else that speaks the protocol. The design follows the GhidraMCP pattern: a thin, tool-per-operation surface where reads are always safe and writes go through the same provenance/confidence economy as every other WARDEN write path. An agent calling propose_symbol through MCP cannot clobber a human-verified name any more than an agent calling the library directly can.
The MCP server is an optional dependency. Nothing in the rest of WARDEN requires it. If the mcp package is absent, warden mcp prints a clear error and exits. No other command is affected.

Installation

pip install warden-re[mcp]
This adds mcp>=1.2 (the official MCP Python SDK). To install WARDEN with every optional dependency at once:
pip install warden-re[all]

Starting the server

warden mcp
By default the server opens warden.db in the current directory. To point it at a specific project database:
warden mcp --db /path/to/project.db
The server speaks MCP over stdio (stdin/stdout). There is no HTTP or SSE transport yet; it must run as a subprocess managed by the client.

Wiring into an MCP client

Most MCP clients accept a server block in a JSON configuration file. The exact key name varies by client. The pattern is the same: point at the warden binary, pass mcp as the subcommand, and optionally pass --db:
{
  "mcpServers": {
    "warden": {
      "command": "warden",
      "args": ["mcp", "--db", "/path/to/project.db"]
    }
  }
}
The server registers itself with FastMCP under the name "warden", which is how it appears in the client’s tool namespace.

Exposed tools

All tools are safe to call concurrently. Reads carry no side effects. Writes are economy-gated (see how the economy works).
List available agent backends, aliases, required credentials, and default models. Use this before calling run_agent_pass with backend: "auto".Inputs: none.Returns: array of objects, one per backend.
FieldTypeDescription
namestringUser-facing selector (offline, openai, anthropic).
backendstringInternal backend name written into evidence.
aliasesarrayOptional alternate selectors, such as codex and oai.
availableboolWhether the SDK and key are present in the server environment.
requiresarrayRequired packages and environment variables.
default_modelstring | nullDefault model for the backend. OpenAI defaults to gpt-5.3-codex.
List all ingested module versions in the project. Call this first to discover the version_id values needed by every other tool.Inputs: none.Returns: array of objects, one per version.
FieldTypeDescription
idintInternal version ID. Pass this to coverage, list_functions, etc.
labelstringHuman label (e.g. "v1", "v2").
emscripten_versionstring | nullInferred Emscripten version, if detected.
functionsintTotal function count (imported + defined).
shared_memoryboolWhether shared memory was detected in the module.
Example response:
[
  {
    "id": 1,
    "label": "v1",
    "emscripten_version": "3.1.55",
    "functions": 412,
    "shared_memory": false
  }
]
Symbol-coverage statistics for a specific version. Use this to decide whether to run an agent pass or how much human review remains.Inputs:
ParameterTypeDescription
version_idintFrom list_versions.
Returns: a single object.
FieldTypeDescription
definedintNumber of defined (non-imported) functions.
namedintNumber that have any name binding.
coverage_pctfloatnamed / defined * 100.
oracle_namedintNames contributed by the Emscripten Oracle.
human_namedintNames set by a human operator.
agent_namedintNames proposed by an agent (including via MCP).
Example response:
{
  "defined": 380,
  "named": 201,
  "coverage_pct": 52.9,
  "oracle_named": 148,
  "human_named": 12,
  "agent_named": 41
}
List every function in a version with its current annotation state. To find work remaining for an agent pass, filter for name == null or confidence < threshold.Inputs:
ParameterTypeDefaultDescription
version_idintrequiredVersion to query.
include_importsboolfalseInclude imported (host-provided) functions.
Returns: array of objects, one per function.
FieldTypeDescription
indexintWasm function table index.
stable_idstringStable content identity. Use this as the key to get_symbol and propose_symbol.
typestring | nullWasm type signature (e.g. "(i32, i32) -> i32").
namestring | nullCurrent name, or null if unnamed.
provenancestring | nullWho assigned the name: oracle, human, agent, export, diff-carry.
confidencefloat | nullConfidence score (0.0–1.0), or null if unnamed.
stable_id is the cross-version key. The same logical function carries the same stable_id across rebuilds even when its table index shifts. See core concepts for how stable identity is computed.
Fetch the grounded FunctionFacts object for one defined function. Use this when an external MCP client wants to produce its own proposal while staying constrained to evidence from the binary and KB.Inputs:
ParameterTypeDescription
version_idintFrom list_versions.
func_indexintWasm function table index.
Returns: null if the function is missing or imported, otherwise:
FieldTypeDescription
func_indexintWasm function table index.
stable_idstringStable function identity.
type_signaturestringWasm type signature.
call_targetsarrayDirect import call targets and <indirect> sites.
referenced_stringsarrayStrings referenced through decoded constants.
raw_namestring | nullName-section hint, if present.
instruction_mnemonicsarrayDecoded opcode mnemonics.
is_exportedboolWhether the function is exported.
Fetch the complete annotation record for a single function by its stable identity. Returns null if no annotation exists yet.Inputs:
ParameterTypeDescription
stable_idstringFrom list_functions.
Returns: null, or a single object.
FieldTypeDescription
stable_idstringEcho of the input key.
namestring | nullCurrent name.
summarystring | nullFree-text description of purpose, parameters, and behaviour.
type_signaturestring | nullWasm type signature.
provenancestringSource of the annotation (oracle, human, agent, export, diff-carry).
confidencefloatConfidence score (0.0–1.0).
lockedboolIf true, only a human operator can overwrite this entry.
evidencearrayEvidence trail: a list of objects describing why this name was assigned.
locked: true means a human called warden set-name with the default --lock flag. propose_symbol will refuse to write to a locked symbol. The response will have written: false.
Run the same propose → verify → write-back pass that warden agent runs. This lets an MCP client trigger WARDEN’s built-in offline, OpenAI/Codex, or Anthropic backend instead of reimplementing the loop.Inputs:
ParameterTypeDefaultDescription
version_idintrequiredVersion to annotate.
backendstring"auto"auto, offline, openai, codex, oai, or anthropic.
only_unconfidentbooltrueSkip symbols that are locked or already at confidence >= 0.5.
Returns: one summary object.
FieldTypeDescription
backendstringBackend that actually ran.
consideredintFunctions visited.
proposedintProposals returned by the backend.
writtenintProposals written to the KB.
rejected_by_verifierintProposals blocked by verify_proposal.
rejected_by_economyintProposals blocked by KnowledgeBase.upsert_symbol.
skipped_existingintLocked or already-confident functions skipped before backend call.
detailsarrayPer-function write, verifier reject, or economy reject details.
Provider-backed runs use the server process environment. Set OPENAI_API_KEY for the OpenAI/Codex backend or ANTHROPIC_API_KEY for the Anthropic backend before the MCP client starts the server.
Propose a name and optional summary for a function. This is the only write tool. It always records provenance: "agent" and actor: "agent:mcp" in the evidence trail. These values are injected by the server and cannot be supplied by the caller.Inputs:
ParameterTypeDefaultDescription
stable_idstringrequiredTarget function’s stable identity.
namestringrequiredProposed function name.
summarystring""Optional description of purpose, parameters, and behaviour.
confidencefloat0.5Agent’s self-assessed confidence (0.0–1.0).
Returns: a single object.
FieldTypeDescription
writtenboolWhether the KB was updated.
reasonstringHuman-readable explanation of the decision.
Example: accepted write
{ "written": true, "reason": "no prior annotation; slot was empty" }
Example: rejected write
{ "written": false, "reason": "symbol is locked by a human operator" }

The provenance/confidence economy

propose_symbol goes through exactly the same economy gate as every other write path in WARDEN. The CLI, the library, and the agent pipeline all converge on KnowledgeBase.upsert_symbol. There is no separate bypass for MCP. The authority ordering from highest to lowest is:
human (locked)  >  human (unlocked)  >  oracle  >  agent  >  diff-carry  >  (unnamed)
The rules propose_symbol must satisfy:
1

Unnamed slots are always accepted

If no annotation exists yet, the write goes through unconditionally.
2

A locked human annotation blocks every agent write

written: false, regardless of confidence.
3

Any human annotation (unlocked) blocks every agent write

Agents sit below humans in the hierarchy.
4

An oracle annotation blocks an agent write unless the incoming confidence exceeds the existing score

An agent that is very confident about a name can displace a weak oracle match, but this is intentionally rare.
5

An existing agent annotation is overwritten only if the incoming confidence is strictly higher

Running the same agent crew twice on the same KB converges; it does not thrash.
This means you can run an MCP-driven agent crew repeatedly (on every version drop, for instance) without requiring a human gating step. Work that humans or the Oracle have already done is never regressed.
See core concepts for the full rationale behind the provenance/confidence economy.

Library usage

If you want to embed the server inside a larger Python process rather than launching it as a subprocess, use build_server directly:
from warden.mcp import build_server

server = build_server("project.db")
server.run()   # blocks; serves over stdio
build_server raises RuntimeError with an actionable message if the mcp package is not installed, and FileNotFoundError if the project database does not exist.

Limitations (alpha)

The MCP server is alpha. The tool surface is functional but incomplete.
LimitationStatus
stdio only. No HTTP or SSE transport. The server must run as a subprocess managed by the client.Current
Function-oriented. Globals, structs, and memory-region annotations are not yet exposed as MCP tools.Planned
No pagination. list_functions returns all rows in one response; large modules may produce large payloads.Planned
Per-call connections. Each tool call opens and closes a fresh KnowledgeBase connection. Safe for concurrent callers; not optimized for high-throughput loops.Planned
These are tracked in roadmap.
Last modified on June 7, 2026