A flexible and extensible proxy gateway for MCP (Model Context Protocol) servers, providing enterprise-grade middleware capabilities including authentication, authorization, rate limiting, and observability.
- Multiple Auth Providers: Okta OAuth2/JWT
- Role-Based Permissions: Fine-grained tool access control
- attribute-to-Role Mapping: Flexible user permission assignment
- JWT Token Verification: Secure token validation
- Multiple Storage Backends: Memory (dev), PostgreSQL
- RESTful Admin API: Dynamic configuration management
- Prometheus Metrics: Built-in observability
- Structured Logging: JSON and text output formats
- Health Endpoints: Container orchestration support
- YAML Configuration: Environment variable substitution
- CLI Flags: Override any configuration option
- Hot Configuration: Runtime proxy/role management via API
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β AI Client βββββΆβ MCP Gateway βββββΆβ MCP Server β
β (Claude, etc.) β β β β (n8n, etc.) β
βββββββββββββββββββ β βββββββββββββ β βββββββββββββββββββ
β β β β
β βOkta Auth β β βββββββββββββββββββ
β β Roles β βββββΆβ Another Server β
β β Metrics β β βββββββββββββββββββ
β βββββββββββββ β
βββββββββββββββββββ
# Clone and run without authentication
git clone https://github.com/matthisholleville/mcp-gateway.git
cd mcp-gateway
# Run without authentication
go run main.go serve \
--log-format=text \
--log-level=debug # Pull the latest image
docker pull ghcr.io/matthisholleville/mcp-gateway:latest
# Run with environment variables
docker run -p 8082:8082 \
ghcr.io/matthisholleville/mcp-gateway:latest serve# Start PostgreSQL
docker-compose up -d postgres
# Run migrations
go run main.go migrate up \
--backend-engine=postgres \
--backend-uri='postgresql://mcp-gateway:changeme@localhost:5439/mcp-gateway?sslmode=disable'
# Start server with PostgreSQL backend
go run main.go serve \
--log-format=text \
--log-level=debug \
--backend-engine=postgres \
--backend-uri='postgresql://mcp-gateway:changeme@localhost:5439/mcp-gateway?sslmode=disable' \
--backend-encryption-key=0123456789abcdeffedcba9876543210cafebabefacefeeddeadbeef00112233helm repo add mcp-gateway https://matthisholleville.github.io/mcp-gateway
helm install mcp-gateway mcp-gateway/mcp-gateway- CLI Flags (highest priority)
- Environment Variables (
MCP_GATEWAY_*) - YAML Configuration File (
config/config.yaml) - Default Values (lowest priority)
# config/config.yaml
server:
url: "http://localhost:8082"
# Authentication
authProvider:
enabled: true
name: "okta"
okta:
issuer: "https://custom-xxx.okta.com/oauth2/default"
orgUrl: "https://custom-xxx.okta.com"
clientId: "xxx"
privateKey: "-----BEGIN PRIVATE KEY-----xxx-----END PRIVATE KEY-----"
privateKeyId: "xxx"
oauth:
enabled: true
provider: "okta"
authorizationServers:
- "https://custom-xxx.okta.com/oauth2/default"
bearerMethodsSupported: ["Bearer"]
scopesSupported: ["openid", "email", "profile"]
# Storage backend
backendConfig:
engine: "memory" # "postgres" coming soon
# uri: "postgres://user:pass@localhost/mcp_gateway"
# Proxy configuration
proxy:
cacheTTL: 300s
heartbeat:
enabled: true
intervalSeconds: 10sAll configuration options can be set via environment variables with MCP_GATEWAY_ prefix:
export MCP_GATEWAY_AUTH_PROVIDER_ENABLED=true
export MCP_GATEWAY_OAUTH_ENABLED=truego run main.go serve \
--auth-provider-name=okta \
--okta-issuer=https://your-domain.okta.com/oauth2/default \
--okta-org-url=https://your-domain.okta.com \
--okta-client-id=your-client-id
--okta-private-key="-----BEGIN RSA PRIVATE KEY-----\n..."
--okta-private-key-id="akXpH7Ha5VKCe2kNT3eCPn_YRaJ0..."- Usage: Development and testing
- Persistence: None (data lost on restart)
- Configuration:
--backend-engine=memory
- Usage: Production environments
- Persistence: Full durability
- Configuration:
--backend-engine=postgres --backend-uri=postgres://...
You can update the admin API Key with --http-admin-api-key flag
The gateway provides RESTful APIs for runtime configuration management:
Swagger is available at http://localhost:8082/swagger/index.html
# List all proxies
curl -H "X-API-Key: your-api-key" http://localhost:8082/v1/admin/proxies
# Add/Update proxy
curl -X PUT -H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"name":"n8n","type":"streamable-http","connection":{"url":"http://n8n:5678"}}' \
http://localhost:8082/v1/admin/proxies/n8nobjectTypecan be*ortoolsobjectNameis the tool name ifobjectTypeistools. Can be*or your object nameproxyis the proxy name. Can be*or your proxy name
# Create role
curl -X PUT -H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"name":"admin","permissions":[{"objectType":"*","proxy":"*","objectName":"*"}]}' \
http://localhost:8082/v1/admin/rolesattributeKeyis the key in your JWTattributesattributeValueis the attribute valuerolesis the list of roles. You must create the roles before creating the attribute-to-role mapping
# Map user attributes to roles
curl -X PUT -H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"attributeKey":"groups","attributeValue":"admins","roles":["admin"]}' \
http://localhost:8082/v1/admin/attribute-to-roles| Endpoint | Method | Description |
|---|---|---|
/mcp |
POST | MCP protocol endpoint |
/live |
GET | Liveness probe |
/ready |
GET | Readiness probe |
/metrics |
GET | Prometheus metrics |
/swagger/* |
GET | API Documentation |
/v1/admin/proxies |
GET, PUT, DELETE | Proxy management |
/v1/admin/roles |
GET, PUT, DELETE | Role management |
/v1/admin/attribute-to-roles |
GET, PUT, DELETE | attribute mapping |
- Go 1.24.3+
- Docker (optional)
- Make
# Install dependencies
make deps
# Run in development
make dev
# Build binary
make build
# Run tests
make test
# Generate coverage
make test-cover
# Build Docker image
make docker-buildThe gateway searches for config.yaml in:
/etc/mcp-gateway/$HOME/.mcp-gateway/./config/
--log-format # text, json
--log-level # debug, info, warn, error
--log-timestamp-format # Format for logging timestamps
--auth-provider-enabled # Enable authentication
--auth-provider-name # okta
--oauth-enabled # Enable OAuth2
--backend-engine # memory, postgres
--http-addr # Server address (default: :8082)
--http-admin-api-key # Admin API key for MCP Gateway configuration--proxy-cache-ttl # TTL for the proxy cache
--proxy-heartbeat-interval # Interval for the proxy heartbeat--backend-uri # URI for the auth backend
--backend-username # The username to use for the auth backend. It will override the username in the URI if provided.
--backend-password # The password to use for the auth backend. It will override the password in the URI if provided.
--backend-max-open-conns # Maximum number of open database connections
--backend-max-idle-conns # Maximum number of idle connections in pool
--backend-conn-max-idle-time # Maximum time a connection may be idle
--backend-conn-max-lifetime # Maximum time a connection may be reused--oauth-authorization-servers # OAuth authorization servers
--oauth-resource # OAuth resource (e.g. http://localhost:8082)
--oauth-bearer-methods-supported # Bearer methods supported for OAuth
--oauth-scopes-supported # OAuth scopes supported (e.g. openid,email,profile)--okta-issuer # Okta authorization server
--okta-org-url # Okta organization URL
--okta-client-id # Okta client ID
--okta-private-key # Private key for client auth
--okta-private-key-id # Private key IDWe welcome contributions! Please see CONTRIBUTING.md for guidelines.
Licensed under the Apache License 2.0 - see LICENSE for details.
Made with β€οΈ by Matthis Holleville