gateway

package
v1.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 48 Imported by: 0

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()))
}
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)
	}
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Version

func Version() string

Version reports the gateway build version.

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 New

func New(cfg *config.Config, opts ...Option) (*Gateway, error)

New builds a gateway from a validated config.

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

func (g *Gateway) Handler() http.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

func (g *Gateway) MetricsHandler() http.Handler

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

func (g *Gateway) Reload(cfg *config.Config) error

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.

type Option

type Option func(*Gateway)

Option configures a Gateway at construction.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the structured logger for operational events. If unset, the gateway logs to a discard handler (silent).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL