MCP Gateway
The MCP Gateway exposes coreX Platform’s full API as MCP tools and brokers connections to external MCP servers. AI agents authenticate once and can call tools across all connected servers through a single endpoint, with policy enforcement, DLP, guardrails, rate limiting, and observability applied at the gateway.
Architecture
AI Agent (Claude, Cursor, custom)
│
│ MCP over Streamable HTTP
│ Authorization: Bearer <PAT or JWT>
▼
┌──────────────────────────────────────────────────────┐
│ mcp-gateway-rs (Rust, :8089) │
│ │
│ 1. Auth (PAT / JWT / OAuth) │
│ 2. Policy evaluation (allow/deny per expression) │
│ 3. Rate limiting (per-identity, per-IP, concurrent) │
│ 4. DLP (block/redact/tokenize sensitive data) │
│ 5. Guardrails (jailbreak/override/obfuscation) │
│ 6. Skills (inject skill guides into agent context) │
│ 7. Circuit breaker (per upstream server) │
│ 8. Tool namespace prefixing (server__tool) │
│ 9. Catalog aggregation (tools/resources/prompts) │
│ 10. Event logging (every JSON-RPC call) │
└──────────────────────┬───────────────────────────────┘
│
┌────────────┼──────────────┐
▼ ▼ ▼
┌────────────┐ ┌───────────┐ ┌───────────────────┐
│ mcp-server │ │ external │ │ external │
│ :8082 │ │ MCP srv 1 │ │ MCP srv 2 (stdio) │
│ (coreX │ │ (HTTP) │ │ (spawned locally) │
│ Manager) │ │ │ │ │
└────────────┘ └───────────┘ └───────────────────┘
The gateway runs as a separate container (mcp-gateway-rs, Rust). The mcp-server container (Python) exposes the coreX Platform backend API as 339+ MCP tools via in-process ASGI execution. External MCP servers are connected via HTTP (Streamable HTTP transport) or stdio (local subprocess spawned by the gateway).
Enabling the Gateway
- Set
MCP_GATEWAY_ENABLED=truein your environment (see Quick Start) - Set
MCP_SECRETS_KEYto a 32+ byte Fernet key (used to encrypt server auth secrets at rest) - Restart the stack — the
mcp-gateway-rsandmcp-servercontainers start automatically - Navigate to Management > MCP Gateway in the UI
When MCP_GATEWAY_ENABLED=true, MCP_SELF_REGISTER=true (default), and MCP_SECRETS_KEY is set, the backend automatically creates a “platform” team, registers the corex-manager MCP server, and publishes a skill guide. No manual setup is needed to start using the gateway with coreX Platform tools.
UI Tabs
The MCP Gateway page has 12 tabs:
| Tab | Description |
|---|---|
| Dashboard | Gateway live status, metrics, circuit breakers, catalog freshness, alerting config |
| Teams | Create and manage teams; assign users to teams |
| Servers | Register external MCP servers (HTTP or stdio); manage replicas, OAuth, catalogs |
| Marketplace | Search npm/PyPI for MCP server packages and install them |
| Identities | Create PATs and JWT identities; sync from Auth0 |
| Policies | Authorize/deny rules using the MCP expression language |
| DLP | Data loss prevention rules (block/redact/tokenize sensitive data) |
| Guardrails | Jailbreak, instruction override, and obfuscation detection |
| Skills | Publish versioned skill guides that agents can reference |
| Traffic | Live request inspection (see MCP Traffic) |
| Events | Audit log of every JSON-RPC call with filters |
| Settings | Gateway configuration (CORS, JWT, rate limits, config bundle) |
Teams
Teams are the top-level organizational unit. Servers, identities, policies, DLP rules, guardrails, and skills all belong to a team. Users are assigned to teams; a user can only see and manage resources in their teams (admins bypass this restriction).
- Create a team — admin only. Name and slug.
- Assign users — add users to a team via the Teams tab. Users in a team can view and (with write permission) manage that team’s resources.
Servers
Register external MCP servers that the gateway proxies. Each server belongs to a team and has a unique namespace (used to prefix tool names: namespace__tool_name).
Transport Types
| Transport | Description |
|---|---|
| Streamable HTTP | Connect to a remote MCP server over HTTP (MCP spec 2025-11-25). The server URL must be reachable from the gateway container. |
| stdio | Spawn a local subprocess (e.g. npx -y @modelcontextprotocol/server-filesystem). The gateway runs the command and communicates over stdin/stdout. Requires command and args fields. |
Server Fields
| Field | Description |
|---|---|
| Name | Unique identifier within the team |
| Display name | Human-friendly name shown in the UI |
| Namespace | Prefix for tool/resource/prompt names (e.g. github, filesystem) |
| URL | Server URL (HTTP transport only) |
| Enabled | Toggle to enable/disable the server |
| Verify TLS | Verify the server’s TLS certificate (HTTP transport) |
| Auth type | none, bearer (token in Authorization header), or basic (username/password) |
| Auth header | Custom header name for the auth secret (default: Authorization) |
| Auth secret | The token or password (encrypted at rest with MCP_SECRETS_KEY) |
| Timeout (ms) | Per-request timeout (default: 30000) |
| Max body bytes | Maximum response body size (default: 1048576) |
| Command | Executable to run (stdio transport only, e.g. npx) |
| Args | Command arguments (stdio transport only, e.g. -y @modelcontextprotocol/server-filesystem /data) |
| Env vars | Environment variables for the subprocess (stdio transport only) |
Replicas
For HTTP servers, you can add replica URLs for load balancing or failover. Replica URLs must have the same path as the primary URL. The gateway distributes requests across the primary and replicas.
OAuth
For servers that require OAuth 2.0 authentication, configure the OAuth client ID, client secret, scopes, and authorization server metadata URL. The gateway handles the OAuth flow:
- Configure OAuth credentials on the server
- Click Authorize — opens the authorization URL in a new tab
- Complete the consent flow
- The gateway stores the access token and refreshes it automatically
- Status badge shows
authorized,pending, orerror
Catalog Refresh
The gateway periodically fetches each server’s catalog (tools, resources, prompts). The Refresh Catalog button triggers an immediate refresh. The dashboard shows catalog freshness (tools/resources/prompts count and last fetch time).
Test Connection
The Test button sends an initialize JSON-RPC request to the server and reports the result. Use this to verify connectivity and authentication before enabling the server.
Marketplace
Search and install MCP server packages from npm and PyPI without leaving the UI.
- Navigate to Marketplace
- Select a package manager: npm or pypi
- Search for a package (e.g.
filesystem,github) - Click a result to view details (README, versions, install command)
- Click Install
- Choose a team, server name, and namespace
- The gateway installs the package and registers the server
- Configure any required env vars (discovered automatically from the package)
Installed packages show the package manager, source package name, and installed version on the Servers tab.
Identities
Identities authenticate AI agents to the gateway. Each identity belongs to a team.
Identity Kinds
| Kind | Description |
|---|---|
| PAT (Personal Access Token) | A long-lived token generated by the gateway. The agent sends it as Authorization: Bearer <token>. The token is shown once on creation — copy it immediately. The prefix is stored for identification. |
| JWT | A JWT issued by an external IdP. Configure the issuer, audience, and JWKS URL. The gateway validates the JWT signature against the JWKS. The JWT sub claim becomes the identity subject. |
Auth0 Sync
Sync identities from Auth0:
- Click Sync from Auth0
- Select a team
- Optionally enable Dry run to preview without creating identities
- Optionally enable Require verified email
- The gateway creates/updates JWT identities for each Auth0 user
Identity Fields
| Field | Description |
|---|---|
| Name | Unique identifier within the team |
| Subject | The JWT sub claim value (JWT kind) or PAT prefix (PAT kind) |
| Kind | pat or jwt |
| JWT issuer | Issuer URL (JWT kind) |
| JWT audience | Expected audience (JWT kind) |
| JWKS URL | URL to fetch signing keys (JWT kind) |
| Enabled | Toggle to enable/disable the identity |
| Expires at | Optional expiration timestamp |
| Last used | Updated on each authenticated request |
Policies
Policies authorize or deny JSON-RPC calls based on an expression language. Policies are evaluated in order; the first match wins. If no policy matches, the call is allowed (default allow).
Expression Language
The expression language supports:
- Fields:
mcp.method,mcp.server,mcp.tool,mcp.resource,mcp.prompt,mcp.identity,mcp.identity.kind,mcp.team,mcp.arg["path"],auth.claim.sub,auth.claim.iss,auth.claim.aud,auth.claim["key"],ip.src - Operators:
=,!=,~(regex match),in,not in,contains,and,or,not - Functions:
mcp.arg["path"]resolves JSONPath-lite on tools/call arguments
MCP Methods
| Method | Description |
|---|---|
initialize | Client initialization handshake |
notifications/initialized | Client initialized notification |
notifications/cancelled | Request cancellation |
notifications/progress | Progress notification |
tools/list | List available tools |
tools/call | Call a tool |
resources/list | List available resources |
resources/read | Read a resource |
prompts/list | List available prompts |
prompts/get | Get a prompt |
Policy Fields
| Field | Type | Description |
|---|---|---|
mcp.method | string | The JSON-RPC method (e.g. tools/call) |
mcp.server | string | The server namespace |
mcp.tool | string | The namespaced tool name (namespace__tool) |
mcp.resource | string | The wrapped resource URI |
mcp.prompt | string | The namespaced prompt name |
mcp.identity | string | The identity name (PAT) or JWT sub |
mcp.identity.kind | string | pat or jwt |
mcp.team | string | The team slug |
mcp.arg["path"] | string | JSONPath-lite access to tools/call arguments |
auth.claim.sub | string | JWT sub claim |
auth.claim.iss | string | JWT iss claim |
auth.claim.aud | string | JWT aud claim |
auth.claim["key"] | string | Arbitrary JWT claim |
ip.src | string | Client IP from X-Forwarded-For |
Actions
| Action | Description |
|---|---|
| allow | Allow the call to proceed |
| deny | Deny the call (returns error to the agent) |
Policy Options
| Option | Description |
|---|---|
| Log | Log the policy evaluation result to the events log |
| No log | Suppress logging for this policy |
Expression Templates
| Template | Expression | Action |
|---|---|---|
| Allow all | true | allow |
| Deny all | true | deny |
| Allow specific tool | mcp.method = "tools/call" and mcp.tool = "namespace__tool_name" | allow |
| Allow tool prefix | mcp.method = "tools/call" and mcp.tool ~ "^namespace__.*" | allow |
| Allow tool list by identity | mcp.identity = "grok-agent" and mcp.tool in ["ns__tool1", "ns__tool2"] | allow |
| Deny by identity | mcp.identity = "name" | deny |
| JWT subject check | auth.claim.sub = "subject-value" | allow |
| Server + method | mcp.server = "namespace" and mcp.method = "tools/call" | allow |
| Path traversal guard | mcp.arg["path"] contains ".." | deny |
Policy Builder
The UI includes a visual expression builder that provides dropdowns for servers, tools, identities, and methods (populated from the live catalog), so you don’t need to memorize field names.
DLP Rules
Data Loss Prevention rules inspect request and response payloads for sensitive data and take action when detected.
DLP Fields
| Field | Description |
|---|---|
| Name | Unique identifier within the team |
| Direction | both, request, or response — which payloads to inspect |
| Detector | email, ssn, credit_card, api_key, phone, or custom (regex) |
| Find regex | Custom regex pattern (when detector is custom) |
| Action | block, redact, or tokenize |
| Token prefix | Prefix for tokenized values (when action is tokenize) |
| Token TTL | Time-to-live for tokens (when action is tokenize) |
| Apply to | Which parts of the payload to scan (default: json_strings) |
DLP Actions
| Action | Description |
|---|---|
| block | Reject the request/response and return an error to the agent |
| redact | Replace matched values with [REDACTED] |
| tokenize | Replace matched values with a token; the original value is stored in Valkey for later detokenization |
Guardrails
Guardrails detect prompt injection, jailbreak attempts, instruction overrides, and obfuscation in agent inputs and outputs.
Guardrail Packs
| Pack | Description |
|---|---|
builtin:jailbreak_v1 | Detects common jailbreak patterns (e.g. “ignore previous instructions”) |
builtin:instruction_override | Detects attempts to override system instructions |
builtin:obfuscation | Detects obfuscated payloads (base64, unicode tricks, etc.) |
custom | Custom regex pattern |
Guardrail Fields
| Field | Description |
|---|---|
| Name | Unique identifier within the team |
| Direction | both, request, or response |
| Pack | Built-in pack or custom |
| Find regex | Custom regex (when pack is custom) |
| Action | block, redact, or log |
Skills
Skills are versioned markdown guides that agents can reference to understand how to use the gateway’s tools. A skill is published to make it available to agents.
Skill Fields
| Field | Description |
|---|---|
| Name | Unique identifier within the team |
| Description | Short description shown to agents |
| Tags | Comma-separated tags for categorization |
| Enabled | Toggle to enable/disable the skill |
| Enable when | Optional expression (same language as policies) that determines when the skill is injected into agent context |
Skill Versions
Skills are versioned. Each version has:
- Frontmatter — YAML metadata (title, description, tags)
- Body — Markdown content (the skill guide)
- Files — Optional attached files (filename: content, one per line)
Skill Lifecycle
- Create a skill with name and description
- Create a version — add frontmatter, body, and optional files
- Publish — publish the latest version to make it active
- Rollback — revert to a previous version if needed
Import from URL
Import a skill from a URL (e.g. a GitHub raw URL). The gateway fetches the content and creates a skill with an optional auto-publish.
Traffic Tab
The Traffic tab shows live MCP requests flowing through the gateway in real time. Each entry shows the JSON-RPC method, tool name, identity, server, status, and latency. This is useful for debugging agent interactions and understanding what tools agents are calling.
Events Tab
The Events tab is an audit log of every JSON-RPC call through the gateway. Each event records:
| Field | Description |
|---|---|
| Request ID | Unique ID for the request |
| Session ID | MCP session ID |
| Method | JSON-RPC method |
| Tool | Tool name (for tools/call) |
| Action | Gateway action taken (allow, deny, block, redact) |
| Identity | Authenticated identity name |
| Server | Target server namespace |
| Timestamp | When the event occurred |
Filters: by action, method, and free-text search on request ID/tool/method.
Dashboard Tab
The Dashboard tab provides real-time gateway health and metrics:
- Gateway status — reachable, configured, backend (rust/python)
- Counters — requests, tools called, tools listed, auth success/failure, policy denied, rate limited, DLP blocked, guardrail blocked, upstream errors
- Latency histogram — request latency distribution
- Active sessions — current MCP session count
- Open circuit breakers — servers with too many failures (auto-tripped)
- Catalog freshness — per-server tools/resources/prompts count and last fetch time
- Alert state — current alert thresholds and counts
- Server status — per-server health, transport type, last seen, last error
Alerting
Configure webhook alerts for gateway events:
| Event Type | Description |
|---|---|
guardrail_blocked | A guardrail blocked a request |
dlp_blocked | A DLP rule blocked a request |
policy_denied | A policy denied a request |
auth_failed | An authentication failure |
rate_limited | A rate limit was hit |
Set a threshold per event type (0 = disabled). When the count of events in the recent window exceeds the threshold, a webhook is sent to the configured URL (e.g. Slack incoming webhook). The alert history shows recent alerts and webhook delivery status.
Settings Tab
General
| Setting | Description |
|---|---|
mcp_allowed_origins | Comma-separated list of allowed CORS origins (e.g. https://claude.ai,https://cursor.sh) |
mcp_log_payloads | Log full request/response payloads in events (default: false — only metadata is logged) |
JWT Configuration
| Setting | Description |
|---|---|
mcp_jwt_issuer | Expected JWT issuer (for gateway-level JWT validation) |
mcp_jwt_audience | Expected JWT audience |
mcp_jwt_jwks_url | URL to fetch JWT signing keys |
Rate Limiting
| Setting | Default | Description |
|---|---|---|
mcp_default_rpm | 600 | Default requests-per-minute per identity |
mcp_per_ip_limit | 0 | Per-IP rate limit (0 = disabled) |
mcp_concurrent_limit | 0 | Maximum concurrent in-flight requests (0 = disabled) |
mcp_team_rpm_overrides | Per-team RPM overrides (JSON map of team_id → rpm) |
Config Bundle
The gateway config bundle is a JSON file containing all teams, servers, identities, policies, DLP rules, guardrails, and skills. It’s generated by the backend and written to the shared volume where the gateway reads it.
- Status — last generated timestamp and bundle size
- Regenerate — manually regenerate the bundle (also happens automatically on any config change)
Connecting an AI Agent
Example: Claude Desktop
Add the following to your Claude Desktop configuration:
{
"mcpServers": {
"corex": {
"url": "https://corex.example.com/mcp",
"headers": {
"Authorization": "Bearer <your-pat>"
}
}
}
}
Example: Custom MCP Client
from mcp import Client
client = Client(
url="https://corex.example.com/mcp",
headers={"Authorization": "Bearer <your-pat>"}
)
# List all tools across all servers
tools = await client.call_tool("tools/list", {})
# Call a coreX Manager tool (namespaced as corex-manager__)
listeners = await client.call_tool("corex-manager__list_listeners", {})
# Call an external server tool (namespaced as filesystem__)
result = await client.call_tool("filesystem__read_file", {"path": "/data/config.txt"})
Tool Namespacing
All tools are prefixed with their server’s namespace: namespace__tool_name. This prevents collisions when multiple servers expose tools with the same name. For example:
corex-manager__list_listeners— coreX Platform toolgithub__create_issue— GitHub MCP server toolfilesystem__read_file— Filesystem MCP server tool
Environment Variables
| Variable | Default | Description |
|---|---|---|
MCP_GATEWAY_ENABLED | false | Enable the MCP gateway and mcp-server containers |
MCP_SECRETS_KEY | (none) | 32+ byte Fernet key for encrypting server auth secrets. Required when gateway is enabled. |
MCP_SELF_REGISTER | true | Auto-register the coreX Manager MCP server into the gateway on startup |
MCP_SERVICE_TOKEN | (none) | Shared secret for rate-limit bypass on in-process MCP calls |
MCP_GATEWAY_BACKEND | rust | Gateway backend (rust or python) |
MCP_GATEWAY_RS_INTERNAL_HOST | mcp-gateway-rs | Rust gateway hostname |
MCP_GATEWAY_RS_INTERNAL_PORT | 8089 | Rust gateway port |
MCP_SERVER_INTERNAL_HOST | mcp-server | MCP server hostname |
MCP_SERVER_INTERNAL_PORT | 8082 | MCP server port |
COREX_MCP_TOKEN | (none) | Bearer token for direct mcp-server connections (bypasses gateway) |
Step-by-Step: Connect an AI Agent
-
Enable the gateway:
- Set
MCP_GATEWAY_ENABLED=trueandMCP_SECRETS_KEYin your environment - Restart the stack
- Set
-
Create a team:
- Navigate to Management > MCP Gateway > Teams
- Click Add Team
- Name:
my-team
-
Create an identity:
- Navigate to Identities
- Click Add Identity
- Name:
my-agent, Kind: PAT - Copy the generated token
-
Configure your AI agent:
- Add the MCP server URL and token to your agent’s configuration
- URL:
https://your-corex-domain/mcp - Header:
Authorization: Bearer <token>
-
Test the connection:
- Ask your AI agent to list tools
- Verify it can call
corex-manager__list_listenersand receive results
-
Add a policy (optional):
- Navigate to Policies
- Click Add Policy
- Expression:
mcp.method = "tools/call" and mcp.tool ~ "^corex-manager__list_.*" - Action: allow
- This restricts the agent to read-only coreX Manager tools
Step-by-Step: Connect an External MCP Server
-
Register the server:
- Navigate to Management > MCP Gateway > Servers
- Click Add Server
- Team: select your team
- Name:
github, Namespace:github - Transport: Streamable HTTP
- URL:
https://api.githubcopilot.com/mcp/ - Auth type: bearer, secret: your GitHub token
- Click Test to verify connectivity
- Click Save
-
Wait for catalog refresh:
- The gateway fetches the server’s catalog automatically
- Check the Dashboard tab for catalog freshness
-
Verify tools are available:
- Ask your AI agent to list tools
- Verify
github__*tools appear alongsidecorex-manager__*tools
Step-by-Step: Install from Marketplace
- Navigate to Management > MCP Gateway > Marketplace
- Package manager: npm
- Search:
filesystem - Click the
@modelcontextprotocol/server-filesystemresult - Review the details (README, versions)
- Click Install
- Team: select your team
- Name:
filesystem, Namespace:filesystem - The gateway installs the package and registers the server
- Configure env vars if prompted
- Verify
filesystem__*tools appear in the agent’s tool list
Verification
-
Check gateway health:
curl https://your-corex-domain/mcp/healthzExpect
{"status":"ok","configured":true}. -
Check OAuth metadata:
curl https://your-corex-domain/mcp/.well-known/oauth-protected-resourceExpect RFC 9728 metadata.
-
Test authentication:
curl -H "Authorization: Bearer <pat>" https://your-corex-domain/mcp/Expect a 200 or 406 (SSE listen not supported in v1).
-
Check the dashboard:
- Navigate to Management > MCP Gateway > Dashboard
- Verify the gateway is reachable and configured
- Verify metrics are incrementing as agents make calls
-
Check events:
- Navigate to Events
- Verify JSON-RPC calls are logged with method, tool, action, and identity
-
Check circuit breakers:
- If a server is failing, the dashboard shows open circuit breakers
- The gateway auto-trips after repeated failures and auto-resets after a cooldown
Next Steps
- Settings — Enable the
mcp_gateway_enabledfeature flag - Terraform Provider — Manage MCP gateway resources as code
- Architecture — MCP gateway architecture diagram
- Log Pipeline — Forward MCP events to external sinks