fold
One governed endpoint between every MCP client and every MCP server. Forty out of forty on the official conformance suite, on every merge.
What it is
A gateway that sits in front of any number of upstream MCP servers, in any language, on any SDK, from any team or vendor, and presents them as one virtual server with namespaced tools. Nobody rewrites anything to get behind it.
It is built on the official MCP Go SDK, so the wire protocol is the SDK’s own implementation on both the client-facing and upstream-facing sides rather than a reimplementation that drifts.
The conformance claim is checkable rather than asserted: the official suite runs against fold fronting the reference everything-server on every merge, and a weekly job re-runs it against the latest unpinned SDK and opens a tracking issue the moment anything drifts.
The request pipeline
A federated configuration
{
"upstreams": [
{
"id": "github-tools",
"url": "https://mcp.platform.acme.com/mcp",
"namespace": "gh",
"owner": { "org": "acme-platform", "team": "devex" }
},
{
"id": "ml-search",
"url": "https://mcp.ml.acquired-co.com/mcp",
"namespace": "search",
"rateLimit": { "requestsPerMinute": 600 },
"circuitBreaker": { "failureThreshold": 5, "halfOpenAfterMs": 30000 }
}
],
"server": { "rateLimit": { "requestsPerMinute": 6000 } }
}The problems federation actually creates
- Two teams building from the same template collide. MCP Apps points a tool at an interface through a ui:// resource URI that only has to be unique within one server, and the published starter templates ship with no server segment. Federate two of them and a host rendering one team’s tool could get another team’s app, depending on what some other client had done first. fold mints those URIs per namespace. It is the one documented exception to never rewriting a URI, and it is narrow on purpose.
- Task ids are opaque and clients persist them. So fold never rewrites them and remembers ownership instead. A task-scoped call from a different principal answers the same error as an unknown id, with no existence leak and no probe. The ownership index is an authorization record rather than a routing hint, which is why it lives in shared state: a caller must not reach another principal’s task by landing on an instance that did not serve the mint.
- A rejected config reload must not take anything down. The upstream set and the policy engine swap atomically, in-flight requests finish against the snapshot they started on, and unchanged upstreams keep their live sessions. Sections that cannot hot-swap fail the reload loudly and keep the running configuration.
- A capability profile is computed, never trusted. Root sessions and list-cache entries are keyed by a normalised profile derived from the extension identifiers fold implements, not from the client’s raw map, so a caller inventing extension ids cannot mint sessions or cache entries.
- Degradation is explicit rather than silent. A fan-out with a dead upstream returns what it has and names the failures in _meta. A circuit breaker short-circuits an unhealthy upstream. Replicated upstreams round-robin per session and eject a dead endpoint on an active health check before a client request pays for the discovery.
Operationally
A distroless container around 22 MB, prebuilt binaries for linux and darwin on both architectures, or one call to embed it in an existing Go service. Set a Redis URL and cache, rate-limit, circuit-breaker and task-ownership state are shared, so a fleet of gateways behaves as one.
One JSON document, validated on startup, with a JSON Schema shipped for editor completion and CI linting.
Ask about it
The assistant on the home page answers from this same record, and will tell you what is not on it.