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::scanalso 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
TOOLSout. - 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.