Why Kavrynt¶
An MCP gateway puts one entry point in front of many MCP servers. Kavrynt is a control plane for MCP on Kubernetes: the Gateway is one part of it, next to a Kubernetes API for MCP servers, an Operator that knows what each server offers, and the tools to run all of it day to day. These are the design choices that shape it.
Kubernetes is the source of truth¶
MCP servers are declared as MCPServer resources,
validated by the API server at admission, and applied with kubectl, GitOps,
or kavryctl. There is no separate registry or gateway database to keep in
sync.
- The Operator reports
AcceptedandReady, lists each server's tools and their MCP behavior hints intostatus.tools, and records the version the server reports.kubectl get mcpservers -Ais your inventory. - A failed tool discovery shows in
kubectl getandkavryctl list, with a message that names the cause. - The Gateway routes only
Readyservers, at/mcp/<namespace>.<name>, and picks up changes by watching the API, not by polling or restarting.
Caller credentials stay at the Gateway¶
A gateway that forwards the caller's token gives every MCP server a
credential it could use somewhere else. Kavrynt never forwards it: the
Gateway removes Authorization, Cookie, and Proxy-Authorization from
every request. A server that needs a credential declares how it gets one:
- Its own credential (
spec.credential), from a Secret the kubelet mounts, sent only to the endpoint origin it is pinned to. - The caller's identity, exchanged for a token with the server's own
audience (
spec.tokenExchange, OAuth 2.0 Token Exchange, RFC 8693), and only for audiences the platform team allowed for that namespace.
Neither the Gateway nor the Operator has RBAC on Secrets. See Credentials for MCP servers.
One token, one server¶
The Gateway is an OAuth 2.1 resource server for your identity provider. Each
route has its own audience, <resourceURL>/mcp/<namespace>.<name>, and its
own Protected Resource Metadata (RFC 9728), so standard MCP clients find
your authorization server and a token issued for one MCP server is refused
by every other.
For agents that call many servers, a token for the whole Gateway can be
accepted on the routes you list (gateway.auth.gatewayAudience), never on
all of them by a wildcard. Policy input and audit events say which audience a
call used. See Client authentication.
Secure by default, fail closed¶
- Authentication is on by default. An install fails until it names your authorization server or explicitly opts out, and an opt-out is warned about at start and in the console.
- Policy denies unless it allows. The embedded Open Policy Agent must
return
{"allow": true}; an error, a timeout, or a policy that does not compile denies or keeps the previous policy in force. A filteredtools/listthat cannot finish returns an empty list. - No call without its record. With audit on, a full audit queue refuses new MCP requests instead of serving them unrecorded.
- Strict MCP checks. Requests that are not well-formed MCP Streamable
HTTP get
400before they reach a server, and bodies over the request size limit (4 MiB by default) get413.
Decisions on tools, not just routes¶
The tool authorization policy is Rego, evaluated in the Gateway for every MCP request. It sees the verified caller, the route, the MCP method, and the tool, plus the tool's recorded behavior hints and whether it was discovered, but never its arguments.
- Each caller's
tools/listcan show only the tools that caller may call. - A denied tool call answers with a JSON-RPC error the agent can read
(
denied by policy: <reason>). - Policy is a ConfigMap of
.regofiles, so it is reviewed and rolled out like any other configuration.
Audit you can verify¶
With audit on, the Gateway writes one JSON event per MCP request: who called,
which route and tool, the decision and its reason, the outcome, and the
policy revision. Events never contain tool arguments, results, or tokens, and
every response carries the event's X-Request-Id.
Events are chained with SHA-256 per Gateway instance, and
kavryctl audit verify reports every gap, reordering, or altered event. Ship
the events off the cluster with your log pipeline, so a record cannot be
rewritten where it was written. See Audit events.
Team boundaries in shared clusters¶
- Endpoint scope. An
MCPServerwhose endpoint names a Service in another namespace is not routed unless the platform team allows the pair. It judges the host name, so a Service in the team's own namespace that forwards elsewhere needs RBAC or an egress policy too; see Endpoint scope. - Egress checks. The Gateway and the Operator refuse link-local, cloud metadata, and loopback addresses when they connect, and the Gateway passes redirects back instead of following them.
- Traffic stays on the Gateway. Opt-in NetworkPolicies make MCP server pods reachable only from the Gateway and the Operator. See Keeping traffic on the Gateway.
- Least privilege. The Gateway can only read
MCPServerresources and EndpointSlices. Images are distroless, non-root, and read-only.
Built for day two¶
kavryctl doctorchecks an installation and says what to fix;--anonymizemakes the report safe for a public issue.kavryctl exportandimportmove registrations to a rebuilt cluster, with secrets redacted.kavryctl upgradeandrollbackcheck the release before they change it and report every server that is no longer routed afterwards.- A high-availability profile, tested by restarting every Gateway replica under load without a failed call, and MCP session affinity for stateful servers, with no shared state between Gateway replicas.
- Prometheus metrics, Grafana dashboards, and alerts with a runbook each, with notifications to Slack, email, Microsoft Teams, or a webhook.
- A web console with alerts, 24-hour dashboards, a tool catalog, and a playground, with sign-in through your OpenID Connect provider.
In your cluster, in the open¶
MCP traffic, tool calls, and policy decisions stay in your cluster, and nothing depends on a hosted service: the Kavrynt Cloud connectors are off unless you turn them on. The runtime is open source under the Apache License 2.0 at github.com/kavrynt/kavrynt, with Cosign-signed multi-architecture images and one Helm chart.
Where Kavrynt does not fit yet¶
Kavrynt 1.0.0-beta.5 is a beta for development and staging clusters. Choose
something else, or wait, if you need:
- MCP over stdio routed directly. Only
httpservers are routed; run a stdio server behind a Streamable HTTP bridge in its own pod. - A gateway for model or agent-to-agent traffic. Kavrynt governs MCP traffic only.
- Approvals for high-risk tool calls. Policy allows or denies; holding a call for a person is planned.
- MCP on a laptop without Kubernetes. Kavrynt runs on any Kubernetes cluster, including a local Kind cluster, but not without one.
- Roles in the console, or cross-cluster inventory and central policy, which Kavrynt Cloud will provide.
Ready to try it? Start with the Quickstart.