Documentation
¶
Overview ¶
Package gateway implements the fold MCP gateway engine: one governed endpoint federating any number of upstream MCP servers, with namespaced tools, enterprise auth, policy, caching, rate limiting, and audit.
Example ¶
Example shows embedding fold in another Go service: build a Gateway from the single JSON config document, mount its handler, and close it on shutdown. The handler serves the MCP endpoint plus the operational endpoints (health, metrics, OAuth protected-resource metadata).
package main
import (
"log"
"log/slog"
"net/http"
"github.com/fold-run/fold/config"
"github.com/fold-run/fold/gateway"
)
func main() {
cfg, err := config.Parse([]byte(`{
"upstreams": [
{"id": "github", "url": "https://mcp.example.com/mcp", "namespace": "github"}
]
}`))
if err != nil {
log.Fatal(err)
}
gw, err := gateway.New(cfg, gateway.WithLogger(slog.Default()))
if err != nil {
log.Fatal(err)
}
defer gw.Close()
log.Fatal(http.ListenAndServe("127.0.0.1:8080", gw.Handler()))
}
Output:
Example (HotReload) ¶
Example_hotReload shows applying a new configuration to a running gateway: the upstream set and policy swap atomically, live sessions to unchanged upstreams survive, and a rejected document (validation failure, or a change to a construction-wired section) leaves the running configuration serving.
package main
import (
"log"
"github.com/fold-run/fold/config"
"github.com/fold-run/fold/gateway"
)
func main() {
cfg, err := config.Parse([]byte(`{
"upstreams": [
{"id": "github", "url": "https://mcp.example.com/mcp", "namespace": "github"}
]
}`))
if err != nil {
log.Fatal(err)
}
gw, err := gateway.New(cfg)
if err != nil {
log.Fatal(err)
}
defer gw.Close()
next, err := config.Parse([]byte(`{
"upstreams": [
{"id": "github", "url": "https://mcp.example.com/mcp", "namespace": "github"},
{"id": "search", "url": "https://mcp.search.example.com/mcp", "namespace": "search"}
]
}`))
if err != nil {
log.Fatal(err)
}
if err := gw.Reload(next); err != nil {
log.Printf("reload rejected, old config still serving: %v", err)
}
}
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Gateway ¶
type Gateway struct {
// contains filtered or unexported fields
}
Gateway is a running fold gateway. Create one with New, mount Handler into any http server, and Close it on shutdown.
func (*Gateway) Close ¶
func (g *Gateway) Close()
Close shuts down all upstream sessions, stops the telemetry listener, flushes buffered trace spans, and releases the state provider. Safe to call more than once.
func (*Gateway) Handler ¶
Handler returns the gateway's HTTP handler: the MCP endpoint plus /.well-known/oauth-protected-resource and /health.
func (*Gateway) MetricsHandler ¶ added in v1.9.0
MetricsHandler serves the Prometheus exposition for this gateway.
Handler() serves it at /metrics too, unless server.metricsAddr moved it to its own listener — which is the arrangement to prefer when anything but the gateway's own host scrapes it. A scrape names upstream ids, namespaces, tenant ids, and multi-endpoint upstreams' endpoint URLs; on the public mux that is what the Host allowlist is protecting, and the same check is what answers a pod-IP scrape with 403. Mount this on a listener your network scopes instead, and nothing has to be exempted.
func (*Gateway) Reload ¶ added in v0.5.0
Reload applies a new configuration without a restart. The upstream set and the policy engine swap atomically: in-flight requests finish against the snapshot they started on, new requests see the new one. Upstreams whose configuration is unchanged keep their live sessions, caches, and breaker state; removed or changed upstreams are drained (closed after their request timeout, so in-flight calls complete) and a changed upstream's resource subscriptions are re-established on its replacement. Clients receive list_changed notifications so they refetch. Discovery-sourced upstreams (see config.Discovery) survive a base reload unchanged.
The auth, server, routing, audit, tracing, and discovery sections are wired in at construction and cannot hot-swap: changing them returns an error and leaves the running configuration untouched.