← Back to all projects

ContextForge

One endpoint in front of every MCP server, A2A agent and REST API you have, with a registry and access control behind it

OfficialApache-2.0
Stars
4.4k
Forks
845
Open issues
1.2k
Last commit
28 Aug 2026

What is ContextForge?

The MCP problem an organisation hits is not writing a server, it is that after a year there are forty of them, nobody has a list, and each client is configured by hand. ContextForge is the registry and proxy for that situation: servers are registered once and discovered from one place, existing REST and gRPC services can be exposed as MCP without being rewritten, A2A agents are routed the same way, and authentication, rate limits and tracing are applied centrally instead of per server. It is itself a compliant MCP server, so clients see one endpoint. The weight is the obvious cost — this is infrastructure with a database, a cache and a Kubernetes story, which is a lot to run if you have three servers rather than forty.

What can you do with ContextForge?

  • Give clients one address instead of forty — Everything registered behind it appears through a single MCP endpoint, so adding a server stops meaning editing every client's configuration.
  • Expose what you already have — REST and gRPC services are translated into MCP, so an internal API becomes available to agents without anyone rewriting it as a server.
  • Apply the rules in one place — Authentication, rate limits and access control sit at the gateway, so a policy does not have to be re-implemented in each server.
  • Route agents as well as tools — A2A agents and OpenAI- or Anthropic-shaped agent endpoints are routed through the same door as the tools they use.
  • See what went through it — OpenTelemetry tracing goes to whichever backend you already run, so tool calls are visible next to the rest of your service traffic.
  • Scale it past one machine — Federation and caching backed by Redis let it run across a cluster rather than becoming a single process everything depends on.

Before you choose ContextForge

  • This is infrastructure, with a database, a cache and a clustered deployment story behind it. With a handful of MCP servers the gateway is more to operate than the servers it fronts.
  • Putting every tool call through one door also puts every tool call behind one failure: it needs the availability planning you would give any other component on the critical path.

Frequently asked questions

Is ContextForge free for commercial use?

ContextForge is released under the Apache-2.0 licence — OSI-approved open source, which permits commercial use.

How can ContextForge be deployed?

ContextForge is available as Self-hosted / Runs locally.

Documentation

Reproduced from the IBM/mcp-context-forge README, published under Apache-2.0. Read the original ↗

ContextForge

An open source registry and proxy that federates MCP, A2A, and REST/gRPC APIs with centralized governance, discovery, and observability. Optimizes Agent & Tool calling, and supports plugins.

ContextForge Banner

Build Python Package  Dependency Review  Tests & Coverage  Lint & Static Analysis

     

ContextForge is an open source registry and proxy that federates tools, agents, and APIs into one clean endpoint for your AI clients. It provides centralized governance, discovery, and observability across your AI infrastructure:

  • Tools Gateway — MCP, REST, gRPC-to-MCP translation, and TOON compression
  • Agent Gateway — A2A protocol, OpenAI-compatible and Anthropic agent routing
  • API Gateway — Rate limiting, auth, retries, and reverse proxy for REST services
  • Plugin Extensibility — 40+ plugins for additional transports, protocols, and integrations
  • Observability — OpenTelemetry tracing with Phoenix, Jaeger, Zipkin, and other OTLP backends

It runs as a fully compliant MCP server, deployable via PyPI or Docker, and scales to multi-cluster environments on Kubernetes with Redis-backed federation and caching.

ContextForge

Table of Contents


ResourceDescription
5-Minute SetupGet started fast — uvx, Docker, Compose, or local dev
Getting HelpSupport options, FAQ, community channels
Issue GuideHow to file bugs, request features, contribute
Full DocumentationComplete guides, tutorials, API reference
DeprecationsDeprecated runtime paths and migration guidance

Overview & Goals

ContextForge is an open source registry and proxy that federates any Model Context Protocol (MCP) server, A2A server, or REST/gRPC API, providing centralized governance, discovery, and observability. It optimizes agent and tool calling, and supports plugins. See the project roadmap for more details.

It currently supports:

  • Federation across multiple MCP and REST services
  • A2A (Agent-to-Agent) integration for external AI agents (OpenAI, Anthropic, custom)
  • gRPC-to-MCP translation via automatic reflection-based service discovery
  • Virtualization of legacy APIs as MCP-compliant tools and servers
  • Transport over HTTP, JSON-RPC, WebSocket, SSE (with configurable keepalive), stdio and streamable-HTTP
  • An Admin UI for real-time management, configuration, and log monitoring (with airgapped deployment support)
  • Built-in auth, retries, and rate-limiting with user-scoped OAuth tokens and unconditional X-Upstream-Authorization header support
  • OpenTelemetry observability with Phoenix, Jaeger, Zipkin, and other OTLP backends
  • Scalable deployments via Docker or PyPI, Redis-backed caching, and multi-cluster federation

ContextForge Architecture

For a list of upcoming features, check out the ContextForge Roadmap


  • Federates any MCP server or REST API
  • Lets you choose your MCP protocol version (e.g., 2025-11-25)
  • Exposes a single, unified interface for diverse backends
  • Wraps non-MCP services as virtual MCP servers
  • Registers tools, prompts, and resources with minimal configuration
  • gRPC-to-MCP translation via server reflection protocol
  • Automatic service discovery and method introspection
  • Adapts REST APIs into tools with:

    • Automatic JSON Schema extraction
    • Support for headers, tokens, and custom auth
    • Retry, timeout, and rate-limit policies
  • Prompts: Jinja2 templates, multimodal support, rollback/versioning
  • Resources: URI-based access, MIME detection, caching, SSE updates
  • Tools: Native or adapted, with input validation and concurrency controls
  • Admin UI built with HTMX 2.0.3 (bundled) + Alpine.js
  • Real-time log viewer with filtering, search, and export capabilities
  • Auth: Basic, JWT, or custom schemes
  • Structured logs, health endpoints, metrics
  • 7,000+ tests, Makefile targets, live reload, pre-commit hooks
  • Vendor-agnostic tracing with OpenTelemetry (OTLP) protocol support
  • Multiple backend support: Phoenix (LLM-focused), Jaeger, Zipkin, Tempo, DataDog, New Relic
  • Distributed tracing across federated gateways and services
  • Automatic instrumentation of tools, prompts, resources, and gateway operations
  • LLM-specific metrics: Token usage, costs, model performance
  • Zero-overhead when disabled with graceful degradation

See Observability Documentation for setup guides with Phoenix, Jaeger, and other backends.


Quick Start - PyPI

ContextForge is published on PyPI as mcp-contextforge-gateway.


⚠️ JWT_SECRET_KEY and AUTH_ENCRYPTION_SECRET are required in every environment — including local development. The gateway will not start without them. Generate real secrets with python3 -m mcpgateway.scripts.init_secrets before first run.

TLDR — single command using uv:

# 1️⃣  Generate secure secrets (creates .env.secrets)
python3 -m mcpgateway.scripts.init_secrets

# 2️⃣  Export the generated values
export JWT_SECRET_KEY="$(grep '^JWT_SECRET_KEY=' .env.secrets | cut -d= -f2)"
export AUTH_ENCRYPTION_SECRET="$(grep '^AUTH_ENCRYPTION_SECRET=' .env.secrets | cut -d= -f2)"

# 3️⃣  Start the gateway
JWT_SECRET_KEY="$JWT_SECRET_KEY" \
AUTH_ENCRYPTION_SECRET="$AUTH_ENCRYPTION_SECRET" \
MCPGATEWAY_UI_ENABLED=true \
MCPGATEWAY_ADMIN_API_ENABLED=true \
PLATFORM_ADMIN_EMAIL=admin@example.com \
uvx --from mcp-contextforge-gateway mcpgateway --host 0.0.0.0 --port 4444
  • Python ≥ 3.11
  • curl + jq - only for the last smoke-test step

1 - Install & run (copy-paste friendly)

# 1️⃣  Create an isolated env and install from PyPI
mkdir mcpgateway && cd mcpgateway
python3 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install mcp-contextforge-gateway

# 2️⃣  Download .env.example and generate real secrets
curl -O https://raw.githubusercontent.com/IBM/mcp-context-forge/main/.env.example
cp .env.example .env

# Generate cryptographically secure secrets into .env.secrets
python3 -m mcpgateway.scripts.init_secrets

# Patch the generated secrets into .env (replaces __REPLACE_ME__ placeholders)
python3 -m mcpgateway.scripts.init_secrets --patch-env .env

# 3️⃣  Start the gateway
mcpgateway --host 0.0.0.0 --port 4444 &

# 4️⃣  Generate a bearer token and smoke-test
export JWT_SECRET_KEY=$(grep '^JWT_SECRET_KEY=' .env | cut -d= -f2)
export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \
    --username admin@example.com --exp 10080 --secret "$JWT_SECRET_KEY")

curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://127.0.0.1:4444/version | jq
# 1️⃣  Isolated env + install from PyPI
mkdir mcpgateway ; cd mcpgateway
python3 -m venv .venv ; .\.venv\Scripts\Activate.ps1
pip install --upgrade pip
pip install mcp-contextforge-gateway

# 2️⃣  Download .env.example and generate real secrets
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/IBM/mcp-context-forge/main/.env.example" -OutFile ".env.example"
Copy-Item .env.example .env

# Generate cryptographically secure secrets into .env.secrets
python3 -m mcpgateway.scripts.init_secrets

# Patch the generated secrets into .env (replaces __REPLACE_ME__ placeholders)
python3 -m mcpgateway.scripts.init_secrets --patch-env .env

# 3️⃣  Launch the gateway
mcpgateway.exe --host 0.0.0.0 --port 4444

# 4️⃣  Bearer token and smoke-test
$Env:JWT_SECRET_KEY = (Get-Content .env | Select-String '^JWT_SECRET_KEY=').ToString().Split('=')[1]
$Env:MCPGATEWAY_BEARER_TOKEN = python3 -m mcpgateway.utils.create_jwt_token `
    --username admin@example.com --exp 10080 --secret $Env:JWT_SECRET_KEY

curl -s -H "Authorization: Bearer $Env:MCPGATEWAY_BEARER_TOKEN" `
     http://127.0.0.1:4444/version | jq
# 1️⃣  Isolated env + install from PyPI using uv
mkdir mcpgateway ; cd mcpgateway
uv venv
.\.venv\Scripts\activate
uv pip install mcp-contextforge-gateway

# Continue with steps 2️⃣-4️⃣ above...

Copy .env.example to .env and tweak any of the settings (or use them as env variables).

# 1️⃣  Spin up the sample MCP time server using mcpgateway.translate & docker (replace docker with podman if needed)
python3 -m mcpgateway.translate \
     --stdio "docker run --rm -i ghcr.io/ibm/fast-time-server:latest -transport=stdio" \
     --expose-sse \
     --port 8003

# Or using the official mcp-server-git using uvx:
pip install uv # to install uvx, if not already installed
python3 -m mcpgateway.translate --stdio "uvx mcp-server-git" --expose-sse --port 9000

# NEW: Expose via multiple protocols simultaneously!
python3 -m mcpgateway.translate \
     --stdio "uvx mcp-server-git" \
     --expose-sse \
     --expose-streamable-http \
     --port 9000
# Now accessible via both /sse (SSE) and /mcp (streamable HTTP) endpoints

# 2️⃣  Register it with the gateway
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"name":"fast_time","url":"http://localhost:8003/sse"}' \
     http://localhost:4444/gateways

# 3️⃣  Verify tool catalog
curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/tools | jq

# 4️⃣  Create a *virtual server* bundling those tools. Use the ID of tools from the tool catalog (Step #3) and pass them in the associatedTools list.
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"server":{"name":"time_server","description":"Fast time tools","associated_tools":[<ID_OF_TOOLS>]}}' \
     http://localhost:4444/servers | jq

# Example curl
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"server":{"name":"time_server","description":"Fast time tools","associated_tools":["6018ca46d32a4ac6b4c054c13a1726a2"]}}' \
     http://localhost:4444/servers | jq

# 5️⃣  List servers (should now include the UUID of the newly created virtual server)
curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/servers | jq

# 6️⃣  Client HTTP endpoint. Inspect it interactively with the MCP Inspector CLI (or use any MCP client)
npx -y @modelcontextprotocol/inspector
# Transport Type: Streamable HTTP, URL: http://localhost:4444/servers/UUID_OF_SERVER_1/mcp,  Header Name: "Authorization", Bearer Token
export MCP_AUTH="Bearer ${MCPGATEWAY_BEARER_TOKEN}"
export MCP_SERVER_URL=http://localhost:4444/servers/UUID_OF_SERVER_1/mcp
python3 -m mcpgateway.wrapper  # Ctrl-C to exit

You can also run it with uv or inside Docker/Podman - see the Containers section above.

In MCP Inspector, define MCP_AUTH and MCP_SERVER_URL env variables, and select python3 as the Command, and -m mcpgateway.wrapper as Arguments.

echo $PWD/.venv/bin/python3 # Using the Python3 full path ensures you have a working venv
export MCP_SERVER_URL='http://localhost:4444/servers/UUID_OF_SERVER_1/mcp'
export MCP_AUTH="Bearer ${MCPGATEWAY_BEARER_TOKEN}"
npx -y @modelcontextprotocol/inspector

or

Pass the url and auth as arguments (no need to set environment variables)

npx -y @modelcontextprotocol/inspector
command as `python`
Arguments as `-m mcpgateway.wrapper --url "http://localhost:4444/servers/UUID_OF_SERVER_1/mcp" --auth "Bearer <your token>"`

When using a MCP Client such as Claude with stdio:

{
  "mcpServers": {
    "mcpgateway-wrapper": {
      "command": "python",
      "args": ["-m", "mcpgateway.wrapper"],
      "env": {
        "MCP_AUTH": "Bearer your-token-here",
        "MCP_SERVER_URL": "http://localhost:4444/servers/UUID_OF_SERVER_1",
        "MCP_TOOL_CALL_TIMEOUT": "120"
      }
    }
  }
}

Quick Start - Containers

Use the official OCI image from GHCR with Docker or Podman. Please note: Currently, arm64 is not supported on production. If you are e.g. running on MacOS with Apple Silicon chips (M1, M2, etc), you can run the containers using Rosetta or install via PyPi instead.

🚀 Quick Start - Docker Compose

Important: docker compose up -d does not build the gateway image locally by default — it uses the pre-built image from GHCR. The compose file includes a build: block as a fallback, but local builds require a hermetic wheel closure that is only produced by the CI pipeline. If you see a cryptography or dependency resolution error during build, you are hitting this — just pull the image instead (step 2 below handles this automatically).

You also must have a .env file with real secrets before running docker compose up -d. The gateway will not start with placeholder values.

Get a full stack running with PostgreSQL and Redis:

# 1️⃣  Clone the repository
git clone https://github.com/IBM/mcp-context-forge.git
cd mcp-context-forge

# 2️⃣  Set up .env with real secrets AND pull the pre-built images
cp .env.example .env
python3 -m mcpgateway.scripts.init_secrets --patch-env .env
# .env now has strong JWT_SECRET_KEY and AUTH_ENCRYPTION_SECRET

# Pull pre-built images from GHCR (avoids local build entirely)
docker pull ghcr.io/ibm/mcp-context-forge:latest
echo 'IMAGE_LOCAL=ghcr.io/ibm/mcp-context-forge:latest' >> .env

# Build only the nginx image (small, local-only, builds in seconds)
docker compose build nginx

# 3️⃣  Start the full stack
docker compose up -d

# 4️⃣  Check status
docker compose ps

# 5️⃣  View logs
docker compose logs -f gateway

# 6️⃣  Access Admin UI: http://localhost:8080/admin
#     Login: PLATFORM_ADMIN_EMAIL / PLATFORM_ADMIN_PASSWORD (from .env)

# 7️⃣  Generate an API token
export JWT_SECRET_KEY=$(grep '^JWT_SECRET_KEY=' .env | cut -d= -f2)
docker compose exec gateway python3 -m mcpgateway.utils.create_jwt_token \
  --username admin@example.com --exp 10080 --secret "$JWT_SECRET_KEY"

What you get:

  • 🗄️ PostgreSQL - Production-ready database with 55+ tables
  • 🚀 ContextForge - Full-featured gateway with Admin UI
  • 📊 Redis - High-performance caching and session storage
  • 🔧 Admin Tools - pgAdmin, Redis Insight for database management
  • 🌐 Nginx Proxy - Caching reverse proxy on port 8080

Enable HTTPS (optional):

# Start with TLS enabled (auto-generates self-signed certs)
make compose-tls

# Access via HTTPS: https://localhost:8443/admin

# Or bring your own certificates:
# Unencrypted key:
mkdir -p certs
cp your-cert.pem certs/cert.pem && cp your-key.pem certs/key.pem
make compose-tls

# Passphrase-protected key:
mkdir -p certs
cp your-cert.pem certs/cert.pem && cp your-encrypted-key.pem certs/key-encrypted.pem
echo "KEY_FILE_PASSWORD=your-passphrase" >> .env
make compose-tls

☸️ Quick Start - Helm (Kubernetes)

Deploy to Kubernetes with enterprise-grade features:

# Add Helm repository (when available)
# helm repo add mcp-context-forge https://ibm.github.io/mcp-context-forge
# helm repo update

# For now, use local chart
git clone https://github.com/IBM/mcp-context-forge.git
cd mcp-context-forge/charts/mcp-stack

# Generate secrets first
python3 -m mcpgateway.scripts.init_secrets
JWT_SECRET=$(grep '^JWT_SECRET_KEY=' .env.secrets | cut -d= -f2)
ENC_SECRET=$(grep '^AUTH_ENCRYPTION_SECRET=' .env.secrets | cut -d= -f2)

# Install with PostgreSQL (default)
# IMPORTANT: replace <strong-password> with a real password — do not use 'changeme' in production
helm install mcp-gateway . \
  --set mcpContextForge.secret.PLATFORM_ADMIN_EMAIL=admin@yourcompany.com \
  --set mcpContextForge.secret.PLATFORM_ADMIN_PASSWORD=<strong-password> \
  --set mcpContextForge.secret.BASIC_AUTH_PASSWORD=<strong-password> \
  --set "mcpContextForge.secret.JWT_SECRET_KEY=${JWT_SECRET}" \
  --set "mcpContextForge.secret.AUTH_ENCRYPTION_SECRET=${ENC_SECRET}"

# Check deployment status
kubectl get pods -l app.kubernetes.io/name=mcp-context-forge

# Port forward to access Admin UI
kubectl port-forward svc/mcp-gateway-mcp-context-forge 4444:80
# Access: http://localhost:4444/admin

# Generate API token (reads JWT_SECRET_KEY from the pod's environment)
kubectl exec deployment/mcp-gateway-mcp-context-forge -- \
  python3 -m mcpgateway.utils.create_jwt_token \
  --username admin@yourcompany.com --exp 10080 --secret "${JWT_SECRET}"

SSRF note: Helm defaults to strict SSRF settings (SSRF_ALLOW_PRIVATE_NETWORKS=false). If you register in-cluster tool URLs, allow only your cluster CIDRs via mcpContextForge.config.SSRF_ALLOWED_NETWORKS or, for local-only benchmark setups, temporarily set SSRF_ALLOW_PRIVATE_NETWORKS=true. See docs/docs/manage/configuration.md#ssrf-protection and docs/docs/deployment/helm.md.

Enterprise Features:

  • 🔄 Auto-scaling - HPA with CPU/memory targets
  • 🗄️ Database Choice - PostgreSQL (prod), SQLite (dev)
  • 📊 Observability - Prometheus metrics, OpenTelemetry tracing
  • 🔒 Security - RBAC, network policies, secret management
  • 🚀 High Availability - Multi-replica deployments with Redis clustering
  • 📈 Monitoring - Built-in Grafana dashboards and alerting

🐳 Docker (Single Container)

# Generate secrets first (creates .env.secrets)
python3 -m mcpgateway.scripts.init_secrets
export JWT_SECRET_KEY="$(grep '^JWT_SECRET_KEY=' .env.secrets | cut -d= -f2)"
export AUTH_ENCRYPTION_SECRET="$(grep '^AUTH_ENCRYPTION_SECRET=' .env.secrets | cut -d= -f2)"

docker run -d --name mcpgateway \
  -p 4444:4444 \
  -e MCPGATEWAY_UI_ENABLED=true \
  -e MCPGATEWAY_ADMIN_API_ENABLED=true \
  -e HOST=0.0.0.0 \
  -e JWT_SECRET_KEY="${JWT_SECRET_KEY}" \
  -e AUTH_ENCRYPTION_SECRET="${AUTH_ENCRYPTION_SECRET}" \
  -e AUTH_REQUIRED=true \
  -e PLATFORM_ADMIN_EMAIL=admin@example.com \
  -e PLATFORM_ADMIN_PASSWORD=<strong-password> \
  -e PLATFORM_ADMIN_FULL_NAME="Platform Administrator" \
  -e DATABASE_URL=sqlite:///./mcp.db \
  -e SECURE_COOKIES=false \
  ghcr.io/ibm/mcp-context-forge:latest

# Tail logs
docker logs -f mcpgateway

# Generate API token (using the same secret)
docker run --rm -it \
  -e JWT_SECRET_KEY="${JWT_SECRET_KEY}" \
  ghcr.io/ibm/mcp-context-forge:latest \
  python3 -m mcpgateway.utils.create_jwt_token \
  --username admin@example.com --exp 10080 --secret "${JWT_SECRET_KEY}"

Browse to http://localhost:4444/admin and login with PLATFORM_ADMIN_EMAIL / PLATFORM_ADMIN_PASSWORD.

Persist SQLite database:

mkdir -p $(pwd)/data && touch $(pwd)/data/mcp.db && chmod 777 $(pwd)/data
docker run -d --name mcpgateway --restart unless-stopped \
  -p 4444:4444 -v $(pwd)/data:/data \
  -e DATABASE_URL=sqlite:////data/mcp.db \
  -e MCPGATEWAY_UI_ENABLED=true -e MCPGATEWAY_ADMIN_API_ENABLED=true \
  -e HOST=0.0.0.0 -e JWT_SECRET_KEY="${JWT_SECRET_KEY}" \
  -e AUTH_ENCRYPTION_SECRET="${AUTH_ENCRYPTION_SECRET}" \
  -e PLATFORM_ADMIN_EMAIL=admin@example.com -e PLATFORM_ADMIN_PASSWORD=<strong-password> \
  ghcr.io/ibm/mcp-context-forge:latest

Host networking (access local MCP servers):

docker run -d --name mcpgateway --network=host \
  -v $(pwd)/data:/data -e DATABASE_URL=sqlite:////data/mcp.db \
  -e MCPGATEWAY_UI_ENABLED=true -e HOST=0.0.0.0 -e PORT=4444 \
  -e JWT_SECRET_KEY="${JWT_SECRET_KEY}" -e AUTH_ENCRYPTION_SECRET="${AUTH_ENCRYPTION_SECRET}" \
  ghcr.io/ibm/mcp-context-forge:latest

Airgapped deployment (no internet):

docker build -f Containerfile -t mcpgateway:airgapped .
docker run -d --name mcpgateway -p 4444:4444 \
  -e MCPGATEWAY_UI_AIRGAPPED=true -e MCPGATEWAY_UI_ENABLED=true \
  -e HOST=0.0.0.0 -e JWT_SECRET_KEY="${JWT_SECRET_KEY}" \
  -e AUTH_ENCRYPTION_SECRET="${AUTH_ENCRYPTION_SECRET}" \
  mcpgateway:airgapped

This README has been shortened. The full version is on GitHub. Read the original ↗