Supports Jaeger as an OpenTelemetry backend for monitoring, tracing, and observability of the gateway's performance.
Enables integration with OpenAI's agents through Agent-to-Agent (A2A) protocols, unifying discovery and access for AI clients.
Provides built-in observability by exporting metrics and traces to OpenTelemetry-compliant backends for enhanced monitoring.
Supports PostgreSQL as a database adapter for persistent storage of configuration, multi-tenant resources, and gateway state.
Utilizes Redis as a backend for federation, caching, and metrics aggregation in scalable, multi-cluster deployments.
Supports SQLite for local persistence of the gateway's registry and configuration database.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ContextForge MCP Gatewaylist all registered MCP and REST services"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Gateway
Model Context Protocol gateway & proxy - unify REST, MCP, and A2A with federation, virtual servers, retries, security, and an optional admin UI.

ContextForge MCP Gateway is a feature-rich gateway, proxy and MCP Registry that federates MCP and REST services - unifying discovery, auth, rate-limiting, observability, virtual servers, multi-transport protocols, and an optional Admin UI into one clean endpoint for your AI clients. 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.
Table of Contents
4.1. 🐳 Docker
4.2. 🦭 Podman (rootless-friendly)
4.2.1. 1 - Basic run
4.2.2. 2 - Persist SQLite
7.1. Prerequisites
7.2. One-liner (dev)
7.4. Smoke-test the API
8.1. Via Make
8.2. UV (alternative)
8.3. pip (alternative)
8.4. Optional (PostgreSQL adapter)
8.4.1. Quick Postgres container
10.1. Basic
10.2. Authentication
10.7. Dynamic Client Registration & Virtual MCP Server Authentication
10.8. UI Features
10.9. Security
10.10. Logging
10.11. Transport
10.12. Federation
10.13. Resources
10.14. Tools
10.15. Prompts
10.16. Health Checks
10.17. Database
10.18. Cache Backend
10.19. Tool Lookup Cache
10.20. Metrics Aggregation Cache
10.21. Plugin Configuration
10.22. Development
11.1. Makefile
11.2. Script helper
11.3. Manual (Uvicorn)
14.1. 🔧 Prerequisites
14.2. 📦 Environment Variables
14.3. 🚀 Make Targets
14.4. 📝 Example Workflow
20.1. Diagnose the listener
20.2. Why localhost fails on Windows
20.2.1. Fix (Podman rootless)
20.2.2. Fix (Docker Desktop > 4.19)
🚀 Overview & Goals
ContextForge is a gateway, registry, and proxy that sits in front of any Model Context Protocol (MCP) server, A2A server or REST API-exposing a unified endpoint for all your AI clients. 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
For a list of upcoming features, check out the ContextForge Roadmap
Note on Multi‑Tenancy (v0.7.0): A comprehensive multi‑tenant architecture with email authentication, teams, RBAC, and resource visibility is available since v0.7.0. If upgrading from an older version, see the Migration Guide and Changelog for details.
⚠️ Important: See SECURITY.md for more details.
Sits in front of any MCP server or REST API
Lets you choose your MCP protocol version (e.g.,
2025-03-26)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 + Alpine.js
Real-time log viewer with filtering, search, and export capabilities
Auth: Basic, JWT, or custom schemes
Structured logs, health endpoints, metrics
400+ 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
Easy configuration via environment variables
Quick start with Phoenix (LLM observability):
See Observability Documentation for detailed setup with other backends.
Quick Start - PyPI
ContextForge is published on PyPI as mcp-contextforge-gateway.
TLDR;: (single command using uv)
Python ≥ 3.10 (3.11 recommended)
curl + jq - only for the last smoke-test step
1 - Install & run (copy-paste friendly)
Copy .env.example to .env and tweak any of the settings (or use them as env variables).
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.
or
Pass the url and auth as arguments (no need to set environment variables)
When using a MCP Client such as Claude with stdio:
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
Get a full stack running with MariaDB and Redis in under 30 seconds:
What you get:
🗄️ MariaDB 10.6 - Production-ready database with 36+ tables
🚀 MCP Gateway - 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 (optional)
☸️ Quick Start - Helm (Kubernetes)
Deploy to Kubernetes with enterprise-grade features:
Enterprise Features:
🔄 Auto-scaling - HPA with CPU/memory targets
🗄️ Database Choice - PostgreSQL, MariaDB, or MySQL
📊 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)
1 - Minimum viable run
Browse to http://localhost:4444/admin (user admin / pass changeme).
2 - Persist the SQLite database
SQLite now lives on the host at ./data/mcp.db.
3 - Local tool discovery (host network)
Using --network=host allows Docker to access the local network, allowing you to add MCP servers running on your host. See Docker Host network driver documentation for more details.
4 - Airgapped deployment (no internet access)
For environments without internet access, build a container with bundled UI assets:
The Admin UI will work completely offline with all CSS/JS assets (~932KB) served locally.
🦭 Podman (rootless-friendly)
1 - Basic run
2 - Persist SQLite
3 - Host networking (rootless)
.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.
v0.9.0) instead oflatestfor reproducible builds.JWT tokens - Generate one in the running container:
docker exec mcpgateway python3 -m mcpgateway.utils.create_jwt_token --username admin@example.com --exp 10080 --secret my-test-keyUpgrades - Stop, remove, and rerun with the same
-v $(pwd)/data:/datamount; your DB and config stay intact.
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.
Testing mcpgateway.wrapper by hand:
Because the wrapper speaks JSON-RPC over stdin/stdout, you can interact with it using nothing more than a terminal or pipes.
🧩 Running from an MCP Client (mcpgateway.wrapper)
The mcpgateway.wrapper exposes everything your Gateway knows about over stdio, so any MCP client that can't (or shouldn't) open an authenticated SSE stream still gets full tool-calling power.
Remember to substitute your real Gateway URL (and server ID) for
http://localhost:4444/servers/UUID_OF_SERVER_1/mcp. When inside Docker/Podman, that often becomeshttp://host.docker.internal:4444/servers/UUID_OF_SERVER_1/mcp(macOS/Windows) or the gateway container's hostname (Linux).
Claude Desktop JSON (uses the host Python that pipx injected):
1 - Install uv (uvx is an alias it provides)
2 - Create an on-the-spot venv & run the wrapper
Claude Desktop JSON (runs through uvx)
🚀 Using with Claude Desktop (or any GUI MCP client)
Edit Config →
File ▸ Settings ▸ Developer ▸ Edit ConfigPaste one of the JSON blocks above (Docker / pipx / uvx).
Restart the app so the new stdio server is spawned.
Open logs in the same menu to verify
mcpgateway-wrapperstarted and listed your tools.
Need help? See:
MCP Debugging Guide - https://modelcontextprotocol.io/docs/tools/debugging
🚀 Quick Start: VS Code Dev Container
Spin up a fully-loaded dev environment (Python 3.11, Docker/Podman CLI, all project dependencies) in just two clicks.
VS Code with the Dev Containers extension
Docker or Podman installed and running locally
1 - Clone & Open
VS Code will detect the .devcontainer and prompt:
"Reopen in Container"
or manually run: Ctrl/Cmd ⇧ P → Dev Containers: Reopen in Container
2 - First-Time Build (Automatic)
The container build will:
Install system packages & Python 3.11
Run
make install-devto pull all dependenciesExecute tests to verify the toolchain
You'll land in /workspace ready to develop.
Common tasks inside the container:
Optional:
make bash- drop into an interactive shellmake clean- clear build artefacts & cachesPort forwarding is automatic (customize via
.devcontainer/devcontainer.json)
No local Docker? Use Codespaces:
Go to the repo → Code ▸ Codespaces ▸ Create codespace on main
Wait for the container image to build in the cloud
Develop using the same workflow above
Quick Start (manual install)
Prerequisites
Python ≥ 3.10
GNU Make (optional, but all common workflows are available as Make targets)
Optional: Docker / Podman for containerized runs
One-liner (dev)
What it does:
Creates / activates a
.venvin your home folder~/.venv/mcpgatewayInstalls the gateway and necessary dependencies
Launches Gunicorn (Uvicorn workers) on http://localhost:4444
For development, you can use:
Containerized (self-signed TLS)
Container Runtime Support
This project supports both Docker and Podman. The Makefile automatically detects which runtime is available and handles image naming differences.
Auto-detection
Smoke-test the API
You should receive [] until you register a tool.
Installation
Via Make
UV (alternative)
pip (alternative)
Optional (PostgreSQL adapter)
You can configure the gateway with SQLite, PostgreSQL (or any other compatible database) in .env.
When using PostgreSQL, you need to install the psycopg (psycopg3) driver.
System Dependencies: The PostgreSQL adapter requires the libpq development headers to compile:
Then install the Python package:
Connection URL format (must use +psycopg for psycopg3):
Quick Postgres container
A make compose-up target is provided along with a docker-compose.yml file to make this process simpler.
🔄 Upgrading to v0.7.0
⚠️ CRITICAL: Version 0.7.0 introduces comprehensive multi-tenancy and requires database migration.
Backup Your Data First
Before upgrading to v0.7.0, always backup your database, environment configuration, and export your settings:
Migration Process
Update - Copy new settings:
cp .env.example .envthen configurePLATFORM_ADMIN_EMAILand other required multi-tenancy settingsRun migration - Database schema updates automatically:
python3 -m mcpgateway.bootstrap_dbVerify migration - Use verification script:
python3 scripts/verify_multitenancy_0_7_0_migration.py
If Migration Fails
If the database migration fails or you encounter issues:
Restore database backup:
cp mcp.db.backup.YYYYMMDD_HHMMSS mcp.dbRestore .env backup:
cp .env.bak .envDelete corrupted database:
rm mcp.db(if migration partially completed)Restore configuration: Import your exported configuration via Admin UI
Complete Migration Guide
For detailed upgrade instructions, troubleshooting, and rollback procedures, see:
📖 - Complete step-by-step upgrade guide
🏗️ - Understanding the new system
Configuration (.env or env vars)
⚠️ If any required
.envvariable is missing or invalid, the gateway will fail fast at startup with a validation error via Pydantic.
You can get started by copying the provided .env.example to .env and making the necessary edits to fit your environment.
Basic
Setting | Description | Default | Options |
| Gateway / OpenAPI title |
| string |
| Bind address for the app |
| IPv4/IPv6 |
| Port the server listens on |
| 1-65535 |
| SQLAlchemy connection URL |
| any SQLAlchemy dialect |
| Subpath prefix for app (e.g. | (empty) | string |
| Path to Jinja2 templates |
| path |
| Path to static files |
| path |
| MCP protocol version supported |
| string |
| Content-Type for outgoing requests to Forge |
|
|
💡 Use
APP_ROOT_PATH=/fooif reverse-proxying under a subpath likehttps://host.com/foo/. 🔄 UseFORGE_CONTENT_TYPE=application/x-www-form-urlencodedto send URL-encoded form data instead of JSON.
Authentication
Setting | Description | Default | Options |
| Username for Admin UI login and HTTP Basic authentication |
| string |
| Password for Admin UI login and HTTP Basic authentication |
| string |
| Email for bootstrap platform admin user (auto-created with admin privileges) |
| string |
| Require authentication for all API routes |
| bool |
| Algorithm used to sign the JWTs ( |
| PyJWT algs |
| Secret key used to sign JWT tokens for API access |
| string |
| If an asymmetric algorithm is used, a public key is required | (empty) | path to pem |
| If an asymmetric algorithm is used, a private key is required | (empty) | path to pem |
| JWT audience claim for token validation |
| string |
| Disables jwt audience verification (useful for DCR) |
| boolean |
| Disables jwt issuer verification (useful for custom auth) |
| boolean |
| JWT issuer claim for token validation |
| string |
| Expiry of generated JWTs in minutes |
| int > 0 |
| Require all JWT tokens to have expiration claims |
| bool |
| Require JTI (JWT ID) claim in all tokens for revocation support |
| bool |
| Require all authenticated users to exist in the database |
| bool |
| Embed environment claim in gateway-issued JWTs |
| bool |
| Reject tokens with mismatched environment claim |
| bool |
| Passphrase used to derive AES key for encrypting tool auth headers |
| string |
| OAuth request timeout in seconds |
| int > 0 |
| Maximum retries for OAuth token requests |
| int > 0 |
| Default OAuth token timeout in seconds |
| int > 0 |
🔐
BASIC_AUTH_USER/PASSWORDare used for:
Logging into the web-based Admin UI
Accessing APIs via Basic Auth (
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN")🔑
JWT_SECRET_KEYis used to:
Sign JSON Web Tokens (
Authorization: Bearer <token>)Generate tokens via:
export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token --username admin@example.com --exp 0 --secret my-test-key) echo $MCPGATEWAY_BEARER_TOKENTokens allow non-interactive API clients to authenticate securely.
🧪 Set
AUTH_REQUIRED=falseduring development if you want to disable all authentication (e.g. for local testing or open APIs) or clients that don't support SSE authentication. In production, you should use the SSE to stdiomcpgateway-wrapperfor such tools that don't support authenticated SSE, while still ensuring the gateway uses authentication.🔐
AUTH_ENCRYPTION_SECRETis used to encrypt and decrypt tool authentication credentials (auth_value). You must set the same value across environments to decode previously stored encrypted auth values. Recommended: use a long, random string.
UI Features
Setting | Description | Default | Options |
| Enable the interactive Admin dashboard |
| bool |
| Enable API endpoints for admin ops |
| bool |
| Enable bulk import endpoint for tools |
| bool |
| Maximum number of tools per bulk import request |
| int |
| Rate limit for bulk import endpoint (requests per minute) |
| int |
| Tool test timeout in milliseconds for the admin UI |
| int |
| Enable ContextForge UI features |
| bool |
🖥️ Set both UI and Admin API to
falseto disable management UI and APIs in production. 📥 The bulk import endpoint allows importing up to 200 tools in a single request via/admin/tools/import. ⏱️ IncreaseMCPGATEWAY_UI_TOOL_TEST_TIMEOUTif your tools make multiple API calls or operate in high-latency environments.
A2A (Agent-to-Agent) Features
Setting | Description | Default | Options |
| Enable A2A agent features |
| bool |
| Maximum number of A2A agents allowed |
| int |
| Default timeout for A2A HTTP requests (seconds) |
| int |
| Maximum retry attempts for A2A calls |
| int |
| Enable A2A agent metrics collection |
| bool |
🤖 A2A Integration: Register external AI agents (OpenAI, Anthropic, custom) and expose them as MCP tools 📊 Metrics: Track agent performance, success rates, and response times 🔒 Security: Encrypted credential storage and configurable authentication 🎛️ Admin UI: Dedicated tab for agent management with test functionality
A2A Configuration Effects:
MCPGATEWAY_A2A_ENABLED=false: Completely disables A2A features (API endpoints return 404, admin tab hidden)MCPGATEWAY_A2A_METRICS_ENABLED=false: Disables metrics collection while keeping functionality
ToolOps
ToolOps streamlines the entire workflow by enabling seamless tool enrichment, automated test case generation, and comprehensive tool validation.
Setting | Description | Default | Options |
| Enable ToolOps functionality |
| bool |
LLM Chat MCP Client
The LLM Chat MCP Client allows you to interact with MCP servers using conversational AI from multiple LLM providers. This feature enables natural language interaction with tools, resources, and prompts exposed by MCP servers.
Setting | Description | Default | Options |
| Enable LLM Chat functionality |
| bool |
| LLM provider selection |
|
|
Azure OpenAI Configuration:
Setting | Description | Default | Options |
| Azure OpenAI endpoint URL | (none) | string |
| Azure OpenAI API key | (none) | string |
| Azure OpenAI deployment name | (none) | string |
| Azure OpenAI API version |
| string |
| Sampling temperature |
| float (0.0-2.0) |
| Maximum tokens to generate | (none) | int |
OpenAI Configuration:
Setting | Description | Default | Options |
| OpenAI API key | (none) | string |
| OpenAI model name |
| string |
| Base URL for OpenAI-compatible endpoints | (none) | string |
| Sampling temperature |
| float (0.0-2.0) |
| Maximum number of retries |
| int |
Anthropic Claude Configuration:
Setting | Description | Default | Options |
| Anthropic API key | (none) | string |
| Claude model name |
| string |
| Sampling temperature |
| float (0.0-1.0) |
| Maximum tokens to generate |
| int |
| Maximum number of retries |
| int |
AWS Bedrock Configuration:
Setting | Description | Default | Options |
| Bedrock model ID | (none) | string |
| AWS region name |
| string |
| Sampling temperature |
| float (0.0-1.0) |
| Maximum tokens to generate |
| int |
| AWS access key ID (optional) | (none) | string |
| AWS secret access key (optional) | (none) | string |
| AWS session token (optional) | (none) | string |
IBM WatsonX AI
Setting | Description | Default | Options |
| watsonx url | (none) | string |
| API key | (none) | string |
| Project Id for WatsonX | (none) | string |
| Watsonx model id |
| string |
| temperature (optional) |
| float (0.0-1.0) |
Ollama Configuration:
Setting | Description | Default | Options |
| Ollama base URL |
| string |
| Ollama model name |
| string |
| Sampling temperature |
| float (0.0-2.0) |
⚙️ ToolOps: To manage the complete tool workflow — enrich tools, generate test cases automatically, and validate them with ease. 🤖 LLM Chat Integration: Chat with MCP servers using natural language powered by Azure OpenAI, OpenAI, Anthropic Claude, AWS Bedrock, or Ollama 🔧 Flexible Providers: Switch between different LLM providers without changing your MCP integration 🔒 Security: API keys and credentials are securely stored and never exposed in responses 🎛️ Admin UI: Dedicated LLM Chat tab in the admin interface for interactive conversations
ToolOps Configuration Effects:
TOOLOPS_ENABLED=false(default): Completely disables ToolOps features (API endpoints return 404, admin tab hidden)TOOLOPS_ENABLED=true: Enables ToolOps functionality in the UI
LLM Chat Configuration Effects:
LLMCHAT_ENABLED=false(default): Completely disables LLM Chat features (API endpoints return 404, admin tab hidden)LLMCHAT_ENABLED=true: Enables LLM Chat functionality with the selected provider
Provider Requirements:
Azure OpenAI: Requires
AZURE_OPENAI_ENDPOINT,AZURE_OPENAI_API_KEY, andAZURE_OPENAI_DEPLOYMENTOpenAI: Requires
OPENAI_API_KEYAnthropic: Requires
ANTHROPIC_API_KEYandpip install langchain-anthropicAWS Bedrock: Requires
AWS_BEDROCK_MODEL_IDandpip install langchain-aws boto3. Uses AWS credential chain if explicit credentials not provided. IBM WatsonX AI: RequiresWATSONX_URL,WATSONX_APIKEY,WATSONX_PROJECT_ID,WATSONX_MODEL_IDandpip install langchain-ibm.Ollama: Requires local Ollama instance running (default:
http://localhost:11434)
Redis Configurations: For maintaining Chat Sessions in multi-worker environment
Setting | Description | Default | Options |
| Seconds for active_session key TTL |
| int |
| Seconds for lock expiry |
| int |
| How many times to poll while waiting |
| int |
| Seconds between polls |
| float |
| Seconds for chat history expiry |
| int |
| Maximum message history to store per user |
| int |
Documentation:
LLM Chat Guide - Complete LLM Chat setup and provider configuration
LLM Settings (Internal API)
The LLM Settings feature enables MCP Gateway to act as a unified LLM provider with an OpenAI-compatible API. Configure multiple external LLM providers through the Admin UI and expose them through a single proxy endpoint.
Setting | Description | Default | Options |
| API prefix for internal LLM endpoints |
| string |
| Request timeout for LLM API calls (seconds) |
| int |
| Enable streaming responses |
| bool |
| Provider health check interval (seconds) |
| int |
Gateway Provider Settings (for LLM Chat with provider=gateway):
Setting | Description | Default | Options |
| Default model to use |
| string |
| Base URL for gateway LLM API | (auto) | string |
| Sampling temperature |
| float |
Features:
OpenAI-Compatible API: Exposes
/v1/chat/completionsand/v1/modelsendpoints compatible with any OpenAI clientMulti-Provider Support: Configure OpenAI, Azure OpenAI, Anthropic, Ollama, Google, Mistral, Cohere, AWS Bedrock, Groq, and more
Admin UI Management: Add, edit, enable/disable, and test providers through the Admin UI (LLM Settings tab)
Model Discovery: Fetch available models from providers and sync them to the database
Health Monitoring: Automatic health checks with status indicators
Unified Interface: Route requests to any configured provider through a single API
API Endpoints:
🔧 Configuration: Providers are managed through the Admin UI under "LLM Settings > Providers" 📋 Models: View and manage models under "LLM Settings > Models" ⚡ Testing: Test models directly from the Admin UI with the "Test" feature
Email-Based Authentication & User Management
Setting | Description | Default | Options |
| Enable email-based authentication system |
| bool |
| Email for bootstrap platform admin user |
| string |
| Password for bootstrap platform admin user |
| string |
| Full name for bootstrap platform admin user |
| string |
| Argon2id time cost (iterations) |
| int > 0 |
| Argon2id memory cost in KiB |
| int > 0 |
| Argon2id parallelism (threads) |
| int > 0 |
| Minimum password length |
| int > 0 |
| Require uppercase letters in passwords |
| bool |
| Require lowercase letters in passwords |
| bool |
| Require numbers in passwords |
| bool |
| Require special characters in passwords |
| bool |
| Maximum failed login attempts before lockout |
| int > 0 |
| Account lockout duration in minutes |
| int > 0 |
MCP Client Authentication
Setting | Description | Default | Options |
| Enable JWT authentication for MCP client operations |
| bool |
| Require authentication for /mcp endpoints. If false, unauthenticated requests can access public items only |
| bool |
| Trust proxy authentication headers |
| bool |
| Header containing authenticated username from proxy |
| string |
🔐 MCP Client Auth: When
MCP_CLIENT_AUTH_ENABLED=false, you must setTRUST_PROXY_AUTH=trueif using a trusted authentication proxy. This is a security-sensitive setting.
🔒 MCP Require Auth: When
MCP_REQUIRE_AUTH=true, all/mcpendpoint requests must include a valid Bearer token. Whenfalse(default), unauthenticated requests are allowed but can only access public tools, resources, and prompts.
⚠️ MCP Access Control Dependencies: Full MCP access control (visibility + team scoping + membership validation) requires
MCP_CLIENT_AUTH_ENABLED=truewith valid JWT tokens containing team claims. WhenMCP_CLIENT_AUTH_ENABLED=false, access control relies onMCP_REQUIRE_AUTHplus tool/resource visibility only—team membership validation is skipped since there's no JWT to extract teams from.
SSO (Single Sign-On) Configuration
Setting | Description | Default | Options |
| Master switch for Single Sign-On authentication |
| bool |
| Automatically create users from SSO providers |
| bool |
| Trusted email domains (JSON array) |
| JSON array |
| Preserve local admin authentication when SSO enabled |
| bool |
| Require admin approval for new SSO registrations |
| bool |
| Optional JSON array of issuer URLs for SSO providers | (none) | JSON array |
GitHub OAuth:
Setting | Description | Default | Options |
| Enable GitHub OAuth authentication |
| bool |
| GitHub OAuth client ID | (none) | string |
| GitHub OAuth client secret | (none) | string |
| GitHub orgs granting admin privileges (JSON) |
| JSON array |
Google OAuth:
Setting | Description | Default | Options |
| Enable Google OAuth authentication |
| bool |
| Google OAuth client ID | (none) | string |
| Google OAuth client secret | (none) | string |
| Google admin domains (JSON) |
| JSON array |
IBM Security Verify OIDC:
Setting | Description | Default | Options |
| Enable IBM Security Verify OIDC authentication |
| bool |
| IBM Security Verify client ID | (none) | string |
| IBM Security Verify client secret | (none) | string |
| IBM Security Verify OIDC issuer URL | (none) | string |
Keycloak OIDC:
Setting | Description | Default | Options |
| Enable Keycloak OIDC authentication |
| bool |
| Keycloak base URL | (none) | string |
| Keycloak realm name |
| string |
| Keycloak client ID | (none) | string |
| Keycloak client secret | (none) | string |
| Map Keycloak realm roles to gateway teams |
| bool |
| Map Keycloak client roles to gateway RBAC |
| bool |
| JWT claim for username |
| string |
| JWT claim for email |
| string |
| JWT claim for groups/roles |
| string |
Microsoft Entra ID OIDC:
Setting | Description | Default | Options |
| Enable Microsoft Entra ID OIDC authentication |
| bool |
| Microsoft Entra ID client ID | (none) | string |
| Microsoft Entra ID client secret | (none) | string |
| Microsoft Entra ID tenant ID | (none) | string |
Generic OIDC Provider (Auth0, Authentik, etc.):
Setting | Description | Default | Options |
| Enable generic OIDC provider authentication |
| bool |
| Provider ID (e.g., keycloak, auth0, authentik) | (none) | string |
| Display name shown on login page | (none) | string |
| Generic OIDC client ID | (none) | string |
| Generic OIDC client secret | (none) | string |
| Authorization endpoint URL | (none) | string |
| Token endpoint URL | (none) | string |
| Userinfo endpoint URL | (none) | string |
| OIDC issuer URL | (none) | string |
| OAuth scopes (space-separated) |
| string |
Okta OIDC:
Setting | Description | Default | Options |
| Enable Okta OIDC authentication |
| bool |
| Okta client ID | (none) | string |
| Okta client secret | (none) | string |
| Okta issuer URL | (none) | string |
SSO Admin Assignment:
Setting | Description | Default | Options |
| Email domains that automatically get admin privileges |
| JSON array |
OAuth 2.0 Dynamic Client Registration (DCR) & PKCE
ContextForge implements OAuth 2.0 Dynamic Client Registration (RFC 7591) and PKCE (RFC 7636) for seamless integration with OAuth-protected MCP servers and upstream API gateways like HyperMCP.
Key Features:
✅ Automatic client registration with Authorization Servers (no manual credential configuration)
✅ Authorization Server metadata discovery (RFC 8414)
✅ PKCE (Proof Key for Code Exchange) enabled for all Authorization Code flows
✅ Support for public clients (PKCE-only, no client secret)
✅ Encrypted credential storage with Fernet encryption
✅ Configurable issuer allowlist for security
Setting | Description | Default | Options |
| Enable Dynamic Client Registration (RFC 7591) |
| bool |
| Auto-register when gateway has issuer but no client_id |
| bool |
| Default OAuth scopes to request during DCR |
| JSON array |
| Allowlist of trusted issuer URLs (empty = allow any) |
| JSON array |
| Token endpoint auth method |
|
|
| AS metadata cache TTL in seconds |
| int |
| Template for client_name in DCR requests |
| string |
| Enable AS metadata discovery (RFC 8414) |
| bool |
| PKCE code challenge method |
|
|
| JWT audience verification (disable for DCR) |
| bool |
| JWT issuer verification (disable if needed) |
| bool |
Documentation:
DCR Configuration Guide - Complete DCR setup and troubleshooting
OAuth 2.0 Integration - OAuth configuration and PKCE details
HyperMCP Tutorial - End-to-end DCR setup with HyperMCP gateway
Personal Teams Configuration
Setting | Description | Default | Options |
| Enable automatic personal team creation for new users |
| bool |
| Personal team naming prefix |
| string |
| Maximum number of teams a user can belong to |
| int > 0 |
| Maximum number of members per team |
| int > 0 |
| Number of days before team invitations expire |
| int > 0 |
| Require email verification for team invitations |
| bool |
MCP Server Catalog
🆕 New in v0.7.0: The MCP Server Catalog allows you to define a catalog of pre-configured MCP servers in a YAML file for easy discovery and management via the Admin UI.
Setting | Description | Default | Options |
| Enable MCP server catalog feature |
| bool |
| Path to catalog configuration file |
| string |
| Automatically health check catalog servers |
| bool |
| Catalog cache TTL in seconds |
| int > 0 |
| Number of catalog servers per page |
| int > 0 |
Key Features:
🔄 Refresh Button - Manually refresh catalog without page reload
🔍 Debounced Search - Optimized search with 300ms debounce
📝 Custom Server Names - Specify custom names when registering
🔌 Transport Detection - Auto-detect SSE, WebSocket, or HTTP transports
🔐 OAuth Support - Register OAuth servers and configure later
⚡ Better Error Messages - User-friendly errors for common issues
Documentation:
MCP Server Catalog Guide - Complete catalog setup and configuration
Security
Setting | Description | Default | Options |
| Skip upstream TLS verification |
| bool |
| Deployment environment (affects security defaults) |
|
|
| Domain for production CORS origins |
| string |
| CORS allow-list | Auto-configured by environment | JSON array |
| Enable CORS |
| bool |
| Allow credentials in CORS |
| bool |
| Force secure cookie flags |
| bool |
| Cookie SameSite attribute |
|
|
| Enable security headers middleware |
| bool |
| X-Frame-Options header value |
|
|
| Enable X-Content-Type-Options: nosniff header |
| bool |
| Enable X-XSS-Protection header |
| bool |
| Enable X-Download-Options: noopen header |
| bool |
| Enable HSTS header |
| bool |
| HSTS max age in seconds |
| int |
| Include subdomains in HSTS header |
| bool |
| Remove server identification |
| bool |
| Allow Basic Auth for docs (in addition to JWT) |
| bool |
| Minimum length for secret keys (JWT, encryption) |
| int |
| Minimum length for passwords |
| int |
| Enforce strong secrets (fail startup on weak secrets) |
| bool |
CORS Configuration: When
ENVIRONMENT=development, CORS origins are automatically configured for common development ports (3000, 8080, gateway port). In production, origins are constructed fromAPP_DOMAIN(e.g.,https://yourdomain.com,https://app.yourdomain.com). You can override this by explicitly settingALLOWED_ORIGINS.Security Headers: The gateway automatically adds configurable security headers to all responses including CSP, X-Frame-Options, X-Content-Type-Options, X-Download-Options, and HSTS (on HTTPS). All headers can be individually enabled/disabled. Sensitive server headers are removed.
Security Validation: Set
REQUIRE_STRONG_SECRETS=trueto enforce minimum lengths for JWT secrets and passwords at startup. This helps prevent weak credentials in production. Default isfalsefor backward compatibility.iframe Embedding: The gateway controls iframe embedding through both
X-Frame-Optionsheader and CSPframe-ancestorsdirective (both are automatically synced). Options:
X_FRAME_OPTIONS=DENY(default): Blocks all iframe embedding
X_FRAME_OPTIONS=SAMEORIGIN: Allows embedding from same domain only
X_FRAME_OPTIONS="ALLOW-ALL": Allows embedding from all sources (setsframe-ancestors * file: http: https:)
X_FRAME_OPTIONS=nullornone: Completely removes iframe restrictions (no headers sent)Modern browsers prioritize CSP
frame-ancestorsover the legacyX-Frame-Optionsheader. Both are now kept in sync automatically.Cookie Security: Authentication cookies are automatically configured with HttpOnly, Secure (in production), and SameSite attributes for CSRF protection.
Note: do not quote the ALLOWED_ORIGINS values, this needs to be valid JSON, such as: ALLOWED_ORIGINS=["http://localhost", "http://localhost:4444"]
Documentation endpoints (
/docs,/redoc,/openapi.json) are always protected by authentication. By default, they require Bearer token authentication. SettingDOCS_ALLOW_BASIC_AUTH=trueenables HTTP Basic Authentication as an additional method using the same credentials asBASIC_AUTH_USERandBASIC_AUTH_PASSWORD.
Ed25519 Certificate Signing
MCP Gateway supports Ed25519 digital signatures for certificate validation and integrity verification. This cryptographic signing mechanism ensures that CA certificates used by the gateway are authentic and haven't been tampered with.
Setting | Description | Default | Options |
| Enable Ed25519 signing for certificates |
| bool |
| Ed25519 private key for signing (PEM format) | (none) | string |
| Previous Ed25519 private key for key rotation | (none) | string |
How It Works:
Certificate Signing - When
ENABLE_ED25519_SIGNING=true, the gateway signs the CA certificate of each MCP server/gateway using the Ed25519 private key.Certificate Validation - Before using a CA certificate for subsequent calls, the gateway validates its signature to ensure authenticity and integrity.
Disabled Mode - When
ENABLE_ED25519_SIGNING=false, certificates are neither signed nor validated (default behavior).
Key Generation:
Key Rotation:
To rotate keys without invalidating existing signed certificates:
Move the current
ED25519_PRIVATE_KEYvalue toPREV_ED25519_PRIVATE_KEYGenerate a new key pair using the command above
Set the new private key to
ED25519_PRIVATE_KEYThe gateway will automatically re-sign valid certificates at the point of key change
Example Configuration:
🔐 Security Best Practices:
Store private keys securely (use secrets management tools like Vault, AWS Secrets Manager, etc.)
Rotate keys periodically (recommended: every 90-180 days)
Never commit private keys to version control
Use environment variables or encrypted config files
🔑 Public Key Derivation:
Public keys are automatically derived from private keys
No need to configure public keys separately
Both
ED25519_PUBLIC_KEYandPREV_ED25519_PUBLIC_KEYare computed at startup⚡ Performance:
Ed25519 signing is extremely fast (~64 microseconds per signature)
Minimal impact on gateway performance
Recommended for production deployments requiring certificate integrity
Response Compression
MCP Gateway includes automatic response compression middleware that reduces bandwidth usage by 30-70% for text-based responses (JSON, HTML, CSS, JS). Compression is negotiated automatically based on client Accept-Encoding headers with algorithm priority: Brotli (best compression) > Zstd (fastest) > GZip (universal fallback).
Setting | Description | Default | Options |
| Enable response compression |
| bool |
| Minimum response size in bytes to compress |
| int (0=compress all) |
| GZip compression level (1=fast, 9=best) |
| int (1-9) |
| Brotli quality (0-3=fast, 4-9=balanced, 10-11=max) |
| int (0-11) |
| Zstd level (1-3=fast, 4-9=balanced, 10+=slow) |
| int (1-22) |
Compression Behavior:
Automatically negotiates algorithm based on client
Accept-EncodingheaderOnly compresses responses larger than
COMPRESSION_MINIMUM_SIZEbytes (small responses not worth compression overhead)Adds
Vary: Accept-Encodingheader for proper cache behaviorNo client changes required (browsers/clients handle decompression automatically)
Typical compression ratios: JSON responses 40-60%, HTML responses 50-70%
Performance Impact:
CPU overhead: <5% (balanced settings)
Bandwidth reduction: 30-70% for text responses
Latency impact: <10ms for typical responses
Testing Compression:
Tuning for Production:
Note: See Scaling Guide for compression performance optimization at scale.
Logging
MCP Gateway provides flexible logging with stdout/stderr output by default and optional file-based logging. When file logging is enabled, it provides JSON formatting for structured logs and text formatting for console output.
Setting | Description | Default | Options |
| Minimum log level |
|
|
| Console log format |
|
|
| Enable detailed request logging |
|
|
| Max request body size to log (bytes) |
|
|
| Enable file logging |
|
|
| Log filename (when enabled) |
|
|
| Directory for log files |
|
|
| File write mode |
|
|
| Enable log file rotation |
|
|
| Max file size before rotation (MB) |
| Any positive integer |
| Number of backup files to keep |
| Any non-negative integer |
| Size of in-memory log buffer (MB) |
| float > 0 |
Logging Behavior:
Default: Logs only to stdout/stderr with human-readable text format
File Logging: When
LOG_TO_FILE=true, logs to both file (JSON format) and console (text format)Log Rotation: When
LOG_ROTATION_ENABLED=true, files rotate atLOG_MAX_SIZE_MBwithLOG_BACKUP_COUNTbackup files (e.g.,.log.1,.log.2)Directory Creation: Log folder is automatically created if it doesn't exist
Centralized Service: All modules use the unified
LoggingServicefor consistent formattingDetailed Request Logging: When
LOG_REQUESTS=true, payload logging is truncated toLOG_DETAILED_MAX_BODY_SIZEand skipped for/health,/healthz,/static, and/favicon.ico
Example Configurations:
Default Behavior:
Logs are written only to stdout/stderr in human-readable text format
File logging is disabled by default (no files created)
Set
LOG_TO_FILE=trueto enable optional file logging with JSON format
Observability (OpenTelemetry)
MCP Gateway includes vendor-agnostic OpenTelemetry support for distributed tracing. Works with Phoenix, Jaeger, Zipkin, Tempo, DataDog, New Relic, and any OTLP-compatible backend.
Setting | Description | Default | Options |
| Master switch for observability |
|
|
| Service identifier in traces |
| string |
| Service version in traces |
| string |
| Environment tag (dev/staging/prod) |
| string |
| Trace exporter backend |
|
|
| Custom resource attributes | (empty) |
|
OTLP Configuration (for Phoenix, Tempo, DataDog, etc.):
Setting | Description | Default | Options |
| OTLP collector endpoint | (none) |
|
| OTLP protocol |
|
|
| Authentication headers | (empty) |
|
| Skip TLS verification |
|
|
Alternative Backends (optional):
Setting | Description | Default | Options |
| Jaeger collector endpoint |
| URL |
| Zipkin collector endpoint |
| URL |
Performance Tuning:
Setting | Description | Default | Options |
| Sampling strategy |
|
|
| Sample rate (0.0-1.0) |
| float (0.1 = 10% sampling) |
| Max queued spans |
| int > 0 |
| Max batch size for export |
| int > 0 |
| Export interval (ms) |
| int > 0 |
Quick Start with Phoenix:
🔍 What Gets Traced: Tool invocations, prompt rendering, resource fetching, gateway federation, health checks, plugin execution (if enabled)
🚀 Zero Overhead: When
OTEL_ENABLE_OBSERVABILITY=false, all tracing is disabled with no performance impact📊 View Traces: Phoenix UI at
http://localhost:6006, Jaeger athttp://localhost:16686, or your configured backend
Internal Observability & Tracing
The gateway includes built-in observability features for tracking HTTP requests, spans, and traces independent of OpenTelemetry. This provides database-backed trace storage and analysis directly in the Admin UI.
Setting | Description | Default | Options | ||
| Enable internal observability tracing and metrics |
| bool | ||
| Automatically trace HTTP requests |
| bool | ||
| Number of days to retain trace data |
| int (≥ 1) | ||
| Maximum number of traces to retain |
| int (≥ 1000) | ||
| Trace sampling rate (0.0-1.0) |
| float (0.0-1.0) | ||
| Regex patterns to include for tracing | `["^/rpc/?$","^/sse$","^/message$","^/mcp(?:/ | $)","^/servers/[^/]+/mcp/?$","^/servers/[^/]+/sse$","^/servers/[^/]+/message$","^/a2a(?:/ | $)"]` | JSON array |
| Regex patterns to exclude (after include patterns) |
| JSON array | ||
| Enable metrics collection |
| bool | ||
| Enable event logging within spans |
| bool |
Key Features:
📊 Database-backed storage: Traces stored in SQLite/PostgreSQL for persistence
🔍 Admin UI integration: View traces, spans, and metrics in the diagnostics tab
🎯 Sampling control: Configure sampling rate to reduce overhead in high-traffic scenarios
🕐 Automatic cleanup: Old traces automatically purged based on retention settings
🚫 Path filtering: Only include-listed endpoints are traced by default (MCP/A2A); regex excludes apply after includes
Configuration Effects:
OBSERVABILITY_ENABLED=false: Completely disables internal observability (no database writes, zero overhead)OBSERVABILITY_SAMPLE_RATE=0.1: Traces 10% of requests (useful for high-volume production)OBSERVABILITY_INCLUDE_PATHS=["^/mcp(?:/|$)","^/a2a(?:/|$)"]: Limits tracing to MCP and A2A endpointsOBSERVABILITY_INCLUDE_PATHS=[]: Traces all endpoints (still subject to exclude patterns)OBSERVABILITY_EXCLUDE_PATHS=["/health","/metrics"]: Prevents noisy endpoints from creating traces
📝 Note: This is separate from OpenTelemetry. You can use both systems simultaneously - internal observability for Admin UI visibility and OpenTelemetry for external systems like Phoenix/Jaeger.
🎛️ Admin UI Access: When enabled, traces appear in Admin → Diagnostics → Observability tab with filtering, search, and export capabilities
Prometheus Metrics
The gateway exposes Prometheus-compatible metrics at /metrics/prometheus for monitoring and alerting.
Setting | Description | Default | Options |
| Enable Prometheus metrics instrumentation |
| bool |
| Regex patterns for paths to exclude from metrics | (empty) | comma-separated |
| Prometheus metrics namespace (prefix) |
| string |
| Prometheus metrics subsystem (secondary prefix) | (empty) | string |
| Static custom labels for app_info gauge | (empty) |
|
Key Features:
📊 Standard metrics: HTTP request duration, response codes, active requests
🏷️ Custom labels: Add static labels (environment, region, team) for filtering in Prometheus/Grafana
🚫 Path exclusions: Prevent high-cardinality issues by excluding dynamic paths
📈 Namespace isolation: Group metrics by application or organization
Configuration Examples:
Metric Names:
With namespace + subsystem:
mycompany_gateway_http_requests_totalDefault (no namespace/subsystem):
default_http_requests_total
⚠️ High-Cardinality Warning: Never use high-cardinality values (user IDs, request IDs, timestamps) in
METRICS_CUSTOM_LABELS. Only use low-cardinality static values (environment, region, cluster).📊 Prometheus Endpoint: Access metrics at
GET /metrics/prometheus(requires authentication ifAUTH_REQUIRED=true)🎯 Grafana Integration: Import metrics into Grafana dashboards using the configured namespace as a filter
Metrics Cleanup & Rollup
Automatic management of metrics data to prevent unbounded table growth and maintain query performance.
Setting | Description | Default | Options |
| Enable execution metrics recording (tool/resource/prompt/server/A2A) |
| bool |
| Enable automatic cleanup of old metrics |
| bool |
| Days to retain raw metrics (fallback) |
| 1-365 |
| Hours between automatic cleanup runs |
| 1-168 |
| Batch size for deletion (prevents long locks) |
| 100-100000 |
| Enable hourly metrics rollup |
| bool |
| Hours between rollup runs |
| 1-24 |
| Days to retain hourly rollup data |
| 30-3650 |
| Hours to re-process for late-arriving data |
| 1-48 |
| Delete raw metrics after rollup exists |
| bool |
| Hours to retain raw when rollup exists |
| 1-8760 |
| Use PostgreSQL-native percentile_cont for p50/p95/p99 |
| bool |
| Rows per batch when streaming rollup queries |
| 100-10000 |
Key Features:
📊 Hourly rollup: Pre-aggregated summaries with p50/p95/p99 percentiles
🗑️ Batched cleanup: Prevents long table locks during deletion
📈 Admin API: Manual triggers at
/api/metrics/cleanupand/api/metrics/rollup⚙️ Configurable retention: Separate retention for raw and rollup data
Deletion behavior:
Deleted tools/resources/prompts/servers are removed from Top Performers by default, but historical rollups remain for reporting.
To permanently erase metrics for a deleted entity, use the Admin UI delete prompt and choose Purge metrics, or call the delete endpoints with
?purge_metrics=true.Purge deletes use batched deletes sized by
METRICS_CLEANUP_BATCH_SIZEto reduce long table locks on large datasets.
🚀 Performance: Reduces storage by 90%+ and query latency from seconds to milliseconds for historical data
Transport
Setting | Description | Default | Options |
| Enabled transports |
|
|
| WebSocket ping (secs) |
| int > 0 |
| SSE retry timeout (ms) |
| int > 0 |
| Enable SSE keepalive events |
| bool |
| SSE keepalive interval (secs) |
| int > 0 |
| streamable http config |
| bool |
| json/sse streams (streamable http) |
| bool |
💡 SSE Keepalive Events: The gateway sends periodic keepalive events to prevent connection timeouts with proxies and load balancers. Disable with
SSE_KEEPALIVE_ENABLED=falseif your client doesn't handle unknown event types. Common intervals: 30s (default), 60s (AWS ALB), 240s (Azure).
Federation
Setting | Description | Default | Options |
| Gateway timeout (secs) |
| int > 0 |
Resources
Setting | Description | Default | Options |
| LRU cache size |
| int > 0 |
| Cache TTL (seconds) |
| int > 0 |
| Max resource bytes |
| int > 0 |
| Acceptable MIME types | see code | JSON array |
Tools
Setting | Description | Default | Options |
| Tool invocation timeout (secs) |
| int > 0 |
| Max retry attempts |
| int ≥ 0 |
| Tool calls per minute |
| int > 0 |
| Concurrent tool invocations |
| int > 0 |
| Tool name separator for gateway routing |
|
|
Prompts
Setting | Description | Default | Options |
| Cached prompt templates |
| int > 0 |
| Max prompt template size (bytes) |
| int > 0 |
| Jinja render timeout (secs) |
| int > 0 |
Health Checks
Setting | Description | Default | Options |
| Health poll interval (secs) |
| int > 0 |
| Health request timeout (secs) |
| int > 0 |
| Per-check timeout for gateway health check (secs) |
| float > 0 |
| Fail-count before peer deactivation, |
| int > 0 |
Set to -1 if deactivation is not needed. | |||
| Gateway URL validation timeout (secs) |
| int > 0 |
| Max Concurrent health checks |
| int > 0 |
| Auto Refresh tools/prompts/resources |
| bool |
| File lock for leader election |
| string |
| Default root paths for resources |
| JSON array |
Database
Setting | Description | Default | Options |
| SQLAlchemy connection pool size |
| int > 0 |
| Extra connections beyond pool |
| int ≥ 0 |
| Wait for connection (secs) |
| int > 0 |
| Recycle connections (secs) |
| int > 0 |
| Max retry attempts at startup (exponential backoff) |
| int > 0 |
| Base retry interval (ms), doubles each attempt up to 30s |
| int > 0 |
Cache Backend
Setting | Description | Default | Options |
| Backend type |
|
|
| Redis connection URL | (none) | string or empty |
| Key prefix |
| string |
| Session validity (secs) |
| int > 0 |
| Message retention (secs) |
| int > 0 |
| Max retry attempts at startup (exponential backoff) |
| int > 0 |
| Base retry interval (ms), doubles each attempt up to 30s |
| int > 0 |
| Connection pool size |
| int > 0 |
| Socket timeout (secs) |
| float > 0 |
| Connect timeout (secs) |
| float > 0 |
| Retry on timeout |
| bool |
| Health check (secs) |
| int >= 0 |
| Return strings vs bytes |
| bool |
| Leader election TTL (secs) |
| int > 0 |
| Leader key name |
| string |
| Heartbeat (secs) |
| int > 0 |
🧠
nonedisables caching entirely. Usememoryfor dev,databasefor local persistence, orredisfor distributed caching across multiple instances.
Tool Lookup Cache
Setting | Description | Default | Options |
| Enable tool lookup cache for |
| bool |
| Cache TTL (seconds) for tool lookup entries |
| int (5-600) |
| Cache TTL (seconds) for missing/inactive/offline entries |
| int (1-60) |
| Max entries in in-memory L1 cache |
| int (100-1000000) |
| Enable Redis-backed L2 cache when |
| bool |
⚡ Performance: Eliminates a DB lookup per tool invocation. L1 is always available; L2 activates when
CACHE_TYPE=redisandTOOL_LOOKUP_CACHE_L2_ENABLED=true.
Metrics Aggregation Cache
Setting | Description | Default | Options |
| Enable metrics query caching |
| bool |
| Cache TTL (seconds) |
| int (1-300) |
⚡ Performance: Caches aggregate metrics queries to reduce full table scans. Under high load (3000+ users), setting TTL to 60-120 seconds can reduce database scans by 6-12×. See Issue #1906.
MCP Session Pool
Setting | Description | Default | Options |
| Enable session pooling (10-20x latency improvement) |
| bool |
| Max sessions per (URL, identity, transport) |
| int (1-100) |
| Session TTL before forced close (seconds) |
| float |
| Timeout for all HTTP operations (seconds) |
| float |
| Idle time before health check (seconds) |
| float |
| Timeout waiting for session slot (seconds) |
| float |
| Timeout creating new session (seconds) |
| float |
| Failures before circuit opens |
| int |
| Seconds before circuit resets |
| float |
| Evict idle pool keys after (seconds) |
| float |
| Force explicit RPC on health checks |
| bool |
⚡ Performance: Session pooling reduces per-request overhead from ~20ms to ~1-2ms (10-20x improvement). Sessions are isolated per user/tenant via identity hashing to prevent cross-user session sharing.
🔒 Security: Sessions are keyed by
(URL, identity_hash, transport_type)to ensure different users never share sessions.🏥 Health Checks: By default, the pool's internal staleness check handles health verification. Set
MCP_SESSION_POOL_EXPLICIT_HEALTH_RPC=truefor stricter verification at ~5ms latency cost per check.
Database Management
MCP Gateway uses Alembic for database migrations. Common commands:
make db-current- Show current database versionmake db-upgrade- Apply pending migrationsmake db-migrate- Create new migrationmake db-history- Show migration historymake db-status- Detailed migration status
Troubleshooting
Common Issues:
"No 'script_location' key found": Ensure you're running from the project root directory.
"Unknown SSE event: keepalive" warnings: Some MCP clients don't recognize keepalive events. These warnings are harmless and don't affect functionality. To disable:
SSE_KEEPALIVE_ENABLED=falseConnection timeouts with proxies/load balancers: If experiencing timeouts, adjust keepalive interval to match your infrastructure:
SSE_KEEPALIVE_INTERVAL=60(AWS ALB) or240(Azure).
Development
Setting | Description | Default | Options |
| Enable dev mode |
| bool |
| Auto-reload on changes |
| bool |
| Debug logging |
| bool |
Well-Known URI Configuration
Setting | Description | Default | Options |
| Enable well-known URI endpoints (/.well-known/*) |
| bool |
| robots.txt content | (blocks crawlers) | string |
| security.txt content (RFC 9116) | (empty) | string |
| Additional custom well-known files (JSON) |
| JSON object |
| Cache control for well-known files (seconds) |
| int > 0 |
🔍 robots.txt: By default, blocks all crawlers for security. Customize for your needs.
🔐 security.txt: Define security contact information per RFC 9116. Leave empty to disable.
📄 Custom Files: Add arbitrary well-known files like
ai.txt,dnt-policy.txt, etc.
Header Passthrough Configuration
Setting | Description | Default | Options |
| Enable HTTP header passthrough feature (⚠️ Security implications) |
| bool |
| Enable overwriting of base headers (⚠️ Advanced usage) |
| bool |
| Default headers to pass through (JSON array) |
| JSON array |
| In-memory cache TTL for GlobalConfig (seconds). Reduces DB queries under load. |
| int (5-3600) |
⚠️ Security Warning: Header passthrough is disabled by default for security. Only enable if you understand the implications and have reviewed which headers should be passed through to backing MCP servers. Authorization headers are not included in defaults.
Plugin Configuration
Setting | Description | Default | Options |
| Enable the plugin framework |
| bool |
| Path to main plugin configuration file |
| string |
| (Optional) default CA bundle for external plugin mTLS | (empty) | string |
| (Optional) gateway client certificate for plugin mTLS | (empty) | string |
| (Optional) gateway client key for plugin mTLS | (empty) | string |
| (Optional) password for plugin client key | (empty) | string |
| (Optional) verify remote plugin certificates ( |
| bool |
| (Optional) enforce hostname verification for plugins |
| bool |
| Enable auto-completion for plugins CLI |
| bool |
| Set markup mode for plugins CLI | (none) |
|
HTTP Retry Configuration
Setting | Description | Default | Options |
| Maximum retry attempts for HTTP requests |
| int > 0 |
| Base delay between retries (seconds) |
| float > 0 |
| Maximum delay between retries (seconds) |
| int > 0 |
| Maximum jitter fraction of base delay |
| float 0-1 |
Running
Makefile
Script helper
To run the development (uvicorn) server:
run.shis a wrapper arounduvicornthat loads.env, supports reload, and passes arguments to the server.
Key flags:
Flag | Purpose | Example |
| load env-file |
|
| bind address |
|
| listen port |
|
| gunicorn workers |
|
| auto-reload |
|
Manual (Uvicorn)
Authentication examples
☁️ AWS / Azure / OpenShift
Deployment details can be found in the GitHub Pages.
☁️ IBM Cloud Code Engine Deployment
This project supports deployment to IBM Cloud Code Engine using the ibmcloud CLI and the IBM Container Registry.
🔧 Prerequisites
Podman or Docker installed locally
IBM Cloud CLI (use
make ibmcloud-cli-installto install)An IBM Cloud API key with access to Code Engine & Container Registry
Code Engine and Container Registry services enabled in your IBM Cloud account
📦 Environment Variables
Create a .env file (or export the variables in your shell).
The first block is required; the second provides tunable defaults you can override:
✅ Quick check:
make ibmcloud-check-env
🚀 Make Targets
Target | Purpose |
| Install IBM Cloud CLI and required plugins |
| Log in to IBM Cloud (API key or SSO) |
| Select the Code Engine project & region |
| Tag the local container image |
| Push the image to IBM Container Registry |
| Create or update the Code Engine application (uses CPU/memory/secret) |
| Show current deployment status |
| Stream logs from the running app |
| Delete the Code Engine application |
📝 Example Workflow
API Endpoints
You can test the API endpoints through curl, or Swagger UI, and check detailed documentation on ReDoc:
Swagger UI → http://localhost:4444/docs
ReDoc → http://localhost:4444/redoc
Generate an API Bearer token, and test the various API endpoints.
Handles any method name: list_tools, list_gateways, prompts/get, or invokes a tool if method matches a registered tool name .
🤖 A2A Integration: A2A agents are external AI agents that can be registered and exposed as MCP tools 🔄 Protocol Detection: Gateway automatically detects JSONRPC vs custom A2A protocols 📊 Testing: Built-in test functionality via Admin UI or
/a2a/{agent_id}/testendpoint 🎛️ Virtual Servers: Associate agents with servers to expose them as standard MCP tools
Full Swagger UI at /docs.
Testing
Doctest Coverage
ContextForge implements comprehensive doctest coverage to ensure all code examples in documentation are tested and verified:
Coverage Status:
✅ Transport Modules: 100% (base, stdio, SSE, WebSocket, streamable HTTP)
✅ Utility Functions: 100% (slug generation, JWT tokens, validation)
✅ Configuration: 100% (settings, environment variables)
🔄 Service Classes: ~60% (in progress)
🔄 Complex Classes: ~40% (in progress)
Benefits:
All documented examples are automatically tested
Documentation stays accurate and up-to-date
Developers can run examples directly from docstrings
Regression prevention through automated verification
For detailed information, see the Doctest Coverage Guide.
Project Structure
API Documentation
Swagger UI → http://localhost:4444/docs
ReDoc → http://localhost:4444/redoc
Admin Panel → http://localhost:4444/admin
Makefile targets
This project offer the following Makefile targets. Type make in the project root to show all targets.
🔍 Troubleshooting
If the gateway fails on macOS with sqlite3.OperationalError: disk I/O error (works on Linux/Docker), it's usually a filesystem/locking quirk rather than a schema bug.
Quick placement guidance (macOS):
Avoid cloning/running the repo under
~/Documentsor~/Desktopif iCloud "Desktop & Documents" sync is enabled.A simple, safe choice is a project folder directly under your home directory:
mkdir -p "$HOME/mcp-context-forge" && cd "$HOME/mcp-context-forge"If you keep the DB inside the repo, use a subfolder like
data/and an absolute path in.env:mkdir -p "$HOME/mcp-context-forge/data"DATABASE_URL=sqlite:////Users/$USER/mcp-context-forge/data/mcp.db
Use a safe, local APFS path for SQLite (avoid iCloud/Dropbox/OneDrive/Google Drive, network shares, or external exFAT/NAS):
Option A (system location): point the DB to Application Support (note spaces):
mkdir -p "$HOME/Library/Application Support/mcpgateway"export DATABASE_URL="sqlite:////Users/$USER/Library/Application Support/mcpgateway/mcp.db"
Option B (project-local): keep the DB under
~/mcp-context-forge/data:mkdir -p "$HOME/mcp-context-forge/data"export DATABASE_URL="sqlite:////Users/$USER/mcp-context-forge/data/mcp.db"
Clean stale SQLite artifacts after any crash:
pkill -f mcpgateway || true && rm -f mcp.db-wal mcp.db-shm mcp.db-journal
Reduce startup concurrency to rule out multi-process contention:
GUNICORN_WORKERS=1 make serve(or usemake devwhich runs single-process)
Run the diagnostic helper to verify the environment:
python3 scripts/test_sqlite.py --verbose
While debugging, consider lowering pool pressure and retry:
DB_POOL_SIZE=10 DB_MAX_OVERFLOW=0 DB_POOL_TIMEOUT=60 DB_MAX_RETRIES=10 DB_RETRY_INTERVAL_MS=5000
Optional: temporarily disable the file-lock leader path by using the in-process mode:
export CACHE_TYPE=none
If the error persists, update SQLite and ensure Python links against it:
brew install sqlite3 && brew link --force sqlite3brew install python3 && /opt/homebrew/bin/python3 -c 'import sqlite3; print(sqlite3.sqlite_version)'
See the full migration guide's "SQLite Troubleshooting Guide" for deeper steps (WAL cleanup, integrity check, recovery): MIGRATION-0.7.0.md.
Diagnose the listener
Seeing - the IPv6 wildcard
socket (::) also accepts IPv4 traffic when
net.ipv6.bindv6only = 0 (default on Linux).
Why localhost fails on Windows
WSL 2's NAT layer rewrites only the IPv6 side of the dual-stack listener. From Windows, http://127.0.0.1:4444 (or Docker Desktop's "localhost") therefore times-out.
Fix (Podman rootless)
ss should now show 0.0.0.0:4444 instead of :::4444, and the
service becomes reachable from Windows and the LAN.
Fix (Docker Desktop > 4.19)
Docker Desktop adds a "WSL integration" switch per-distro. Turn it on for your distro, restart Docker Desktop, then restart the container:
Copy .env.example to .env first:
Then edit DATABASE_URL, JWT_SECRET_KEY, BASIC_AUTH_PASSWORD, etc.
Missing or empty required vars cause a fast-fail at startup.
Contributing
Fork the repo, create a feature branch.
Run
make lintand fix any issues.Keep
make testgreen and 100% coverage.Open a PR - describe your changes clearly.
See CONTRIBUTING.md for more details.
Changelog
A complete changelog can be found here: CHANGELOG.md
License
Licensed under the Apache License 2.0 - see LICENSE
Core Authors and Maintainers
Mihai Criveti - Distinguished Engineer, Agentic AI
Special thanks to our contributors for helping us improve ContextForge:
Star History and Project Activity
