Skip to content

Request Flows

This page maps MCP Runtime use cases to the components and request paths they exercise. Use it when choosing PR E2E scenarios, designing pre-release regression coverage, or debugging a request that crosses service boundaries.

Flow Planes

Most use cases sit on one or more of these planes:

flowchart LR
    User["User, admin, CI, or agent"] --> Entry["CLI, browser, Docker, or MCP client"]
    Entry --> Control["Control plane\nplatform-api, runtime-api, UI, CLI, Kubernetes"]
    Entry --> Runtime["Runtime plane\nIngress, gateway, MCP server"]
    Entry --> Registry["Registry plane\nDocker registry and authz"]
    Control --> Policy["Policy plane\nMCPAccessGrant, platform sessions, rendered grant/tool ConfigMap"]
    Runtime --> Policy
    Runtime --> Analytics["Analytics plane\nIngest, Kafka, processor, ClickHouse"]
    Control --> Tenancy["Tenant plane\nusers, teams, namespaces, RBAC"]
    Registry --> Tenancy
    Analytics --> Control

The important rule is that the request path is broader than the URL. A runtime MCP request, for example, also exercises rendered policy, session state, audit emission, ingest, Kafka, processor, and analytics query paths.

Control Plane

Setup, server deployment, and server updates start in the CLI or the split API services and end when the operator reconciles Kubernetes resources. Only runtime-api talks to the Kubernetes API; platform-api authenticates the caller and owns identity state in Postgres.

sequenceDiagram
    participant User
    participant CLI as mcp-runtime CLI
    participant Platform as platform-api
    participant API as runtime-api
    participant K8s as Kubernetes API
    participant Operator
    participant Registry
    participant Runtime as MCP server workload

    User->>CLI: setup, bootstrap, server deploy, server push
    CLI->>Registry: build, tag, push, or mirror images
    CLI->>Platform: auth login, identity, registry credentials
    CLI->>API: platform-backed server/access/team requests
    API->>Platform: POST /internal/auth/resolve (service token)
    CLI->>K8s: --use-kube admin/dev/test requests
    API->>K8s: MCPServer, grants, Deployments, RBAC
    API->>Platform: persist sessions in Postgres
    K8s-->>Operator: watch MCPServer/grant changes
    Operator->>K8s: Deployment, Service, Ingress, policy ConfigMap, status
    K8s-->>Runtime: pods roll out with app container and optional gateway

Primary request paths:

  • mcp-runtime setup, bootstrap, cluster doctor, ops *
  • mcp-runtime auth login/status/logout
  • mcp-runtime registry status/info/provision/push
  • mcp-runtime server list/get/create/apply/deploy/delete/logs/status/policy inspect
  • GET/POST /api/v1/runtime/servers, GET/DELETE /api/v1/runtime/servers/{namespace}/{name}
  • GET/POST /api/v1/deployments, DELETE /api/v1/deployments/{namespace}/{name}

Runtime MCP Requests

MCP traffic should not bypass the gateway when governance is enabled. The gateway evaluates tool calls, forwards allowed requests, returns deny responses, and emits audit events.

sequenceDiagram
    participant Client as MCP client
    participant Ingress as Traefik / Ingress
    participant Gateway as mcp-gateway sidecar
    participant Policy as Rendered policy ConfigMap
    participant Server as MCP server
    participant Ingest
    participant Kafka
    participant Processor
    participant Store as ClickHouse

    Client->>Ingress: POST /{server}/mcp initialize
    Ingress->>Gateway: route to MCPServer Service
    Gateway->>Server: forward initialize
    Server-->>Gateway: MCP result
    Gateway-->>Client: initialize response with Mcp-Session-Id
    Client->>Ingress: POST /{server}/mcp tools/call
    Ingress->>Gateway: Request with verified identity when configured
    Gateway->>Policy: match identity, session, grant, trust, side effect, tool rule
    alt allowed
        Gateway->>Server: forward JSON-RPC request
        Server-->>Gateway: result
        Gateway-->>Client: 200 JSON-RPC result
    else denied
        Gateway-->>Client: 401/403 JSON error
    end
    Gateway->>Ingest: POST /events audit envelope
    Ingest->>Kafka: produce event
    Processor->>Kafka: consume event
    Processor->>Store: insert analytics row

Primary request paths:

  • /{server}/mcp
  • JSON-RPC methods: initialize, tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read
  • Optional OAuth bearer authentication; adapters always add a verified client certificate
  • Gateway health: /health

OAuth-protected MCP servers add:

  • /.well-known/oauth-protected-resource
  • /.well-known/oauth-protected-resource/{server}/mcp
  • Authorization: Bearer <token> validation through issuer metadata and JWKS

Adapter-Issued Certificates

Adapters enroll a session-bound certificate so local agents can use governed MCP routes without constructing identity headers.

sequenceDiagram
    participant Agent
    participant Adapter as local HTTP adapter proxy
    participant API as runtime-api
    participant Platform as platform-api / Postgres
    participant K8s as Kubernetes API
    participant Operator
    participant Traefik
    participant Gateway
    participant Server as MCP server

    Agent->>Adapter: Streamable HTTP MCP request
    Adapter->>API: POST /api/v1/runtime/adapter/sessions
    API->>Platform: create or reuse server-UID-bound session
    Platform-->>API: persisted session
    Gateway->>Platform: synchronize server-scoped session changes
    API-->>Adapter: session name and expiry
    Adapter->>Adapter: generate private key and session-bound CSR
    Adapter->>API: POST /api/v1/runtime/adapter/certificates
    API-->>Adapter: signed client certificate and CA bundle
    Adapter->>Traefik: forward MCP request with client certificate (+ bearer when OAuth is enabled)
    Traefik->>Gateway: verify certificate and inject trusted SPIFFE identity
    Gateway->>Gateway: resolve the SPIFFE identity against session and grant policy
    alt policy allows
        Gateway->>Server: Proxy the authorized MCP request
    else policy denies
        Gateway-->>Traefik: 401 or 403 with denial reason
        Traefik-->>Adapter: Error response
        Adapter-->>Agent: Error response
    end

Primary request paths:

  • mcp-runtime adapter proxy --server <name> --agent <id>
  • POST /api/v1/runtime/adapter/sessions and /certificates
  • Local adapter routes: /mcp, /healthz, /livez, /readyz, /metrics

UI And Platform API

The browser loads static assets from the UI service. Unmigrated /api/v1/* calls go through Traefik to the split API services and still require a bearer token or API key. Authenticated dashboard reads use the UI session BFF:

GET /api/ui/v1/* with the HttpOnly mcp_ui_session cookie, restricted to an explicit allowlist of runtime dashboard and analytics paths. The UI service injects the stored bearer token or upstream API key toward runtime-api or analytics-api and does not expose that credential to JavaScript. Mutating requests remain on the owning API ingress and are not accepted by the BFF.

sequenceDiagram
    participant Browser
    participant Ingress as Traefik
    participant UI as UI in mcp-platform
    participant Platform as mcp-platform-api
    participant Runtime as mcp-runtime-api
    participant DB as Postgres
    participant K8s as Kubernetes API
    participant Store as ClickHouse

    Browser->>Ingress: GET /
    Ingress->>UI: static app shell
    Browser->>Ingress: POST /auth/login
    Ingress->>UI: Login request
    UI->>Platform: POST /api/v1/auth/login
    Platform->>DB: Validate password and load identity
    Platform-->>UI: Platform credential
    UI-->>Browser: mcp_ui_session cookie
    Browser->>Ingress: GET /api/ui/v1/runtime/servers
    Ingress->>UI: session BFF
    UI->>Runtime: GET /api/v1/runtime/servers with session credential
    Runtime->>Platform: POST /internal/auth/resolve (service token)
    Platform->>DB: authenticate principal and team membership
    Runtime->>K8s: list MCPServer resources in allowed namespaces
    Runtime-->>UI: server list
    UI-->>Browser: server list
    Browser->>Ingress: GET /api/ui/v1/dashboard/summary
    Ingress->>UI: session BFF
    UI->>Runtime: dashboard summary with session credential
    Runtime->>K8s: grants, sessions, servers
    Runtime->>Store: analytics summary

Primary request paths:

  • UI: /, /config.js, /app.js, /styles.css, /health
  • UI auth: /auth/login, /auth/logout, /auth/status, /auth/admin-check
  • UI session BFF: allowlisted GET /api/ui/v1/* runtime dashboard/catalog and analytics reads; RUNTIME_UPSTREAM selects runtime-api and ANALYTICS_UPSTREAM selects analytics-api.
  • API auth: /api/v1/auth/login, /api/v1/auth/signup, /api/v1/auth/oidc, /api/v1/auth/me
  • Dashboard and analytics: /api/v1/dashboard/summary, /api/v1/events, /api/v1/stats, /api/v1/sources, /api/v1/event-types, /api/v1/analytics/usage, /api/v1/user/analytics/usage

Policy And Access Resources

Access resources are the bridge between platform intent and gateway enforcement.

sequenceDiagram
    participant Caller as UI, CLI, or API client
    participant API as runtime-api
    participant K8s as Kubernetes API
    participant Operator
    participant Policy as Mounted policy ConfigMap
    participant Gateway
    participant Client as MCP client

    Caller->>API: POST /api/v1/runtime/grants or /sessions
    API->>K8s: apply MCPAccessGrant or MCPAgentSession
    K8s-->>Operator: watch grant/session
    Operator->>K8s: write {server}-gateway-policy ConfigMap
    K8s-->>Policy: Project the ConfigMap into the pod
    Client->>Gateway: tools/call with ingress-verified identity when configured
    Gateway->>Policy: Read local policy snapshot
    Gateway-->>Client: allow, tool_not_granted, session_not_found, revoked, expired, trust denied

Primary request paths:

  • GET/POST /api/v1/runtime/grants
  • GET/DELETE /api/v1/runtime/grants/{namespace}/{name}
  • PATCH /api/v1/runtime/grants/{namespace}/{name}
  • GET/POST /api/v1/runtime/sessions
  • GET/DELETE /api/v1/runtime/sessions/{namespace}/{name}
  • PATCH /api/v1/runtime/sessions/{namespace}/{name}

Registry Publish And Pull

Registry requests enter through the registry Ingress. Traefik calls platform-api as a forward-auth service before the Docker registry receives the request.

sequenceDiagram
    participant Docker as docker or server push
    participant Ingress as registry Ingress
    participant Authz as /api/v1/registry/authz
    participant API as platform-api
    participant DB as Postgres
    participant Registry

    Docker->>Ingress: /v2/{scope}/{repo}/manifests/{tag}
    Ingress->>Authz: forwardAuth with original /v2 path
    Authz->>API: authenticate x-api-key or basic registry credential
    API->>DB: user, team, registry credential, publish scope
    alt authorized scope
        Authz-->>Ingress: 204
        Ingress->>Registry: proxy registry request
        Registry-->>Docker: pull or push response
    else unauthorized or forbidden
        Authz-->>Docker: 401 or 403
    end

Primary request paths:

  • Registry: /v2/, /v2/{scope}/{repo}/manifests/{tag}, /v2/{scope}/{repo}/blobs/*, /v2/{scope}/{repo}/tags/list
  • Authz: /api/v1/registry/authz
  • Credential lifecycle: GET/POST /api/v1/user/registry-credentials, DELETE /api/v1/user/registry-credentials/{id}
  • Publish audit: POST /api/v1/user/activity/image-publish

Teams And Namespaces

Tenant and team flows decide which namespaces a principal can read, publish to, or mutate.

sequenceDiagram
    participant Admin
    participant API as runtime-api
    participant Platform as platform-api
    participant DB as Postgres
    participant K8s as Kubernetes API
    participant Traefik
    participant User

    Admin->>API: POST /api/v1/runtime/teams
    API->>Platform: team and namespace record
    Platform->>DB: persist team and namespace
    API->>K8s: create namespace, RBAC, NetworkPolicy
    API->>Traefik: patch watched namespaces when bundled Traefik is used
    Admin->>Platform: POST /api/v1/users
    Platform->>DB: create password user
    Admin->>API: PUT /api/v1/runtime/teams/{slug}/members/{userID}
    API->>Platform: create membership
    Platform->>DB: persist membership
    User->>API: GET /api/v1/runtime/namespaces
    API-->>User: user, team, org, public, and shared catalog namespaces
    User->>API: GET /api/v1/runtime/servers?namespace=<allowed>
    API->>K8s: list namespace-scoped MCPServer resources

Primary request paths:

  • GET/POST /api/v1/runtime/teams
  • GET /api/v1/runtime/teams/{slug}
  • GET /api/v1/runtime/teams/{slug}/members
  • PUT /api/v1/runtime/teams/{slug}/members/{userID}
  • DELETE /api/v1/runtime/teams/{slug}/members/{userID}
  • POST /api/v1/users
  • GET /api/v1/runtime/namespaces
  • GET /api/v1/runtime/namespaces/{namespace}

Observability And Admin

Observability uses both direct service routes and platform-guarded public routes. The public /grafana path is protected by the UI admin check. Prometheus stays off the public ingress.

flowchart LR
    Browser["Browser or API client"] --> Ingress["Traefik / platform ingress"]
    Ingress --> Auth["UI admin check\n/auth/admin-check"]
    Auth --> Grafana["/grafana"]
    Gateway["mcp-gateway"] --> Ingest["ingest /events"]
    Ingest --> Kafka
    Kafka --> Processor
    Processor --> ClickHouse
    Analytics["analytics-api"] --> ClickHouse
    Platform["platform-api"] --> Admin["/api/v1/admin/*"]

Primary request paths:

  • Public observability: /grafana/*, /prometheus/*
  • Service metrics: /metrics on platform-api, runtime-api, analytics-api, ingest, processor, and adapter proxy
  • Ingest: GET /health, GET /live, GET /ready, POST /events
  • Processor: metrics server /health, /metrics
  • Admin: /api/v1/admin/namespaces, /api/v1/admin/audit, /api/v1/admin/operations, /api/v1/admin/deployments

Use Case Matrix

Use case Entry point Components crossed Primary contracts E2E scenario
Bootstrap/install platform mcp-runtime bootstrap, setup CLI, Docker, registry, K8s, Traefik, API, UI, operator, platform services manifests, setup plan, image refs, rollouts smoke-auth, all
Check platform health status, cluster doctor, service /health CLI, K8s, API/UI/ingest/processor/gateway health routes workload status, secrets, ingress, registry smoke-auth, observability
Log in to platform from CLI mcp-runtime auth login CLI, API, Postgres, authfile JWT/API token, platform URL cli-platform, api-platform
Browser login/logout UI /auth/* browser, UI, API key/session store mcp_ui_session, admin check ui-auth
Authenticated dashboard reads via UI session UI allowlisted GET /api/ui/v1/* browser, UI BFF, runtime-api/analytics-api session cookie translated to bearer or API key ui-auth
List visible servers CLI/API GET /api/v1/runtime/servers API, Postgres principal, K8s MCPServer list namespace scoping, public/org/team/user catalogs api-platform, multitenancy
Publish MCP server server deploy, POST /api/v1/runtime/servers CLI/API, registry, K8s, operator MCPServer spec, image scope, ingress path cli-platform, api-platform, all
Admin direct kube changes --use-kube CLI CLI, kubeconfig, Kubernetes API, operator CRDs and RBAC, no platform auth boundary targeted local/admin tests
Reconcile server workload MCPServer change K8s API, operator, Deployment, Service, Ingress, status CRD defaults, service target port, gateway sidecar smoke-auth, all
Render gateway policy grant/session/server change API/CLI, K8s CRs, operator, ConfigMap, gateway MCPAccessGrant, MCPAgentSession, policy JSON governance, trust
MCP initialize/list/call MCP client /{server}/mcp Ingress, Service, gateway sidecar, MCP server Streamable HTTP, JSON-RPC, MCP session header smoke-auth
Denied MCP call tools/call without matching policy gateway, policy evaluator, audit pipeline deny reasons such as tool_not_granted, session_not_found governance, trust
OAuth MCP call bearer token MCP route gateway, OIDC discovery/JWKS, policy, MCP server OAuth protected resource metadata, JWT claims oauth
Adapter proxy mcp-runtime adapter proxy local adapter, API, K8s session, operator, Traefik, gateway session-bound SPIFFE certificate, trusted ingress identity adapter-proxy
Create/update grants UI/CLI/API /api/v1/runtime/grants API, K8s, operator, gateway grant validation, subject/team binding governance, api-platform
Create/update sessions (admin) UI/CLI/API POST /api/v1/runtime/sessions API, K8s, operator, gateway admin role required for direct session apply governance, api-platform
Adapter-issued certificates adapter proxy, POST /api/v1/runtime/adapter/sessions and /certificates adapter, API, K8s, Traefik, gateway matching grant, session-bound SPIFFE identity adapter-proxy, governance
Revoke/disable access item action paths API, K8s, operator, gateway enable/disable/revoke/unrevoke governance, api-platform
Push or pull registry image Docker /v2/* registry ingress, Traefik forwardAuth, API, registry scope authz, registry credentials api-platform, all
Create registry credential /api/v1/user/registry-credentials API, Postgres, registry authz one-time credential, revoke flow api-platform
Create user API key /api/v1/user/api-keys API, Postgres, auth middleware one-time key, revoke flow api-platform
Create team namespace /api/v1/runtime/teams or team create API/CLI, Postgres, K8s namespace/RBAC, Traefik watch team slug, namespace, membership, RBAC multitenancy, api-platform
Manage team members/users /api/v1/runtime/teams/{slug}/* API, Postgres, namespace authorization membership and user records multitenancy, api-platform
Query analytics /api/v1/events*, /api/v1/analytics/usage API, ClickHouse, gateway/ingest history event envelope, filters, usage rows observability, api-platform
Direct ingest event POST /events ingest, auth, Kafka, processor, ClickHouse event envelope and API key auth observability
View Grafana/Prometheus /grafana/*, /prometheus/* ingress, UI admin-check, Grafana/Prometheus cookie/API-key admin forward auth ui-auth, observability
Admin audit/operations /api/v1/admin/* API, Postgres, K8s, audit store admin role checks, audit payloads api-platform
Pre-release regression manual workflow static checks, tests, security scans, Staging E2E on disposable k3s production setup, TLS, registry, tenant deployment and governed calls staging-e2e.yaml with multi-tenancy enabled

Coverage Guidance

For normal PRs, run the shortest scenario that crosses the changed request plane. If a change touches shared contracts, generated manifests, API auth, policy evaluation, or namespace scoping, prefer the broader scenario or let CI fall back to all.

For pre-release, run Pre-release Regression: Staging E2E is its only cluster suite. Staging currently uses org platform mode and exercises the production install and tenant journey. Use focused PR Kind scenarios for changed request paths. Run additional full Kind sweeps with E2E_SCENARIOS=all and E2E_DEEP_REQUEST_FLOWS=1 when org/public modes or cache reuse need explicit coverage; these sweeps are not automatic pre-release jobs.