- 22custom error codes a client can branch on
- 3MCP servers mapped by the read-only explorer
Routing generated from YAML
In FAFO Core and Function Forge I expected the number of tools to grow faster than anyone could hand-wire gateway routes. So I made JSON-RPC 2.0, the envelope of the Model Context Protocol, something the gateway serves from generated code. The gateway is an Axum server that speaks MCP over HTTP with the .well-known MCP configuration, protected-resource metadata and session headers.
At build time a generator turns a YAML trio per tool into handlers and routing, so a new function becomes callable without anyone editing gateway code, and the gateway and its catalog cannot drift apart.
the new tool takes its slot with no gateway code edited
Function Forge is itself an MCP tool on this envelope. An agent calls create_function, and the generator emits a new crate and wires it into the gateway, the control plane and the completion service in one reversible operation. After a rebuild and a restart I authorise, the new function answers tools/call with execute, status and control actions. See Tools that build tools, under governance.
A typed error space
The gateway defines its own error codes, so a failure reaches the client as a typed JSON-RPC error. Clients and agents branch on the kind of failure instead of parsing a message string.
A transport that survives restarts
In FAFOHive the first transport was a streaming server-sent-events session, and it broke every time a container restarted. Agents lost their connection mid-task. I replaced it with stateless JSON-RPC over HTTPS.
I also built a read-only explorer that discovers the catalogs on my MCP servers through the standard listing calls. It handles JSON and SSE responses and pagination, never calls a tool and treats every tool description it reads as untrusted text, so I can inspect several hundred tools with no side effects.
Envelopes between agents
Agent Swarm agents had to message one another and start work on a second machine, and I wanted one envelope for both. Agent-to-agent messages are JSON-RPC 2.0 envelopes aligned with the Agent Client Protocol, carried over Redis streams with response correlation and a durable journal. The message types live in a crate with no I/O and no business logic, so producers and consumers compile against one definition.
With the envelope out of the way, the attention goes to routing, identity and failure handling. The services use standard Rust and Python JSON-RPC stacks; the generated routing, the error space and the transport choices are mine.
I treat the wire envelope as plumbing that should be generated, typed and boring.