coreX MCP Server

The mcp-server container is a standalone MCP (Model Context Protocol) server that exposes the full coreX Platform backend REST API as MCP tools. It speaks MCP spec 2025-11-25 over Streamable HTTP, so any MCP-compatible AI agent (Devin, Claude Code, Cursor, Windsurf, Continue, or a custom client) can connect and manage the platform.

The server auto-discovers tools by introspecting the backend FastAPI app’s routes — one MCP tool per API endpoint. Tools are executed in-process via an ASGI transport with a service admin JWT, so all route logic, validation, audit middleware, and rate limiting run exactly as they would for a normal HTTP request.

  AI Agent

     │  MCP over Streamable HTTP (POST /mcp)
     │  Authorization: Bearer <COREX_MCP_TOKEN>  (optional)

  ┌───────────────────────────────────────────────────┐
  │  mcp-server  (Python, :8082)                      │
  │                                                   │
  │  JSON-RPC dispatch:                               │
  │  ├── initialize / ping                            │
  │  ├── tools/list  → discover_tools()               │
  │  ├── tools/call  → call_tool() → ASGI transport   │
  │  ├── resources/list  → 7 curated resources        │
  │  ├── resources/read → ASGI transport              │
  │  ├── prompts/list   → 6 workflow prompts          │
  │  └── prompts/get    → render prompt template      │
  │                                                   │
  │  GET /healthz         → liveness                  │
  │  GET /.well-known/oauth-protected-resource        │
  └──────────────────────┬────────────────────────────┘
                         │ httpx ASGITransport (in-process)
                         │ Authorization: Bearer <service admin JWT>
                         │ X-MCP-Service-Token: <MCP_SERVICE_TOKEN> (rate-limit bypass)

  ┌───────────────────────────────────────────────────┐
  │  backend (FastAPI app)                            │
  │  All v1 routes run exactly as a normal HTTP call: │
  │  auth, validation, audit, rate limit, config gen  │
  └───────────────────────────────────────────────────┘

Why a Separate Server?

The MCP server is a thin adapter that wraps the existing REST API. It doesn’t reimplement any business logic — it maps JSON-RPC calls to in-process HTTP requests against the backend. This means:

  • No duplicated logic — every tool call hits the real backend with full validation, audit logging, and middleware
  • Automatic coverage — new backend endpoints appear as MCP tools automatically (no manual tool definitions)
  • Full API access — all 339+ v1 endpoints are exposed (minus file-upload endpoints, which can’t be represented as JSON)

Tool Discovery

Tools are auto-generated at startup by tools.discover_tools(), which introspects app.main:app.routes:

  1. Walk all routes — recursively walks the FastAPI app’s route tree, handling _IncludedRouter wrappers (FastAPI 0.141+ sub-routers)
  2. Skip non-API routes — excludes /openapi.json, /docs, /redoc, /healthz, static mounts, and HEAD/OPTIONS methods
  3. Generate one tool per method — each APIRoute + HTTP method becomes a tool
  4. Derive tool name — from the endpoint function name, stripping _endpoint/_route suffixes. If the same name appears for different routes, the HTTP method is appended (e.g. list_backends_get, list_backends_post)
  5. Build input schema — from the route’s dependant:
    • Path params → required string properties
    • Query params → typed properties (type inferred from default value; PydanticUndefinedType sentinel treated as no default)
    • Body params → a body property with a JSON Schema from the Pydantic model’s model_json_schema() (sanitized via json.dumps(default=str) to coerce non-serializable objects)
  6. Skip file uploads — endpoints with UploadFile body params are skipped (can’t be represented as JSON)

The tool list is cached after first discovery and pre-warmed at startup so the first tools/list is fast.

339+ tools

The current backend exposes 339+ MCP tools. The exact count changes as new endpoints are added — call tools/list to see the current set.

Tool Execution

When an agent calls tools/call, the server:

  1. Looks up the tool by name in the cached list
  2. Substitutes path params — replaces {param} placeholders in the URL path with values from the arguments
  3. Collects query params — from arguments (excluding path params and body)
  4. Extracts body — from the body argument if the tool has a body param
  5. Sets headers:
    • Authorization: Bearer <service admin JWT> — a 24-hour admin JWT minted via create_access_token({"sub": "admin"}), cached for 20 hours
    • X-MCP-Service-Token: <MCP_SERVICE_TOKEN> — if set, bypasses per-user rate limits (see below)
  6. Executes in-process — via httpx.AsyncClient(transport=httpx.ASGITransport(app=app)) with a 60-second timeout
  7. Returns the result — JSON responses are pretty-printed; non-JSON responses are returned as text. Errors (HTTP >= 400) are prefixed with the status code and flagged with isError: true

Rate-Limit Bypass

In-process MCP calls would be rate-limited like any other API request, which is problematic for agents making many rapid tool calls. To avoid this:

  • Set MCP_SERVICE_TOKEN to a shared secret
  • The MCP server sends it as the X-MCP-Service-Token header on every tool call
  • The backend’s rate_limit() dependency checks this header and bypasses per-user limits when it matches
  • The backend’s get_current_user() dependency also skips the Valkey token-revocation check for service calls (the service admin JWT is never revoked) and uses a cached user lookup to avoid a per-request DB query

Resources

The server exposes 7 curated read-only MCP resources, each mapping to a backend GET endpoint. Resources are fetched in-process via the same ASGI transport as tools.

URINameDescriptionBackend Path
corex://config/previewconfig-previewPreview the generated HAProxy config without applying it/api/v1/config/preview
corex://config/statusconfig-statusCurrent config apply status (applied vs pending changes)/api/v1/config/status
corex://config/snapshotsconfig-snapshotsList of config snapshots (applied config history)/api/v1/config/snapshots
corex://system/statssystem-statsSystem stats (HAProxy process info, uptime, connections)/api/v1/stats
corex://system/haproxy-statshaproxy-statsHAProxy stats (frontend/backend/server metrics)/api/v1/haproxy-stats
corex://audit-eventsaudit-eventsRecent audit events (config mutations, auth events)/api/v1/audit-events
corex://healthhealthBackend health check/api/v1/health

Resources are read-only — agents can fetch them via resources/read but cannot modify them. Use tools for mutations.

Prompts

The server exposes 6 MCP prompts. The primary prompt is corex-manager-guide, which returns the full operating guide. The other 5 are workflow-specific prompts that guide an agent through common tasks.

PromptDescriptionArguments
corex-manager-guideFull operating guide for coreX Manager via MCP toolsnone
diagnose-trafficDiagnose traffic or routing issuessymptom (required)
security-reviewReview the current security configurationnone
add-backendGuided workflow to add a new backend pool with serversname (required), servers (required)
waf-investigationInvestigate WAF events and tune rulesconcern (optional)
apply-and-verifyApply pending config changes and verify the resultcomment (optional)

corex-manager-guide

The corex-manager-guide prompt is the primary skill-delivery mechanism. Any MCP-compatible client can fetch it via prompts/get and inject the operating instructions into its conversation, making the skill fully agent-agnostic. The guide covers:

  • Tool naming (bare names for direct connections, corex-manager__ prefix via the gateway)
  • Key workflows (inspect state, make changes, WAF/security, rollback)
  • Safety rules (confirm before destructive ops, always apply config, check dependencies)
  • Available resources and other prompts

The guide content is mirrored in:

  • .devin/skills/corex-manager/SKILL.md — for Devin CLI auto-discovery
  • docs/mcp-skill.md — portable guide with install snippets for Claude Code, Cursor, Windsurf, Continue, and generic MCP clients

Authentication

The MCP server supports optional bearer token authentication:

  • If COREX_MCP_TOKEN is set, direct connections must include Authorization: Bearer <token>
  • If unset, the endpoint is open (the gateway is the gatekeeper when used via the gateway)
Direct vs gateway connections

When connecting directly to the MCP server (:8082/mcp), set COREX_MCP_TOKEN to require authentication. When connecting via the gateway (:8089/mcp), the gateway handles authentication (PAT/JWT) and forwards calls to the MCP server with its own service token — COREX_MCP_TOKEN is not used in this path.

Self-Registration

When the MCP gateway is enabled, the backend automatically registers the MCP server into the gateway’s database on startup. This is handled by ensure_self_registration() in backend/app/services/mcp_self_register.py, called from the main.py lifespan.

Prerequisites

Self-registration runs only when all three conditions are met:

ConditionSettingDefault
Gateway enabledMCP_GATEWAY_ENABLEDfalse
Self-registration enabledMCP_SELF_REGISTERtrue
Secrets key configuredMCP_SECRETS_KEY(none)

If MCP_SECRETS_KEY is not set, self-registration is skipped with a warning (the gateway needs it to encrypt the server’s auth secret).

Registration Steps

The registration is idempotent — it runs on every startup and only creates/updates what’s missing or changed:

  1. Ensure “platform” team — creates a Team with slug platform if it doesn’t exist
  2. Ensure McpServer row — creates an McpServer with:
    • Namespace: corex-manager
    • URL: http://<MCP_SERVER_INTERNAL_HOST>:<MCP_SERVER_INTERNAL_PORT>/mcp (e.g. http://mcp-server:8082/mcp)
    • Transport: streamable_http
    • Auth type: bearer (header: Authorization)
    • Auth secret: COREX_MCP_TOKEN env var, or a randomly generated 32-byte token
    • Timeout: 60000ms, max body: 10MB
    • Enabled: true
    • If the server already exists, it updates the URL and auth secret if they’ve changed (e.g. if COREX_MCP_TOKEN was rotated)
  3. Ensure McpSkill + published version — creates an McpSkill named corex-manager with:
    • Tags: haproxy, waf, load-balancer, corex
    • A published McpSkillVersion containing the skill guide (frontmatter + body)
    • A new version is created only if the content has changed (compared by body text and frontmatter)
  4. Regenerate config bundle — calls write_config_bundle(db) so the gateway picks up the new server and skill
  5. Trigger catalog refresh — calls trigger_background_catalog_refresh([server.id]) with retries every 5 seconds for up to 1 minute (the mcp-server may still be starting when the control plane first tries; this avoids waiting for the gateway’s 60-second refresh cycle)

What This Means for Users

After enabling the gateway for the first time:

  • A “platform” team appears in Management > MCP Gateway > Teams
  • The corex-manager server appears in Servers with a healthy catalog
  • The corex-manager skill appears in Skills (published)
  • Agents connecting via the gateway can immediately call corex-manager__* tools
  • The corex-manager-guide prompt is available via prompts/get

No manual server registration is needed for the coreX Platform’s own tools.

Disabling Self-Registration

To disable self-registration (e.g. in a multi-instance deployment where only one instance should register):

MCP_SELF_REGISTER=false

The previously-registered server and skill remain in the database; only the automatic registration/update is skipped.

Environment Variables

VariableDefaultDescription
COREX_MCP_TOKEN(none)Bearer token for direct connections. If set, direct clients must include Authorization: Bearer <token>. If unset, the endpoint is open. Also used as the auth secret when self-registering into the gateway.
MCP_SERVICE_TOKEN(none)Shared secret for rate-limit bypass on in-process MCP calls. Sent as X-MCP-Service-Token header.
MCP_SELF_REGISTERtrueAuto-register the coreX Manager MCP server into the gateway on startup
MCP_SERVER_INTERNAL_HOSTmcp-serverHostname the backend uses to reach the MCP server (for self-registration URL)
MCP_SERVER_INTERNAL_PORT8082Port the backend uses to reach the MCP server

Deployment

The MCP server runs as a separate container in the stack:

  • Image: built from mcp-server/Dockerfile (Python 3.14-slim)
  • Port: 8082
  • Dependencies: postgres, valkey, api (the backend must be running for tool discovery)
  • Volumes: mounts backend/app/ at runtime (shares the same code as the api container for in-process imports) and the haproxy-data volume (read-only access to config files)
  • PYTHONPATH: /app (so from app... and from shared... work)
  • Command: uvicorn server:app --host 0.0.0.0 --port 8082

On Kubernetes, the MCP server runs as a sidecar in the same pod as the API and HAProxy, communicating over localhost.

Connecting Directly (Without the Gateway)

You can connect an AI agent directly to the MCP server, bypassing the gateway. This skips policy enforcement, DLP, guardrails, and rate limiting, but is simpler for single-agent setups.

Devin CLI

devin mcp add corex-manager http://localhost:8082/mcp

The skill file at .devin/skills/corex-manager/SKILL.md is auto-discovered by Devin CLI. Invoke with /corex-manager [task].

Claude Code

claude mcp add corex-manager http://localhost:8082/mcp

To load the skill guidance, call prompts/get with corex-manager-guide, or copy the operating guide from docs/mcp-skill.md into .claude/commands/corex-manager.md.

Cursor

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "corex-manager": {
      "url": "http://localhost:8082/mcp"
    }
  }
}

Paste the operating guide from docs/mcp-skill.md into .cursor/rules/corex-manager.mdc.

Windsurf

windsurf mcp add corex-manager http://localhost:8082/mcp

Continue / Generic MCP Client

Connect to http://localhost:8082/mcp. To load the skill guidance, call prompts/get with corex-manager-guide.

With Authentication

If COREX_MCP_TOKEN is set, include it in the connection:

{
  "mcpServers": {
    "corex-manager": {
      "url": "http://localhost:8082/mcp",
      "headers": {
        "Authorization": "Bearer <your-corex-mcp-token>"
      }
    }
  }
}

Connecting Via the Gateway

When connecting through the gateway (http://localhost:8089/mcp):

  • Tools appear with the corex-manager__ prefix (e.g. corex-manager__list_backends)
  • The skill appears as the corex-manager prompt
  • The gateway applies policies, DLP, guardrails, and rate limiting
  • Authentication is via PAT or JWT (see MCP Gateway > Identities)

See MCP Gateway for the full gateway documentation.

Verification

  1. Check the server is running:

    curl http://localhost:8082/healthz

    Expect: {"status":"ok","server":"corex-manager","version":"1.0.0"}

  2. Check OAuth metadata:

    curl http://localhost:8082/.well-known/oauth-protected-resource

    Expect: RFC 9728 metadata with the resource URL.

  3. List tools:

    curl -X POST http://localhost:8082/mcp \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

    Expect: a JSON-RPC response with 339+ tools.

  4. Call a tool:

    curl -X POST http://localhost:8082/mcp \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_listeners","arguments":{}}}'

    Expect: a JSON-RPC response with the listener list.

  5. Read a resource:

    curl -X POST http://localhost:8082/mcp \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"corex://config/status"}}'

    Expect: a JSON-RPC response with the config status.

  6. Get the skill guide:

    curl -X POST http://localhost:8082/mcp \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc":"2.0","id":4,"method":"prompts/get","params":{"name":"corex-manager-guide"}}'

    Expect: a JSON-RPC response with the full operating guide.

  7. Verify self-registration (gateway enabled):

    • Navigate to Management > MCP Gateway > Servers
    • Verify the corex-manager server appears with a healthy catalog
    • Navigate to Skills
    • Verify the corex-manager skill is published

Next Steps

  • MCP Gateway — Gateway with policies, DLP, guardrails, and multi-server support
  • Settings — Enable the mcp_gateway_enabled feature flag
  • Architecture — MCP gateway architecture diagram
  • Quick Start — MCP environment variables