Skip to main content

Module mcp

Module mcp 

Source
Expand description

MCP, on the same port as everything else.

The agentic principle’s first reading: a model should be able to point at Mira and ask, without a translation layer in between. That is one endpoint, POST /mcp, speaking JSON-RPC 2.0 over Streamable HTTP.

Eight tools, and they are the same eight questions the UI asks — deliberately. An agent and a human looking at the same incident should be reading the same numbers out of the same code path; a separate “agent API” is a second read path to keep correct, and the first thing it does is drift.

Stateless, and not by accident. Streamable HTTP lets a server hand out an Mcp-Session-Id and then requires every later request to carry it, which makes the server a thing with memory that a load balancer has to route back to the same replica. We issue none: every request carries everything it needs, any replica can answer it, and killing one loses nothing. That is principle 4 applied to the agent surface.

No SSE either. The responses here are single JSON documents that arrive when the scan finishes, so a stream would be one event and a teardown.

Constants§

PROTOCOL 🔒
The revision of the MCP spec these messages conform to.
TOOLS 🔒
Tool definitions, verbatim.

Functions§

blocking 🔒
Same rule as the HTTP API, through the same door: a cold mmap fault stalls the OS thread it lands on, and tokio has no way to see that happen. Sharing api::scan also shares its permit, so an agent’s reads and a browser’s are bounded together rather than each getting the whole pool.
call 🔒
handler 🔒
The MCP endpoint: JSON-RPC in, one of the eight tools in TOOLS out.
json 🔒
Always 200 with a JSON body, even for an error object: in JSON-RPC the failure is in the payload, and a client that sees a 4xx may never parse far enough to find out what went wrong.
result 🔒
router
rpc_error 🔒
rpc_id 🔒
JSON-RPC ids are a number, a string, or absent. Echoed back exactly, because that is how the client matches the reply to the call.
trace_search 🔒
“Every span of this trace”, which is the one query with no useful time bound: you look a trace up because you do not know when it happened. The window is therefore all of it, and the block-level trace-id filter is what makes that affordable.