The MCP Runtime API surface comes in three layers:
- CRDs under
mcpruntime.org/v1alpha1:MCPServer,MCPAccessGrant,MCPAgentSession. - Gateway headers carried on live MCP requests when
gateway.enabled. - Sentinel HTTP APIs exposed by
services/api: dashboard, runtime governance, governance actions, analytics.
flowchart LR
subgraph CRDs
Server[MCPServer]
Grant[MCPAccessGrant]
Session[MCPAgentSession]
end
subgraph HTTP["Sentinel HTTP APIs"]
Dash[/api/dashboard/]
Run[/api/runtime/]
Act[/api/runtime/.../disable etc/]
Ana[/api/events, /api/stats/]
end
CRDs -- rendered into --> Policy[Policy ConfigMap]
Policy --> Gateway[mcp-gateway]
Gateway -->|audit| Ana
Run --> CRDs
| Kind | Purpose |
|---|---|
| MCPServer | Runtime deployment spec plus gateway, auth, policy, session, tool inventory, rollout, and analytics settings. |
| MCPAccessGrant | Who can use which server, for which side-effect classes and tools, with what admin-side maximum trust. |
| MCPAgentSession | Server-side consented trust, expiry, revocation, and upstream token references per agent session. |
| Group | Fields |
|---|---|
| Workload + routing | image, imageTag, registryOverride, replicas, port, servicePort, publicPathPrefix, ingressPath, ingressHost, ingressClass, ingressAnnotations |
| Resources + env | CPU/memory requests/limits, literal envVars, secret-backed secretEnvVars, imagePullSecrets |
| Identity + policy | tools[], auth, policy, session, gateway |
| Delivery | analytics, rollout, useProvisionedRegistry |
| Advanced knobs | gateway.stripPrefix, session.upstreamTokenHeader, analytics.apiKeySecretRef, rollout.maxUnavailable, rollout.maxSurge |
| Enum | Values | Notes |
|---|---|---|
| auth.mode | none, header, oauth |
Working path today is header (identity extraction at the gateway). |
| policy.mode | allow-list, observe |
allow-list enforces deny-by-default; observe keeps the decision path visible. |
| trust | low, medium, high |
Used on tools, grants, sessions. Effective trust = min(grant, session). |
| tool sideEffect | read, write, destructive |
Required on each listed tool. Grants must include the tool's side effect in allowedSideEffects before a tool call can pass. |
| rollout.strategy | RollingUpdate, Recreate, Canary |
Available on spec.rollout. |
- Analytics emission requires
gateway.enabled; settinganalytics.disabled: true(or omitting the analytics block) is the way to opt out per server. gateway.portmust differ fromspec.port.- Every listed
tools[]entry must declaresideEffect. - Canary rollouts require positive
canaryReplicasstrictly less than total replicas.
MCPServer.status exposes phase, message, conditions[], and per-resource readiness booleans for deployment, service, ingress, gateway, policy. MCPAccessGrant and MCPAgentSession expose phase, message, and conditions[].
apiVersion: mcpruntime.org/v1alpha1
kind: MCPServer
metadata:
name: payments
namespace: mcp-servers
spec:
teamID: 7d0a0b8f-7c25-4761-a632-3cf0108e31d6
description: Payments MCP server for invoice lookup and refund workflows.
image: registry.example.com/payments-mcp
port: 8088
publicPathPrefix: payments
gateway:
enabled: true
auth:
mode: header
humanIDHeader: X-MCP-Human-ID
agentIDHeader: X-MCP-Agent-ID
teamIDHeader: X-MCP-Team-ID
sessionIDHeader: X-MCP-Agent-Session
policy:
mode: allow-list
defaultDecision: deny
enforceOn: call_tool
policyVersion: v1
session:
required: true
store: kubernetes
headerName: X-MCP-Agent-Session
maxLifetime: 24h
idleTimeout: 1h
tools:
- name: list_invoices
description: List invoices for a customer account.
requiredTrust: low
sideEffect: read
- name: refund_invoice
description: Issue a refund for an invoice.
requiredTrust: high
sideEffect: destructive
rollout:
strategy: Canary
canaryReplicas: 1MCPAccessGrant.spec.disabled and MCPAgentSession.spec.revoked are the hard kill switches — they turn off access without deleting the underlying object's history.
MCPServer.spec.teamID records the owning platform team. SubjectRef has
humanID, agentID, and teamID; the gateway matches every non-empty subject
field exactly. A grant with only subject.teamID applies to any authenticated
principal from that team when trusted header or OAuth team identity is present.
See Multi-team isolation.
The platform API enforces the namespace boundary for access writes. Grants and
sessions must live in the same namespace as their serverRef; non-admin
callers cannot write access resources into the shared mcp-servers catalog
namespace and can only operate in namespaces authorized on their principal.
Team namespace server writes default and validate spec.teamID against the
authenticated principal namespace. Grant/session writes default missing
subject.teamID from the referenced server team, while preserving an explicit
foreign subject.teamID for delegated cross-team access. The gateway still
matches every non-empty subject field exactly.
allowedSideEffects is independent from toolRules: tool rules select names,
and side-effect allowances select risk kind. A call must pass both. The
Runtime Governance API and UI require at least one allowedSideEffects entry
when creating or updating a grant; direct CRD objects that omit it still
evaluate fail-closed.
apiVersion: mcpruntime.org/v1alpha1
kind: MCPAccessGrant
metadata:
name: payments-ops-agent
namespace: mcp-servers
spec:
serverRef:
name: payments
subject:
humanID: user-123
agentID: ops-agent
teamID: 7d0a0b8f-7c25-4761-a632-3cf0108e31d6
maxTrust: high
allowedSideEffects:
- read
- destructive
policyVersion: v1
toolRules:
- name: list_invoices
decision: allow
requiredTrust: low
- name: refund_invoice
decision: allow
requiredTrust: highapiVersion: mcpruntime.org/v1alpha1
kind: MCPAgentSession
metadata:
name: sess-8f1b9d
namespace: mcp-servers
spec:
serverRef:
name: payments
subject:
humanID: user-123
agentID: ops-agent
teamID: 7d0a0b8f-7c25-4761-a632-3cf0108e31d6
consentedTrust: medium
expiresAt: "2026-03-26T12:00:00Z"
upstreamTokenSecretRef:
name: payments-upstream-token
key: access-token- Header-based identity at the gateway (default path).
- Optional bearer-token validation against JWKS / issuer / audience on
mcp-sentinelAPI + ingest services. spec.auth.mode: oauthexists on the type as a forward-looking shape.
No /authorize, /token, /.well-known/oauth-authorization-server, PKCE, or Dynamic Client Registration endpoint in this release.
- Use the gateway for human, agent, and session identity headers.
- Use MCPAccessGrant + MCPAgentSession for side-effect permissions, trust, and revocation.
- Use OIDC-issued bearer tokens only where Sentinel services validate them.
These routes are served by services/api. Platform identity routes require the
Postgres-backed platform store (POSTGRES_DSN or DATABASE_URL) and
PLATFORM_JWT_SECRET.
POST /api/auth/signup
POST /api/auth/login
POST /api/auth/oidc
GET /api/auth/me
| Route | Body / response |
|---|---|
POST /api/auth/signup |
Body: email, password, optional role. Returns 201 with access_token, token_type, expires_in, and user. Admin signup requires an admin principal. |
POST /api/auth/login |
Body: email, password. Returns 200 with access_token, token_type, expires_in, and user. |
POST /api/auth/oidc |
Body: id_token. Requires configured issuer, audience, and JWKS. Returns 200 with access_token, token_type, expires_in, and user. |
GET /api/auth/me |
Requires auth. Returns authenticated=true and the current principal. |
setup writes OIDC settings through mcp-sentinel-config. For Google sign-in,
set GOOGLE_CLIENT_ID before setup; when the issuer, audience, and JWKS URL are
empty, setup derives the standard Google OIDC values from that client ID. For
other OIDC providers, set OIDC_ISSUER, OIDC_AUDIENCE, and OIDC_JWKS_URL
explicitly. Non-test public TLS setup fails fast unless one of those browser
login configurations is present.
sequenceDiagram
participant Client
participant Gateway as mcp-gateway
participant Server as MCP server
Client->>Gateway: POST /payments/mcp tools/call
Note right of Gateway: Read X-MCP-Human-ID,<br/>X-MCP-Agent-ID,<br/>X-MCP-Agent-Session
Gateway->>Gateway: Lookup grant + session
Gateway->>Gateway: Check sideEffect + min(tool, grant.maxTrust, session.consentedTrust)
alt allowed
Gateway->>Server: forward
Server-->>Gateway: response
Gateway-->>Client: response
else denied
Gateway-->>Client: 403 + audit reason
end
Gateway-->>+Ingest: audit event
- Enforcement point: authorization is evaluated at
call_tool/tools/call, not at discovery time. - Allow-list first: missing grants deny by default unless the policy explicitly overrides the default decision. Empty
toolRulesmeans name-unrestricted access, still constrained byallowedSideEffectsand trust. - Side-effect guard:
allowedSideEffectsis fail-closed. If it is omitted or empty, no tool side-effect class is allowed by that grant. - Audit on allow and deny: the gateway emits decision, reason, trust levels, required side effect, human, agent, session, server, cluster, and namespace fields.
X-MCP-Human-ID: user-123
X-MCP-Agent-ID: ops-agent
X-MCP-Agent-Session: sess-8f1b9d
Overview statistics and usage analytics for the admin and user dashboards.
GET /api/dashboard/summary
GET /api/analytics/usage?limit=10
GET /api/user/analytics/usage?window_days=7&server=payments
The admin dashboard endpoints require admin authentication. For direct
curl/API clients, send an
x-api-key value that is present in both API_KEYS and ADMIN_API_KEYS.
setup keeps UI_API_KEY in both lists for browser/API-key admin login.
INGEST_API_KEYS is only for event ingestion and is not accepted here.
/api/dashboard/summary returns: total_events, active_servers,
active_grants, active_sessions, latest_source, last_event_type,
last_event_time.
/api/analytics/usage reads the ClickHouse event stream and returns admin
usage rollups for the dashboard: totals, top MCP servers, top human/agent
pairs, top tools, decision counts, recent activity, and request buckets.
Query: limit (1-50, default 10), window_days (1-365, default 30),
namespace, team_id, server, decision, and tool_name.
/api/user/analytics/usage is available to normal platform users. It returns
the same analytics shape, but the API enforces scope before querying
ClickHouse: non-admin callers can see only events from team namespaces they
belong to, and the shared mcp-servers catalog is excluded from user
analytics. Query: window_days, limit, namespace, server, decision,
and tool_name. Passing namespace narrows the result only when the caller
owns that namespace or belongs to that team.
Manage access grants, sessions, and view runtime state. All /api/runtime/*
routes require an authenticated platform bearer token or x-api-key; requests
without authentication receive 401. POST requests create the Kubernetes CRs
that the operator renders into the gateway policy ConfigMap. Server redeploys
must opt in with update: true; grants and sessions remain create-or-update.
For POST /api/runtime/grants and admin-only direct POST /api/runtime/sessions, the API resolves serverRef to an MCPServer in the cluster. If that server does not exist, the call returns 400 with a clear unknown serverRef message. The server lookup is not part of a single distributed transaction with the grant/session write — a concurrent delete can leave a stale reference (same as kubectl apply). Kubernetes apply errors are surfaced with the status the API server would use, when available. Non-admin grant mutations and session item mutations require the caller to be the server owner or a team owner for the server namespace; normal adapter flows should use POST /api/runtime/adapter/sessions instead of direct session apply.
GET /api/runtime/servers # List authenticated MCP catalog entries
GET /api/runtime/servers/{namespace}/{name} # Get one MCPServer catalog entry
POST /api/runtime/servers # Create MCPServer; set update=true to redeploy an existing one
DELETE /api/runtime/servers/{namespace}/{name} # Retire one MCPServer
GET /api/runtime/server-events?namespace=&server= # Recent analytics events for one administered server
GET /api/runtime/grants # List MCPAccessGrant resources
GET /api/runtime/grants/{namespace}/{name} # Get one MCPAccessGrant
POST /api/runtime/grants # Create or update an MCPAccessGrant (x-api-key)
DELETE /api/runtime/grants/{namespace}/{name} # Delete one MCPAccessGrant
GET /api/runtime/sessions # List MCPAgentSession resources
GET /api/runtime/sessions/{namespace}/{name} # Get one MCPAgentSession
POST /api/runtime/sessions # Admin/internal direct MCPAgentSession apply
DELETE /api/runtime/sessions/{namespace}/{name} # Delete one MCPAgentSession
POST /api/runtime/adapter/sessions # Issue/reuse an adapter MCPAgentSession for a human/user principal
GET /api/runtime/teams # Admin: all teams; user: caller memberships
POST /api/runtime/teams # Admin-only team + namespace provisioning
GET /api/runtime/teams/{team} # Team metadata (admin/member)
GET /api/runtime/teams/{team}/members # List team memberships (admin/member)
PUT /api/runtime/teams/{team}/members/{userID} # Admin/team-owner membership upsert
POST /api/users # Admin-only password user create
DELETE /api/runtime/teams/{team}/members/{userID}
POST /api/runtime/registry/push # Multipart docker-save upload; in-cluster skopeo push to platform registry
GET /api/runtime/namespaces # Allowed namespaces + org catalog metadata
GET /api/runtime/namespaces/{namespace}
GET /api/runtime/components # Admin-only Sentinel component health status
GET /api/runtime/policy?namespace=&server= # Get rendered policy for an administered server
For non-admin users, runtime scope depends on PLATFORM_MODE / setup
--platform-mode. In tenant mode, GET /api/runtime/servers without a
namespace query returns MCPs in the caller's team namespaces. In org mode,
signed-in users can use the org catalog namespace and their team namespaces.
In public mode, anonymous users can list the mcp-servers-public catalog,
while signed-in users can publish to the public catalog and their team
namespaces. Admin callers can inspect any
namespace. Passing namespace=<name> narrows the list to an authorized
namespace for the active mode. POST /api/runtime/servers also accepts
scope: "tenant" | "org" | "public" in the JSON body. scope: "public"
requires public platform mode and resolves the active public catalog namespace;
scope: "org" requires org mode and resolves the active org catalog namespace;
scope: "tenant" uses the caller's team namespace unless the request passes an
authorized team namespace. If an MCPServer with the same name already
exists in the target namespace, the API returns 409 unless the request body
sets update: true.
POST /api/runtime/servers is governed by the platform publish policy. Admins
configure PLATFORM_MCP_ACTIVE_SERVER_LIMIT (default 5, set 0 to disable)
and PLATFORM_MCP_PUSH_COOLDOWN (Go duration such as 30m, default 0s to
disable). A quota or cooldown denial returns 429 with a clear error; cooldown
responses include next_allowed_at and Retry-After. GET /api/runtime/servers
includes publish_policy so UI clients can show the active limit and count.
Server list/get responses keep CRD tools, prompts, resources, and
tasks as governance metadata and add liveInventory from the running MCP
server when the API service's short-TTL gateway probe has completed. On a cold
cache miss or probe failure, liveInventory is null and
liveInventoryError contains a short reason. DELETE /api/runtime/servers/{namespace}/{name} retires a server and frees one
active-server slot for the owning publisher. The active-server limit is
enforced by the platform API before Kubernetes apply; strict serialization of
concurrent publishes would require a shared reservation or admission-control
layer.
Adapter session minting requires an authenticated principal with a subject or
email, such as a platform login bearer token or user API key. Service-only
setup keys authenticate but cannot mint adapter sessions because they do not
identify the human principal that should own the MCPAgentSession.
{
"name": "payments-ops-agent",
"namespace": "mcp-servers",
"serverRef": {"name": "payments", "namespace": "mcp-servers"},
"subject": {"humanID": "user-123", "agentID": "ops-agent"},
"maxTrust": "high",
"allowedSideEffects": ["read", "destructive"],
"policyVersion": "v1",
"toolRules": [
{"name": "read_invoice", "decision": "allow"},
{"name": "refund_invoice", "decision": "allow", "requiredTrust": "high"}
]
}{
"name": "sess-8f1b9d",
"namespace": "mcp-servers",
"serverRef": {"name": "payments", "namespace": "mcp-servers"},
"subject": {"humanID": "user-123", "agentID": "ops-agent"},
"consentedTrust": "medium",
"policyVersion": "v1",
"expiresAt": "2030-12-31T23:59:00Z"
}Safe operational actions for grants, sessions, and components.
PATCH /api/runtime/grants/{namespace}/{name}
PATCH /api/runtime/sessions/{namespace}/{name}
POST /api/runtime/actions/restart # Body: {component: "api"} or {all: true}
| Action | Effect |
|---|---|
| Grant Toggle | Enable / disable an MCPAccessGrant without deleting it. Disabled grants deny access at the gateway. |
| Session Revoke | Revoke / unrevoke an MCPAgentSession. Revoked sessions cannot be used for tool calls. |
| Component Restart | Rolling restart of Sentinel components (api, ingest, processor, gateway, ui) or all. |
Additional authenticated routes exposed by the API service:
GET /api/deployments # User-scoped deployment list
POST /api/deployments # Apply a platform-managed Deployment + Service
DELETE /api/deployments/{namespace}/{name}
GET /api/admin/namespaces # Admin-only namespace inventory
GET /api/admin/deployments # Admin-only deployment inventory
GET /api/admin/audit # Admin-only audit timeline; supports user/since/until/limit
GET /api/admin/operations # Admin-only user, image, deployment, and timeline view
GET /api/user/api-keys # List caller-owned API keys
POST /api/user/api-keys # Create caller-owned API key
DELETE /api/user/api-keys/{id} # Revoke caller-owned API key
GET /api/user/analytics/usage # User/team-scoped MCP server analytics
GET /api/user/registry-credentials # List caller-owned registry credentials
POST /api/user/registry-credentials # Create a registry credential
DELETE /api/user/registry-credentials/{id}
* /api/registry/authz # Traefik forward-auth for registry ingress
POST /api/user/activity/image-publish # Record a successful user image publish event
User API-key creation returns the cleartext key once as both api_key and
one_time_key; clients should store it immediately.
The bundled registry.<domain> ingress calls /api/registry/authz before
proxying Docker Registry API traffic. Platform admin credentials (x-api-key or
Bearer token) keep global registry access. Normal user API keys and platform
Bearer tokens are accepted only for repository paths scoped to the caller's
team slug or team namespace, such as /v2/acme/demo/... or
/v2/mcp-team-acme/demo/....
In public mode, signed-in users may also write /v2/public/... (or the
configured public catalog namespace). In org mode, signed-in users may write
/v2/org/... (or the configured org catalog namespace). Anonymous requests and
catalog requests for inactive modes are rejected.
Deployment apply body:
{
"name": "payments",
"image": "registry.example.com/payments-mcp",
"version": "v1.0.0",
"port": 8088,
"replicas": 1,
"namespace": "team-a"
}For non-admin users, deployment operations are scoped to the caller's namespace.
Admins may pass namespace; if omitted, admin list calls can span namespaces.
Successful and failed platform deployment, API key, registry credential, login,
and image publish actions are written to platform audit logs where platform
identity storage is enabled. GET /api/admin/operations returns a filtered
operations snapshot with users, audit_logs, images, and deployments.
Filters: user (email, user ID, namespace, resource, or image match), since,
until (RFC3339 or YYYY-MM-DD), and limit (1-200). Image activity includes
CLI-reported registry push events and currently deployed image references
from platform-managed Kubernetes deployments; the bundled Docker registry does
not emit a full raw push ledger.
Read API over the ClickHouse-backed event stream.
GET /api/events?limit=100
GET /api/stats
GET /api/sources
GET /api/event-types
GET /api/analytics/usage?limit=10
GET /api/events/filter?trace_id=<trace>&server=payments&decision=deny&agent_id=ops-agent&limit=50
| Group | Fields |
|---|---|
| Filter fields | trace_id, source, event_type, server, namespace, cluster, human_id, agent_id, session_id, decision, tool_name |
| Audit payload fields | decision, reason, policy_version, required_trust, required_side_effect, admin_trust, consented_trust, effective_trust |
| Transport fields | method, path, status, latency_ms, bytes_in, bytes_out, rpc_method |
mcp-runtime setup builds the runtime operator image, the gateway proxy image, the analytics service images, and deploys the bundled analytics stack by default. Use --without-sentinel to skip the request-path stack and keep only the runtime / operator footprint.
- Sentinel — what each HTTP surface above maps to.
- Architecture — how requests flow through the gateway.
- internals/api-types.md — contributor-oriented guide to the CRD Go types and generated API contract.