Runtime¶
MCP Runtime turns a server description into a running deployment, gives it a route clients can reach, and updates it when the description changes. This page explains the Kubernetes resources it creates and the settings used to operate them. See Services and Observability for tool call handling and audit data.
The runtime runs on top of your ingress and networking layer and handles MCP-specific delivery, access, and rollout. It does not route general cluster traffic.
What the runtime owns¶
| Area | Responsibility |
|---|---|
| Bootstrap | cluster and setup initialize CRDs and namespaces, configure ingress, provision clusters, optionally wire cert-manager TLS. |
| Registry workflow | Registry commands and setup wiring provide a place to publish and pull MCP server images. |
| Server delivery | The operator reconciles MCPServer into Deployments, Services, and Ingress. Each server gets a stable route. |
| Access and consent | Grants and sessions are separate resources. They hold policy, side-effect allowances, trust ceilings, consent, expiry, and revocation, apart from the deployment YAML. |
| Brokered rollout | Servers run direct or behind the proxy sidecar. Rollout settings live on the same server resource. |
Core resources¶
MCPServer and MCPAccessGrant are declarative Kubernetes resources.
Sessions are platform-owned Postgres records; MCPAgentSession YAML remains
the CLI input format, while legacy Kubernetes session objects are not consulted.
Many grants and sessions can reference one MCPServer. With allow-list policy,
the gateway evaluates the matching grant and, when session.required: true,
the session on each tool call. Observe mode records calls without enforcing
those checks.
See the API reference for full field definitions and examples.
Reconciliation outputs¶
For every MCPServer, the operator reconciles:
- Deployment: image, replicas, resource requests/limits, env, image-pull secrets.
- Service: ClusterIP exposing
spec.servicePort→spec.port. - Ingress: routes
spec.publicPathPrefixas/<prefix>/mcp, or explicitspec.ingressHost+spec.ingressPath, to the Service with per-class annotations (Traefik / NGINX / Istio). - Policy ConfigMap: rendered from matching
MCPAccessGrantresources and tool metadata, consumed by the gateway sidecar whengateway.enabled. Sessions arrive through the platform sync API and are never embedded.
MCPServer.status exposes:
phase:Pending→PartiallyReady→Ready.message: human-readable progress.conditions: standard Kubernetes condition slice.- Per-resource readiness booleans:
deploymentReady,serviceReady,ingressReady,gatewayReady,policyReady, andcanaryReadywhen a canary rollout is configured. ingressReadydefaults to strict mode: the Ingress must publishstatus.loadBalancer.ingress[]. For dev or NodePort-style ingress controllers that route traffic without publishing load-balancer status, set operator envMCP_INGRESS_READINESS_MODE=permissive. Permissive mode treats an Ingress with rules as ready.
Useful defaults¶
- Servers default to
/{server-name}/mcp; setspec.publicPathPrefixto choose the public path prefix explicitly. - Hostless path-based routing is supported through
spec.publicPathPrefix; otherwise providespec.ingressHostor configure the operator default host. - Container port defaults to
8088, service port to80. - Gateway listens on
8091. setupprovisionsmcp-runtimeandmcp-servers-orgin defaultorgmode; public mode also provisionsmcp-servers-public.tenantpublish scope uses team namespaces for the principal's team memberships in either mode. Place runtime CRDs in per-team namespaces and rely on Kubernetes RBAC and ingress watch configuration for isolation.- Default ingress class is
traefik; override viaspec.ingressClass. - Gateway defaults to enabled; set
spec.gateway.enabled: falseto route directly to the MCP application.
Topology¶
flowchart TB
Dev[Developer / CI] --> CLI[mcp-runtime CLI]
CLI --> CRD[v1alpha1 surface<br/>MCPServer / MCPAccessGrant / MCPAgentSession]
CRD --> Op[Operator + Registry + Ingress]
Op --> K8s[Deployments / Services / Ingress]
K8s -->|gateway disabled| Direct["/{server-name}/mcp → MCP server"]
K8s -->|gateway enabled| Gateway[mcp-gateway sidecar]
Gateway --> MCP[MCP server]
Gateway --> Stack[Services Stack<br/>ingest / processor / API / UI / observability]
Install and delivery flow¶
flowchart LR
A[01. Prepare an existing cluster<br/>bootstrap, cluster doctor] --> B[02. Configure and install<br/>registry, DNS, TLS, setup]
B --> C[03. Log in and describe a server<br/>auth login, server init, server validate]
C --> D[04. Publish and deploy<br/>server build image, push, deploy]
D --> E[05. Grant access<br/>grant init/apply; adapter sessions]
E --> F[06. Observe<br/>status, UI, API]
| Step | Commands |
|---|---|
| Prepare cluster | Choose or provision the target, then bootstrap and cluster doctor |
| Configure and install | Select registry, ingress, DNS, and TLS; run configured setup |
| Describe servers | server init, hand-written MCPServer YAML, or metadata in .mcp/ |
| Publish + deploy | auth login, server build image, server push, server deploy, server generate for GitOps YAML |
| Grant access | auth login, access grant init, access grant apply; sessions via adapter proxy --server … --agent … or admin access session init/apply |
| Observe | status, platform UI/API; admin: ops status, ops port-forward ui |
Traffic and enforcement model¶
| Mode | Behavior |
|---|---|
| Direct | spec.gateway.enabled: false. Service points at the MCP server directly. Server is exposed at /{server-name}/mcp. |
| Gateway | spec.gateway.enabled: true. Traffic flows through the proxy sidecar, which handles identity, policy, audit, and telemetry. |
| Trust evaluation | At tool-call time, effective trust is min(grant.maxTrust, session.consentedTrust) and must meet the required trust, which is the higher of the tool's requiredTrust and the matching tool rule's requiredTrust. |
| Side-effect evaluation | Each listed tool must declare sideEffect: read, write, or destructive. A grant authorizes only tools whose side effect is in allowedSideEffects. Omitted or empty allowedSideEffects allows no side-effect classes. A tool the server never declared is denied, because it has no side effect to authorize. |
| Observe mode | policy.mode: observe allows the call before identity, session, grant, side-effect, and trust checks run. Requests are still proxied and audited, but nothing is enforced. |
Gateway policy snapshots¶
The operator renders MCPServer + MCPAccessGrant state
into a JSON policy ConfigMap that the gateway sidecar mounts and reloads. The
rendered document carries this metadata, separate from the authorization
policyVersion:
| Field | Meaning |
|---|---|
schema_version |
Compatibility of the rendered JSON contract. The gateway rejects versions it does not support. Grant expiry requires v2, delegated headers require v3, and platform session sync requires v4. Updated operator and gateway images must be deployed together for v4. |
revision |
Deterministic sha256: digest of the canonical policy content. Identical content always yields the same revision. generated_at is excluded from the digest, so timestamps never change it. |
generated_at |
Informational only; set at write time and never affects revision. |
Both sides share pkg/policy.Validate: the operator validates a rendered
document before replacing the ConfigMap, and the gateway validates a decoded
document before activating it. Validation fails closed. It rejects unknown
trust, side-effect, decision, or policy-mode values, duplicate names,
and OAuth without an issuer.
Activation is last-known-good: a malformed, unsupported, or invalid update never replaces the active snapshot. The gateway keeps serving the previous valid policy and records the failure. Snapshot swaps are atomic, so each request sees either the complete old policy or the complete new one.
To check the applied policy, use the gateway endpoints:
GET /health: liveness (always OK while serving).GET /ready: readiness; fails until the first valid policy snapshot loads.GET /config/status: sanitizedschema_version,revision,loaded_at, andlast_reload_error(no policy body).GET /metrics:mcp_gateway_policy_reload_total{result},mcp_gateway_policy_active_revision_info{revision,schema_version}, andmcp_gateway_policy_last_success_timestamp_seconds.
Agent adapters¶
The agent adapter is a helper process for frameworks and IDEs. mcp-runtime
adapter proxy accepts local Streamable HTTP MCP traffic and authenticates to
the governed runtime route with a session-bound client certificate. The gateway
derives the enrolled session identity from the verified certificate. When the
target configures spec.auth, the adapter also forwards the OAuth bearer and
the gateway requires the token subject to match the session human.
With --server <MCPServer name> --agent <id>, the adapter creates or reuses an
MCPAgentSession through POST /api/v1/runtime/adapter/sessions, then submits
a CSR for a certificate whose SPIFFE URI identifies that session. The
platform issues the session only when a matching enabled MCPAccessGrant
allows it. --auto-refresh enrolls a replacement certificate before expiry
and rotates the TLS transport without restarting the process. adapter enroll
saves the PEM files under MCP_RUNTIME_CONFIG_DIR/certs (normally
~/.mcpruntime/certs).
Operational notes:
- The proxy exposes
/healthz,/livez,/readyz, and an optional/metricsendpoint when wired withProxyConfig.MetricsHandler. - Idempotent reads (
tools/list,resources/list,prompts/list,ping) retry on502/504/connection-reset;tools/calldoes not retry. - Set
MCP_RUNTIME_LOG_LEVEL=infoon the adapter to print runtime 4xx denials to stderr.
See Agent Adapters for build commands and full integration examples.
Operator internals (high-level)¶
The operator is a single-controller controller-runtime manager:
- Watches
MCPServer(and owns Deployment / Service / Ingress). - Defaults and validates new API writes through admission webhooks; on reconcile, applies the same defaults to an in-memory copy for legacy objects without patching the stored spec.
- Resolves the image string (respecting
imageTag,registryOverride, andPROVISIONED_REGISTRY_URL). - Builds image-pull secrets, including auto-creating a docker-config secret from provisioned-registry env vars.
- Reconciles Deployment → Service → Ingress in order.
- Computes per-resource readiness, sets phase and conditions, writes status.
Source walkthroughs live under internals/operator.md.
Current scope¶
Implemented and stable enough to evaluate:
- Deployment, routing, image pull, registry handling.
- Grants, sessions, gateway policy generation.
- Trust evaluation and audit-event flow.
- Multi-ingress class support (Traefik, NGINX, Istio, generic).
- OAuth: when
spec.authis configured, the gateway acts as an MCP protected resource. It publishes protected-resource metadata, validates the token issuer and resource audience, and forwards the validated bearer to the MCP application server for validation against the same issuer and audience. Tokens come either from the opt-in bundledmcp-auth-server(setup --with-mcp-auth-server, authorization code with S256 PKCE, refresh rotation, CIMD or DCR client registration) or from an external authorization server you operate. Accounts stay in your identity provider. The bundled server federates to one configured OIDC connector per process. Policy decisions stay in the gateway. See MCP authorization. - Adapter certificates: the runtime API enrolls a session certificate when
MCP_MTLS_CLUSTER_ISSUERandMCP_TRUST_DOMAINare set. Ingress verifies that certificate, and the gateway derives the session identity from it, only whenMCP_ADAPTER_CERTIFICATES=true. Direct clients use OAuth only whenspec.authis present. With verification on, adapters present the certificate and add OAuth for an OAuth-enabled target; the gateway then binds the certificate identity to the OAuth subject.
Not yet:
- Multi-cluster federation.
Next¶
- CLI: every command and flag.
- API: full CRD reference with examples.
- Platform services: what happens after traffic enters the gateway.