MCP Federation
Expose a single MCP endpoint that aggregates tools from multiple backend MCP servers with unified routing on Kubernetes.
What you’ll build
In this tutorial, you will:
- Set up a local Kubernetes cluster with agentgateway
- Deploy two separate MCP servers (echo and filesystem)
- Federate both servers into a single AgentgatewayBackend
- Access tools from both servers through one unified endpoint
Before you begin
Make sure you have the following tools installed:
For detailed installation instructions, see the LLM Gateway tutorial.
Step 1: Create a kind cluster
kind create cluster --name agentgatewayStep 2: Install agentgateway
# Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
# agentgateway CRDs
helm upgrade -i --create-namespace \
--namespace agentgateway-system \
--version v2.2.1 agentgateway-crds oci://ghcr.io/kgateway-dev/charts/agentgateway-crds
# Control plane
helm upgrade -i -n agentgateway-system agentgateway oci://ghcr.io/kgateway-dev/charts/agentgateway \
--version v2.2.1Verify the control plane is running:
kubectl get pods -n agentgateway-systemStep 3: Create a Gateway
kubectl apply -f- <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: agentgateway-proxy
namespace: agentgateway-system
spec:
gatewayClassName: agentgateway
listeners:
- protocol: HTTP
port: 80
name: http
allowedRoutes:
namespaces:
from: All
EOFWait for the proxy to be ready:
kubectl get deployment agentgateway-proxy -n agentgateway-systemStep 4: Deploy the MCP servers
Deploy two separate MCP servers that provide different sets of tools.
MCP “Everything” server
This server provides general-purpose tools like echo, add, and longRunningOperation.
kubectl apply -f- <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-everything
namespace: agentgateway-system
spec:
replicas: 1
selector:
matchLabels:
app: mcp-everything
template:
metadata:
labels:
app: mcp-everything
spec:
containers:
- name: mcp-server
image: node:22-alpine
command: ["npx", "-y", "mcp-proxy", "--port", "8080", "--", "npx", "-y", "@modelcontextprotocol/server-everything"]
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: mcp-everything
namespace: agentgateway-system
spec:
selector:
app: mcp-everything
ports:
- port: 80
targetPort: 8080
appProtocol: kgateway.dev/mcp
EOFMCP “Filesystem” server
This server provides file operation tools like read_file, write_file, and list_directory.
kubectl apply -f- <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-filesystem
namespace: agentgateway-system
spec:
replicas: 1
selector:
matchLabels:
app: mcp-filesystem
template:
metadata:
labels:
app: mcp-filesystem
spec:
containers:
- name: mcp-server
image: node:22-alpine
command: ["npx", "-y", "mcp-proxy", "--port", "8080", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: mcp-filesystem
namespace: agentgateway-system
spec:
selector:
app: mcp-filesystem
ports:
- port: 80
targetPort: 8080
appProtocol: kgateway.dev/mcp
EOFWait for both pods to be ready:
kubectl get pods -n agentgateway-system -l 'app in (mcp-everything, mcp-filesystem)' -wStep 5: Create the federated backend
Create a single AgentgatewayBackend that targets both MCP servers. Tools from each server are automatically prefixed with their target name.
kubectl apply -f- <<EOF
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
metadata:
name: mcp-federated
namespace: agentgateway-system
spec:
mcp:
targets:
- name: everything
static:
host: mcp-everything.agentgateway-system.svc.cluster.local
port: 80
protocol: SSE
- name: filesystem
static:
host: mcp-filesystem.agentgateway-system.svc.cluster.local
port: 80
protocol: SSE
EOFStep 6: Create the HTTPRoute
kubectl apply -f- <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: mcp-federated
namespace: agentgateway-system
spec:
parentRefs:
- name: agentgateway-proxy
namespace: agentgateway-system
rules:
- backendRefs:
- name: mcp-federated
namespace: agentgateway-system
group: agentgateway.dev
kind: AgentgatewayBackend
EOFStep 7: Test the federated endpoint
Set up port-forwarding:
kubectl port-forward deployment/agentgateway-proxy -n agentgateway-system 8080:80 &Initialize an MCP session:
curl -s -i http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'Copy the mcp-session-id from the response headers, then list all available tools:
curl -s http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":2}'You should see tools from both servers, prefixed with their target name:
everything_echo,everything_add,everything_longRunningOperation, …filesystem_read_file,filesystem_write_file,filesystem_list_directory, …
Call a tool from each server
Call the echo tool from the “everything” server:
curl -s http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"everything_echo","arguments":{"message":"Hello from federation!"}},"id":3}'Call the list_directory tool from the “filesystem” server:
curl -s http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"filesystem_list_directory","arguments":{"path":"/tmp"}},"id":4}'Cleanup
kill %1 2>/dev/null
kind delete cluster --name agentgateway