trackmcp
Back to directory
IBM

mcp-context-forge

View on GitHub

An AI Gateway, registry, and proxy that sits in front of any MCP, A2A, or REST/gRPC APIs, exposing a unified endpoint with centralized discovery, guardrails and management. Optimizes Agent & Tool calling, and supports plugins.

4,422 stars PythonOthers Updated Sep 4, 2026
agentsaiapi-gatewayasyncioauthentication-middlewaredevopsdockerfastapifederationgatewaygenerative-aijwtkubernetesllm-agentsmcpmodel-context-protocolobservabilityprompt-engineeringpythontools

Documentation

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
Async
License
PyPI
Docker Image

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 Setup**Get started fast β€” uvx, Docker, Compose, or local dev
**Getting Help**Support options, FAQ, community channels
**Issue Guide**How to file bugs, request features, contribute
**Full Documentation**Complete guides, tutorials, API reference
**Deprecations**Deprecated 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


πŸ”Œ Gateway Layer with Protocol Flexibility

  • 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

🧩 Virtualization of REST/gRPC Services

  • 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

πŸ” REST-to-MCP Tool Adapter

  • Adapts REST APIs into tools with:

    🧠 Unified Registries

    • 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, Observability & Dev Experience

    • 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

    πŸ” OpenTelemetry Observability

    • 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:

    bash
    # 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

    πŸ“‹ Prerequisites

    • Python β‰₯ 3.11
    • curl + jq - only for the last smoke-test step

    1 - Install & run (copy-paste friendly)

    bash
    # 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

    Windows (PowerShell) quick-start

    powershell
    # 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

    ⚑ Alternative: uv (faster)

    powershell
    # 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...

    More configuration

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

    πŸš€ End-to-end demo (register a local MCP server)

    bash
    # 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":[]}}' \
         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

    πŸ–§ Using the stdio wrapper (mcpgateway-wrapper)

    bash
    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.

    bash
    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)

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

    When using a MCP Client such as Claude with stdio:

    json
    {
      "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:

    bash
    # 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):

    bash
    # 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:

    bash
    # 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  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= \
      --set mcpContextForge.secret.BASIC_AUTH_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)

    bash
    # 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= \
      -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`.

    Advanced: Persistent storage, host networking, airgapped

    Persist SQLite database:

    bash
    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= \
      ghcr.io/ibm/mcp-context-forge:latest

    Host networking (access local MCP servers):

    bash
    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):

    bash
    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

    🦭 Podman (rootless-friendly)

    bash
    podman run -d --name mcpgateway \
      -p 4444:4444 -e HOST=0.0.0.0 -e DATABASE_URL=sqlite:///./mcp.db \
      ghcr.io/ibm/mcp-context-forge:1.0.0-RC-3

    Advanced: Persistent storage, host networking

    Persist SQLite:

    bash
    mkdir -p $(pwd)/data && chmod 777 $(pwd)/data
    podman run -d --name mcpgateway --restart=on-failure \
      -p 4444:4444 -v $(pwd)/data:/data \
      -e DATABASE_URL=sqlite:////data/mcp.db \
      ghcr.io/ibm/mcp-context-forge:1.0.0-RC-3

    Host networking:

    bash
    podman run -d --name mcpgateway --network=host \
      -v $(pwd)/data:/data -e DATABASE_URL=sqlite:////data/mcp.db \
      ghcr.io/ibm/mcp-context-forge:1.0.0-RC-3

    ✏️ Docker/Podman tips

    • .env files - Put all the `-e FOO=` lines into a file and replace them with `--env-file .env`. See the provided .env.example for reference.
    • Pinned tags - Use an explicit version (e.g. `1.0.0-RC-3`) instead of `latest` for reproducible builds.
    • JWT tokens - Generate one in the running container (reads the secret from the container environment):
    bash
    docker exec mcpgateway python3 -m mcpgateway.utils.create_jwt_token \
        --username admin@example.com --exp 10080 --secret "${JWT_SECRET_KEY}"
    • Upgrades - Stop, remove, and rerun with the same `-v $(pwd)/data:/data` mount; your DB and config stay intact.

    πŸš‘ Smoke-test the running container

    bash
    curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
         http://localhost:4444/health | jq
    curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
         http://localhost:4444/tools | jq
    curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
         http://localhost:4444/version | jq

    πŸ–§ Running ContextForge stdio wrapper

    The `mcpgateway.wrapper` lets you connect to the gateway over stdio while keeping JWT authentication. You should run this from the MCP Client. The example below is just for testing.

    bash
    # JWT_SECRET_KEY must be set β€” see "Docker (Single Container)" for how to generate it
    export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \
      --username admin@example.com --exp 10080 --secret "${JWT_SECRET_KEY}")
    export MCP_AUTH="Bearer ${MCPGATEWAY_BEARER_TOKEN}"
    export MCP_SERVER_URL='http://localhost:4444/servers/UUID_OF_SERVER_1/mcp'
    export MCP_TOOL_CALL_TIMEOUT=120
    export MCP_WRAPPER_LOG_LEVEL=DEBUG  # or OFF to disable logging
    
    docker run --rm -i \
      -e MCP_AUTH="${MCP_AUTH}" \
      -e MCP_SERVER_URL=http://host.docker.internal:4444/servers/UUID_OF_SERVER_1/mcp \
      -e MCP_TOOL_CALL_TIMEOUT=120 \
      -e MCP_WRAPPER_LOG_LEVEL=DEBUG \
      ghcr.io/ibm/mcp-context-forge:latest \
      python3 -m mcpgateway.wrapper

    Quick Start: VS Code Dev Container

    Clone the repo and open in VS Codeβ€”it will detect `.devcontainer` and prompt to "Reopen in Container". The container includes Python 3.11, Docker CLI, and all project dependencies.

    For detailed setup, workflows, and GitHub Codespaces instructions, see **Developer Onboarding**.


    Installation

    bash
    make venv install-dev      # create .venv + install deps + build Admin UI
    make serve                 # gunicorn on :4444

    Rust workspace note:

    • Workspace-owned Rust crates live under `crates/` and are picked up by the root `Cargo.toml` via `crates/*`.
    • Run `cargo build`, `cargo test`, and `cargo check` from the repo root to cover the shared workspace.
    • `make venv install-dev` creates the root `.venv`, which is also reused by the workspace's PyO3/maturin builds.

    Alternative: UV or pip

    bash
    # UV (faster)
    uv venv && source .venv/bin/activate
    uv pip install -e '.[dev]'
    
    # pip
    python3 -m venv .venv && source .venv/bin/activate
    pip install -e ".[dev]"

    PostgreSQL adapter setup

    Install the `psycopg` driver for PostgreSQL:

    bash
    # Install system dependencies first
    # Debian/Ubuntu: sudo apt-get install libpq-dev
    # macOS: brew install libpq
    
    uv pip install 'psycopg[binary]'   # dev (pre-built wheels)
    # or: uv pip install 'psycopg[c]'  # production (requires compiler)

    Connection URL format:

    bash
    DATABASE_URL=postgresql+psycopg://user:password@localhost:5432/mcp

    Quick Postgres container:

    bash
    docker run --name mcp-postgres \
      -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=mysecretpassword \
      -e POSTGRES_DB=mcp -p 5432:5432 -d postgres

    Upgrading

    For upgrade instructions, migration guides, and rollback procedures, see:

    • **Upgrade Guide** β€” General upgrade procedures
    • **MIGRATION.md** β€” Breaking changes and step-by-step upgrade instructions
    • **CHANGELOG.md** β€” Version history and breaking changes

    Configuration

    > ⚠️ If any required `.env` variable is missing or invalid, the gateway will fail fast at startup with a validation error via Pydantic.

    Copy the provided .env.example to `.env` and update the security-sensitive values below.

    πŸ” Required: Set Before Starting

    These variables must be set before the gateway will start. There are no usable defaults β€” the application fails at startup if these are missing or placeholder values:

    VariableDescriptionHow to generate
    `JWT_SECRET_KEY`HMAC secret for signing JWTs (32+ chars)`python3 -m mcpgateway.scripts.init_secrets`
    `AUTH_ENCRYPTION_SECRET`Passphrase for encrypting stored credentials`python3 -m mcpgateway.scripts.init_secrets`

    These variables have insecure defaults and should be changed before production use:

    VariableDescriptionDefault
    `BASIC_AUTH_USER`Username for HTTP Basic auth`admin`
    `BASIC_AUTH_PASSWORD`Password for HTTP Basic authrequired β€” no default; set via `make init-secrets-patch-env`
    `PLATFORM_ADMIN_EMAIL`Email for bootstrap admin user`admin@example.com`
    `PLATFORM_ADMIN_PASSWORD`Password for bootstrap admin userrequired β€” set a strong value before first run
    `PLATFORM_ADMIN_FULL_NAME`Display name for bootstrap admin`Admin User`

    πŸ”’ Security Defaults (Secure by Default)

    These settings are enabled by default for securityβ€”only disable for backward compatibility:

    VariableDescriptionDefault
    `REQUIRE_JTI`Require JTI claim in tokens for revocation support`true`
    `REQUIRE_TOKEN_EXPIRATION`Require exp claim in tokens`true`
    `PUBLIC_REGISTRATION_ENABLED`Allow public user self-registration`false`

    πŸ›‘οΈ Content Security

    Content size limits prevent DoS attacks and ensure system stability:

    VariableDescriptionDefault
    `CONTENT_MAX_RESOURCE_SIZE`Maximum resource content size (bytes)`102400` (100KB)
    `CONTENT_MAX_PROMPT_SIZE`Maximum prompt template size (bytes)`10240` (10KB)

    Note: Size limits apply only to new create/update operations. Existing content is not retroactively validated.

    🌐 UAID Cross-Gateway Routing Security

    UAID Security Configuration

    Production Requirements:

    Cross-gateway UAID routing requires explicit security configuration:

    1. Configure Domain Allowlist:

    bash
    UAID_ALLOWED_DOMAINS=["gateway1.example.com", "gateway2.example.com"]

    2. Ensure JWT Trust:

      3. Enable Authentication:

      bash
      AUTH_REQUIRED=true
         UAID_FORWARD_AUTH=true

      Authentication Flow:

      Cross-gateway calls forward the user's bearer token via the `Authorization` header.

      Remote gateways validate tokens through existing auth middleware, preserving RBAC context.

      Security Features:

      • βœ… Fail-closed default: Empty allowlist blocks all cross-gateway routing
      • βœ… Bearer token forwarding: User authentication preserved across hops
      • βœ… Audit trail: Source gateway and user tracked in headers
      • βœ… Clear error messages: Misconfigurations caught at startup and runtime

      Troubleshooting:

      • "UAID_ALLOWED_DOMAINS not configured" error: Add trusted domains to allowlist in .env
      • 401/403 from remote gateway: Verify both gateways trust same JWT issuer
      • "proceeding without authentication token" warning: Check auth middleware extracts token to `request.state.bearer_token`

      For detailed security architecture, see `docs/security/uaid-cross-gateway-auth.md`.

      βš™οΈ Project Defaults (Dev Setup)

      These values differ from code defaults to provide a working local/dev setup:

      VariableDescriptionDefault
      `HOST`Bind address`0.0.0.0`
      `MCPGATEWAY_UI_ENABLED`Enable Admin UI dashboard`true`
      `MCPGATEWAY_ADMIN_API_ENABLED`Enable Admin API endpoints`true`
      `DATABASE_URL`SQLAlchemy connection URL`sqlite:///./mcp.db`
      `SECURE_COOKIES`Set `false` for HTTP (non-HTTPS) dev`false`

      πŸ“š Full Configuration Reference

      For the complete list of 300+ environment variables organized by category (authentication, caching, SSO, observability, etc.), see the **Configuration Reference**.


      Running

      Quick Reference

      CommandServerPortDatabaseUse Case
      `make dev`Uvicorn8000SQLiteDevelopment (single instance, auto-reload)
      `make serve`Gunicorn4444SQLiteProduction single-node (multi-worker)
      `make serve-ssl`Gunicorn4444SQLiteProduction single-node with HTTPS
      `make compose-up`Docker Compose + Nginx8080PostgreSQL + RedisFull stack (3 replicas, load-balanced)
      `make compose-sso`Docker Compose + Keycloak8080 / 8180PostgreSQL + RedisLocal SSO testing (Keycloak profile)
      `make testing-up`Docker Compose + Nginx8080PostgreSQL + RedisTesting environment

      Development Server (Uvicorn)

      bash
      make dev                 # Uvicorn on :8000 with auto-reload and SQLite
      # or
      ./run.sh --reload --log debug --workers 2

      > `run.sh` is a wrapper around `uvicorn` that loads `.env`, supports reload, and passes arguments to the server.

      Key flags:

      FlagPurposeExample
      `-e, --env FILE`load env-file`--env prod.env`
      `-H, --host`bind address`--host 127.0.0.1`
      `-p, --port`listen port`--port 8080`
      `-w, --workers`gunicorn workers`--workers 4`
      `-r, --reload`auto-reload`--reload`

      Production Server (Gunicorn)

      bash
      make serve               # Gunicorn on :4444 with multiple workers
      make serve-ssl           # Gunicorn behind HTTPS on :4444 (uses ./certs)

      Docker Compose (Full Stack)

      bash
      make compose-up          # Start full stack: PostgreSQL, Redis, 3 gateway replicas, Nginx on :8080
      make compose-sso         # Start SSO stack with Keycloak on :8180
      make sso-test-login      # Run SSO smoke checks (providers + login URL + test users)
      make compose-logs        # Tail logs from all services
      make compose-down        # Stop the stack

      Manual (Uvicorn)

      bash
      uvicorn mcpgateway.main:app --host 0.0.0.0 --port 4444 --workers 4

      Cloud Deployment

      ContextForge can be deployed to any major cloud platform:

      PlatformGuide
      AWSECS/EKS Deployment
      AzureAKS Deployment
      Google CloudCloud Run
      IBM CloudCode Engine
      KubernetesHelm Charts
      OpenShiftOpenShift Deployment

      For comprehensive deployment guides, see **Deployment Documentation**.


      API Reference

      Interactive API documentation is available when the server is running:

      • **Swagger UI** β€” Try API calls directly in your browser
      • **ReDoc** β€” Browse the complete endpoint reference

      Quick Authentication:

      bash
      # Read JWT_SECRET_KEY from your .env (it must already contain a real secret)
      export JWT_SECRET_KEY=$(grep '^JWT_SECRET_KEY=' .env | cut -d= -f2)
      
      # Generate a JWT token
      export TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \
        --username admin@example.com --exp 10080 --secret "$JWT_SECRET_KEY")
      
      # Test API access
      curl -H "Authorization: Bearer $TOKEN" http://localhost:4444/health

      For comprehensive curl examples covering all endpoints, see the **API Usage Guide**.


      Testing

      bash
      make test            # Run unit tests
      make lint            # Run all linters
      make doctest         # Run doctests
      make coverage        # Generate coverage report

      See Doctest Coverage Guide for documentation testing details.


      Project Structure

      code
      mcpgateway/          # Core FastAPI application
      β”œβ”€β”€ main.py          # Entry point
      β”œβ”€β”€ config.py        # Pydantic Settings configuration
      β”œβ”€β”€ db.py            # SQLAlchemy ORM models
      β”œβ”€β”€ schemas.py       # Pydantic validation schemas
      β”œβ”€β”€ services/        # Business logic layer (50+ services)
      β”œβ”€β”€ routers/         # HTTP endpoint definitions
      β”œβ”€β”€ middleware/      # Cross-cutting concerns
      └── transports/      # SSE, WebSocket, stdio, streamable HTTP
      
      tests/               # Test suite (7,000+ tests)
      docs/docs/           # Full documentation (MkDocs)
      charts/              # Kubernetes/Helm charts
      plugins/             # Plugin framework and implementations
      mcp-servers/         # Sample/test MCP servers (see note below)

      > Note: The `mcp-servers/` directory contains unsupported sample and test servers,

      > most originating from community contributions, provided for demonstration and integration

      > testing purposes only. They generally lack session management, persistent state,

      > multi-tenancy, authentication, and other production concerns. They do not go through

      > the same review, testing, and security rigor as the core ContextForge codebase and

      > should not be run in production.

      >

      > Security: Never run untrusted MCP servers directly on your local filesystem.

      > Always use a sandbox, container, or microVM (e.g. gVisor, Firecracker) with

      > restricted capabilities. Exercise caution when registering any remote MCP server,

      > including servers from public catalogs β€” perform your own security evaluation

      > before granting access to your gateway.

      For complete structure, see CONTRIBUTING.md or run `tree -L 2`.


      Development

      bash
      make dev             # Dev server with auto-reload (:8000)
      make test            # Run test suite
      make lint            # Run all linters
      make coverage        # Generate coverage report

      Run `make` to see all available targets.

      For development workflows, see:


      Troubleshooting

      Common issues and solutions:

      IssueQuick Fix
      `docker compose up` fails with `cryptography` or dependency resolution errorThe local build requires a CI-produced wheel closure. Run `docker pull ghcr.io/ibm/mcp-context-forge:latest && echo 'IMAGE_LOCAL=ghcr.io/ibm/mcp-context-forge:latest' >> .env` then retry
      `docker compose up` fails with `SecurityConfigurationError: jwt_secret_key``.env` is missing or has `__REPLACE_ME__` placeholders. Run `cp .env.example .env && python3 -m mcpgateway.scripts.init_secrets --patch-env .env`
      `docker compose up` fails β€” `mcpgateway/nginx-cache` pull access deniednginx image must be built locally: `docker compose build nginx`
      `make dev` β€” nothing on port 8000Check terminal for `SecurityConfigurationError` β€” run `make ensure-secrets` then retry. On WSL2 use `http://127.0.0.1:8000` not `localhost`
      SQLite "disk I/O error" on macOSAvoid iCloud-synced directories; use `~/mcp-context-forge/data`
      Port 4444 not accessible on WSL2Configure WSL integration in Docker Desktop
      Gateway exits immediatelyRun `cp .env.example .env && python3 -m mcpgateway.scripts.init_secrets --patch-env .env`
      `ModuleNotFoundError`Run `make install-dev`

      For detailed troubleshooting guides, see **Troubleshooting Documentation**.


      Contributing

      1. Fork the repo, create a feature branch.

      2. Run `make lint` and fix any issues.

      3. Keep `make test` green.

      4. Open a PR with signed commits (`git commit -s`).

      See **CONTRIBUTING.md for full guidelines and Issue Guide #2502** for how to file bugs, request features, and find issues to work on.


      Changelog

      A complete changelog can be found here: CHANGELOG.md

      License

      Licensed under the Apache License 2.0 - see LICENSE

      Core Authors and Maintainers

      Special thanks to our contributors for helping us improve ContextForge:

      Star History and Project Activity

      Star History Chart
      PyPi Downloads
      Stars
      Forks
      Contributors
      Last Commit
      Open Issues

      Frequently asked questions

      What is mcp-context-forge?

      mcp-context-forge is An AI Gateway, registry, and proxy that sits in front of any MCP, A2A, or REST/gRPC APIs, exposing a unified endpoint with centralized discovery, guardrails and management. Optimizes Agent & Tool calling, and supports plugins.

      How do I install mcp-context-forge?

      Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

      Is mcp-context-forge open source?

      Yes β€” it is hosted on GitHub at https://github.com/IBM/mcp-context-forge and has 4,422 stars.

      Related MCP tools

      Run your own MCP server? See who uses it and what to fix.

      Measure it with TrackMCP