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/logoutmcp-runtime registry status/info/provision/pushmcp-runtime server list/get/create/apply/deploy/delete/logs/status/policy inspectGET/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}/mcpAuthorization: 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/sessionsand/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_UPSTREAMselects runtime-api andANALYTICS_UPSTREAMselects 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/grantsGET/DELETE /api/v1/runtime/grants/{namespace}/{name}PATCH /api/v1/runtime/grants/{namespace}/{name}GET/POST /api/v1/runtime/sessionsGET/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/teamsGET /api/v1/runtime/teams/{slug}GET /api/v1/runtime/teams/{slug}/membersPUT /api/v1/runtime/teams/{slug}/members/{userID}DELETE /api/v1/runtime/teams/{slug}/members/{userID}POST /api/v1/usersGET /api/v1/runtime/namespacesGET /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:
/metricson 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.