Disclosure: I built systemprompt.io, which is one of the platforms compared in this guide. I will be straightforward about where it is strong and where other approaches may be a better fit. Judge me on the honesty.
The MCP Security Problem
The Model Context Protocol has gone from a niche specification to the default integration layer for AI agents in production. Forrester estimates that 40% of enterprise applications will embed some form of autonomous agent capability by the end of 2026. Most of those agents will connect to external tools and data sources through MCP. And most of those MCP connections will be insecure.
This is not a theoretical concern. It is the observable state of MCP adoption right now.
The typical MCP server starts as a local process. It runs on a developer's laptop, communicates over stdio, and connects Claude to an internal database or API. No authentication. No audit trail. No rate limiting. The developer trusts it because they built it and they are the only person running it. If you have gone through the journey of deploying an MCP server to production, you already know how much changes when a second person needs access.
The problem accelerates when organisations adopt MCP across teams. Each new MCP server connection expands the attack surface. An agent that can call three MCP servers has the combined permissions of all three. An agent that can call fifteen has the effective access of a superuser, distributed across a dozen integration points with no unified policy.
Three critical vulnerabilities emerge at this scale.
Credential exposure. MCP servers need credentials to access the systems they connect to. Database passwords, API keys, OAuth tokens. In most deployments, these credentials are either passed as environment variables to the MCP server process or stored in configuration files that the agent framework reads. If any part of that chain is compromised, or if the credentials leak into the AI model's context window through tool responses, the blast radius is the sum of every system those credentials can access.
Autonomous action without governance. An AI agent does not ask for permission before calling a tool. It evaluates the user's request, decides which tools to invoke, constructs the arguments, and executes. The decision happens inside the model. By the time anyone can review it, the action has already been taken. A misconfigured MCP server that exposes a delete_records tool alongside a query_records tool gives the agent the ability to delete data based on its own interpretation of a prompt.
Surface expansion from every connection. Each MCP server is an independent process with its own dependencies, its own attack surface, and its own failure modes. A team running ten MCP servers has ten separate security surfaces to manage. Different versions of different SDKs. Different authentication mechanisms. Different logging formats. Different people responsible for different servers. The governance overhead scales linearly with the number of connections, and in practice, it scales worse than linearly because no one has a complete picture.
The OWASP Top 10 for Agentic Applications codified these risks in early 2026. ASI02 (Tool Misuse), ASI03 (Identity and Privilege Abuse), ASI07 (Agent Supply Chain), and ASI09 (Resource Saturation) all map directly to the MCP security surface. If you have read our AI agent governance tools comparison, you have seen how broadly the industry is scrambling to address this. The MCP layer is where the most acute risks concentrate because it is where model decisions become real-world actions.
The question is not whether to secure MCP. It is how.
Three Approaches to MCP Security
The market has responded to the MCP security problem with three fundamentally different architectural approaches. Each makes different trade-offs. Understanding the trade-offs matters more than understanding the features.
MCP Gateways
An MCP gateway is a proxy layer that sits between your AI agents and your MCP servers. The agent connects to the gateway. The gateway handles authentication, applies rate limits, logs the request, and forwards it to the appropriate MCP server. The MCP server never sees the raw client connection.
MintMCP, TrueFoundry, Lunar.dev MCPX, and Runlayer all take this approach. Each implements it differently, but the architectural pattern is the same: intercept MCP traffic at a proxy layer and apply governance there.
The strength of gateways is speed of deployment. You can put a gateway in front of existing MCP servers without changing the servers themselves. No code modifications. No SDK changes. Add a proxy, configure authentication and rate limits, and you have a governance layer in hours rather than weeks.
The limitation is depth. A gateway sees the MCP traffic. It knows which tool was called, with which arguments, by which authenticated user. But it does not understand the tool's semantics. It cannot enforce business-level policies like "sales team members can only query their own accounts" or "the content:write tool requires the content:write scope, not just any valid token." A gateway enforces network-level governance. For many organisations, that is sufficient. For those with granular compliance requirements, it is a starting point, not a destination.
Gateways also create a single point of failure. All MCP traffic routes through the gateway. If the gateway goes down, every agent loses access to every tool. High-availability gateway configurations add operational complexity that offsets some of the deployment speed advantage.
Governance Toolkits
A governance toolkit gives you components that you wire into your agent framework to enforce policies at the application layer. Microsoft's Agent Governance Toolkit (AGT) is the clearest example. It provides a policy engine, cryptographic agent identities, runtime isolation, and compliance automation as libraries and services that you integrate into your existing stack.
We covered AGT in depth in our systemprompt.io vs Microsoft AGT comparison. The short version: AGT is powerful, open-source, and extremely flexible. It supports Python, TypeScript, Rust, Go, and .NET. It integrates with LangChain, CrewAI, Google ADK, and Microsoft's own Agent Framework. It claims coverage of all ten OWASP agentic risks.
The trade-off is assembly. AGT is not a product you deploy. It is a set of components you build with. You need engineering capacity to integrate the policy engine, configure identity management, set up the runtime sandbox, and connect it to your monitoring stack. For organisations with strong platform engineering teams, this is ideal. You get exactly the governance architecture you want, built into your existing infrastructure, with no vendor dependency.
For organisations that need governance today and do not have a platform engineering team to spare, the assembly requirement is a blocker.
Integrated Governance Platforms
An integrated governance platform builds MCP governance into the platform itself. The governance pipeline is not a separate layer bolted onto the MCP transport. It is the MCP transport. Every tool call passes through the governance pipeline as part of the protocol execution, not as a proxy intercept.
systemprompt.io takes this approach. MCP servers registered on the platform are governed by the same pipeline that handles authentication, RBAC, audit logging, and policy enforcement for everything else. The MCP service injects credentials server-side. The governance pipeline evaluates every tool call against a four-layer policy stack. Audit events are structured JSON, ready for SIEM ingestion.
The strength is completeness. You do not configure governance separately from MCP. They are the same thing. The weakness is flexibility. You are governing MCP within the platform's architecture. If you need governance for MCP servers that run entirely outside the platform, on developer laptops or in other infrastructure, an integrated platform cannot reach them. A gateway can.
Each approach has a natural home. Gateways are best for organisations that have existing MCP servers and need governance quickly. Toolkits are best for organisations with strong engineering teams that want to build governance into their own architecture. Integrated platforms are best for organisations that want a complete solution and are willing to standardise on a single governance layer.
What Production MCP Security Requires
Regardless of which approach you choose, production MCP security has six non-negotiable requirements. If your deployment is missing any of these, you have a gap that will eventually become an incident.
Per-Server OAuth2 Scoping
Every MCP server needs its own OAuth2 configuration with scoped permissions. Not a shared token across all servers. Not a global API key. Per-server, per-scope authentication.
The MCP specification defines OAuth 2.1 as the standard authentication mechanism for HTTP transport. In practice, this means each MCP server exposes a discovery endpoint, and clients follow the authorisation code flow with mandatory PKCE. Our MCP server authentication guide covers the implementation in detail.
What the specification does not prescribe is scope granularity. This is where most deployments fall short. A valid OAuth2 token should not grant access to every tool on the server. Each tool should require a specific scope.
Here is a concrete configuration pattern for per-server OAuth2 with tool-level scoping:
# mcp-server-registry.yaml
servers:
content-api:
url: "https://mcp.internal.example.com/content"
oauth2:
issuer: "https://auth.example.com"
audience: "mcp:content-api"
scopes:
- "content:read"
- "content:write"
- "content:publish"
tool_scopes:
list_articles:
required: ["content:read"]
create_article:
required: ["content:write"]
publish_article:
required: ["content:publish"]
analytics-db:
url: "https://mcp.internal.example.com/analytics"
oauth2:
issuer: "https://auth.example.com"
audience: "mcp:analytics-db"
scopes:
- "analytics:read"
tool_scopes:
query_metrics:
required: ["analytics:read"]
export_report:
required: ["analytics:read"]
The key detail: the content-api server and the analytics-db server have different audiences. A token issued for mcp:content-api cannot be used against mcp:analytics-db, even if both servers sit behind the same gateway. Compromising one token does not grant access to the other server.
Tool Call Audit Trails
Every tool invocation must be logged with enough detail to reconstruct what happened, who initiated it, and what the outcome was. This is not optional for any organisation with compliance requirements, and it is not optional for any organisation that wants to debug agent behaviour in production.
A production-grade audit event looks like this:
{
"event_id": "evt_8f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"timestamp": "2026-04-07T14:23:11.847Z",
"event_type": "mcp.tool_call",
"server": "content-api",
"tool": "create_article",
"user_id": "usr_29384756",
"agent_id": "agent_content-writer",
"session_id": "sess_a1b2c3d4",
"arguments": {
"title": "Q2 Product Update",
"category": "announcements",
"draft": true
},
"result": {
"status": "success",
"article_id": "art_57392846",
"duration_ms": 342
},
"auth": {
"token_issuer": "https://auth.example.com",
"scopes": ["content:write"],
"token_exp": "2026-04-07T14:28:11Z"
},
"policy": {
"evaluated": true,
"rules_matched": ["require-draft-mode-for-new-articles"],
"decision": "allow"
}
}
Three things matter in this event structure. First, the identity chain is complete: user, agent, session, and authentication context. You can trace any tool call back to a specific human decision. Second, the policy evaluation is recorded. You know not just what happened but which governance rules were applied. Third, the arguments are logged. If an agent creates content or modifies data, you have the exact parameters.
For SIEM integration, these events should be emitted as structured JSON to a dedicated audit stream. Most SIEM platforms (Splunk, Elastic, Datadog) can ingest structured JSON directly. The alternative, parsing unstructured log lines, is fragile and loses detail.
Secret Isolation
This is the requirement most deployments get wrong, and the one with the worst consequences when it fails.
The problem: an MCP server needs credentials to access backend systems. A database MCP server needs a database password. A CRM MCP server needs an API key. These credentials must exist somewhere in the execution path.
The wrong approach is to pass credentials through the agent. If the agent's configuration includes the database password, that password exists in the agent's context. It can leak into model responses. It can be extracted through prompt injection. It can appear in logs. The credential's blast radius extends to anywhere the agent's output is visible.
The correct approach is server-side credential injection. The MCP service resolves credentials at the server side. The agent never sees the actual credential. Instead, the agent receives a resolution token, a short-lived reference that the MCP service exchanges for the real credential at execution time.
Here is how the flow works:
- The agent calls the
query_metricstool on the analytics MCP server. - The MCP gateway or platform authenticates the agent's OAuth2 token and validates scopes.
- The MCP service looks up the analytics database credential from a secrets store (HashiCorp Vault, AWS Secrets Manager, or the platform's built-in secret management).
- The credential is injected into the MCP server's execution context for the duration of the tool call.
- The tool executes. The result is returned to the agent.
- The credential is never included in the tool response. The agent's context window never contains the database password.
Resolution tokens have a five-minute expiry by default. If a token is intercepted, it is useless within minutes. The actual credential never traverses the network between the agent and the MCP server.
This is fundamentally different from passing credentials as environment variables to the MCP server process, which is the most common pattern in development deployments. Environment variable injection means the credential persists for the lifetime of the process. Server-side injection means the credential exists in the execution context only for the duration of the individual tool call.
Rate Limiting
Rate limiting for MCP is not the same as rate limiting for a REST API. A REST API serves human-initiated requests. An MCP server serves agent-initiated requests. Agents do not pause between tool calls. They do not get tired. A misconfigured agent can call the same tool hundreds of times in a loop, and it will do so as fast as the server can respond.
Production rate limiting needs three dimensions:
# rate-limits.yaml
limits:
per_user:
requests_per_minute: 60
requests_per_hour: 500
concurrent_sessions: 5
per_tool:
query_metrics:
requests_per_minute: 30
max_result_size_kb: 512
create_article:
requests_per_minute: 10
requires_approval_above: 5
delete_record:
requests_per_minute: 2
requires_human_approval: true
per_department:
engineering:
monthly_tool_calls: 50000
priority: "high"
marketing:
monthly_tool_calls: 20000
priority: "standard"
The per_tool dimension is the most important and the most commonly missing. A blanket rate limit of 100 requests per minute is reasonable for read operations but dangerously permissive for write or delete operations. Production deployments should have tighter limits on destructive tools and, ideally, require human approval for high-impact actions above a threshold.
The per_department dimension is relevant for cost management. MCP tool calls consume compute resources on the backend systems they connect to. An unthrottled department can rack up significant infrastructure costs from agent-driven tool usage. Monthly ceilings with alerting prevent surprises.
Central Registry
In development, each developer configures their own MCP servers in their local Claude Code settings. In production, this creates configuration drift. Developer A has version 2.3 of the analytics MCP server. Developer B has version 2.1. Developer C has a completely different URL because they are pointing at a staging environment they forgot to switch back.
A central registry solves this by being the single source of truth for all MCP server configurations.
# central-registry.yaml
registry:
version: "2026-04-07"
servers:
content-api:
url: "https://mcp.internal.example.com/content"
version: "3.1.0"
health_check: "/health"
health_interval_seconds: 30
status: "active"
owner: "content-team"
last_audit: "2026-03-15"
analytics-db:
url: "https://mcp.internal.example.com/analytics"
version: "2.4.1"
health_check: "/health"
health_interval_seconds: 30
status: "active"
owner: "data-team"
last_audit: "2026-04-01"
legacy-crm:
url: "https://mcp.internal.example.com/crm-v1"
version: "1.0.3"
health_check: "/health"
health_interval_seconds: 60
status: "deprecated"
deprecation_date: "2026-06-01"
replacement: "crm-v2"
owner: "sales-ops"
The registry includes health monitoring, version tracking, ownership, and deprecation status. When a server is deprecated, agents receive a warning but can still connect until the deprecation date. When the date passes, the registry stops serving the server configuration, and agents that still reference it fail with a clear error.
Central registries also enable compliance auditing. You can answer "which MCP servers are deployed, who owns them, and when were they last reviewed?" in a single query.
Configuration Integrity
The final requirement ties everything together. An agent should only be able to invoke tools it has been explicitly granted access to. This means explicit agent-to-tool mappings, not implicit access to everything registered in the system.
# agent-tool-mappings.yaml
agents:
content-writer:
description: "Drafts and publishes content"
allowed_servers:
- server: "content-api"
tools: ["list_articles", "create_article", "publish_article"]
- server: "analytics-db"
tools: ["query_metrics"]
denied_servers:
- "legacy-crm"
sales-assistant:
description: "Manages sales pipeline"
allowed_servers:
- server: "crm-v2"
tools: ["list_opportunities", "update_opportunity"]
- server: "analytics-db"
tools: ["query_metrics"]
denied_servers:
- "content-api"
The content-writer agent can read analytics but cannot touch the CRM. The sales-assistant can read analytics and manage opportunities but cannot publish content. Each agent has exactly the permissions it needs and nothing more.
This is the principle of least privilege applied to MCP. Without it, every agent has the theoretical ability to call every tool on every registered server. With it, a compromised or misconfigured agent can only reach the tools it was explicitly granted.
MCP Gateway Comparison
The comparison below covers the MCP-specific gateway and governance products available as of April 2026. This is not exhaustive. New entrants appear regularly. But these are the ones with production deployments or significant community adoption.
| Capability | MintMCP | TrueFoundry | Lunar.dev MCPX | Runlayer | systemprompt.io |
|---|---|---|---|---|---|
| OAuth2 support | Yes (per-server) | Yes (platform-wide) | Yes (per-server) | Yes (per-server) | Yes (per-server, per-tool scoping) |
| Audit trails | Basic (tool call logging) | Detailed (structured JSON) | Basic (request logging) | Basic (tool call logging) | Detailed (structured JSON, policy trace) |
| Secret management | Vault integration | Built-in secrets | Environment injection | Vault integration | Built-in (server-side injection, 5-min expiry tokens) |
| Rate limiting | Per-user | Per-user, per-tool | Per-user | Per-user | Per-user, per-tool, per-department |
| RBAC | Basic roles | Team-based | No | Basic roles | 6-tier RBAC (owner to anonymous) |
| SIEM integration | Webhook export | Datadog, Splunk | No | Webhook export | Structured JSON events, webhook and streaming export |
| Self-hosted option | No (SaaS only) | Yes (Kubernetes) | No (SaaS only) | No (SaaS only) | Yes (single binary, air-gapped capable) |
| MCP-native vs proxy | Proxy | Proxy | Proxy | Proxy | Native (governance is the transport) |
| Pricing model | Per-seat | Platform licence | Per-request | Per-seat | Free tier, Pro per-seat, Enterprise custom |
A few observations worth noting.
MintMCP has strong developer experience. If you need a gateway running in front of existing MCP servers within an afternoon, MintMCP is the fastest path. The trade-off is that governance depth stops at the proxy layer. You get authentication and logging, but you do not get policy evaluation or tool-level scoping.
TrueFoundry is the strongest option for organisations already on Kubernetes. Their gateway integrates with existing Kubernetes RBAC and service mesh configurations. The team-based access model maps well to organisations that already manage permissions through namespace-level policies.
Lunar.dev MCPX focuses on observability rather than governance. If your primary concern is understanding what your agents are doing, rather than controlling what they are allowed to do, MCPX provides detailed request analysis. Governance is lighter.
Runlayer is the newest entrant and the most focused on developer workflow. Their registry model makes it simple to share MCP server configurations across teams. Governance features are still early.
systemprompt.io is the only option where MCP governance is not a separate product bolted onto the platform. The governance pipeline handles MCP the same way it handles everything else. The trade-off is that you are adopting a platform, not adding a proxy. That is a larger commitment, and for some organisations, it is more than they need.
Implementation Patterns
The configuration examples above are illustrative. Here are the patterns that matter when implementing each requirement in practice.
OAuth2 Per-Server Pattern
The key implementation detail is audience isolation. Each MCP server must have a distinct audience value in its OAuth2 configuration. When your identity provider issues a token, the audience claim restricts which server that token can access.
If you are using an identity provider like Auth0, Okta, or Keycloak, create a separate API/resource definition for each MCP server. Each definition gets its own audience URI and its own set of scopes. Agents request tokens for a specific audience when they need to call tools on that server.
This prevents lateral movement. An attacker who obtains a valid token for the content API cannot use it to query the analytics database. The audience mismatch causes the token validation to fail at the server level, before any tool execution occurs.
Audit Trail Pattern
Audit events should flow to a dedicated stream, separate from application logs. Application logs are for debugging. Audit events are for compliance and forensics. They have different retention requirements, different access controls, and different consumers.
The event schema should be versioned. When you add new fields to your audit events, consumers that have not updated should not break. Use a schema version field and document the evolution. SIEM integrations that parse specific fields will fail silently if the schema changes without notice.
Emit audit events synchronously within the tool call path, not asynchronously after the fact. If the audit write fails, the tool call should fail. This ensures that you never have a successful tool execution without a corresponding audit record. The latency cost of a synchronous write is small (single-digit milliseconds for a well-configured event store) and the integrity guarantee is worth it.
Secret Isolation Pattern
If you are implementing secret isolation without a governance platform, the minimum viable pattern is a sidecar process.
The MCP server does not have direct access to credentials. Instead, a sidecar process running alongside the MCP server holds the credentials and exposes a local-only endpoint (localhost, Unix socket, or shared memory) that the MCP server calls to retrieve credentials for a specific tool execution. The sidecar validates that the requesting process is the expected MCP server (using process identity or a local authentication token) and returns the credential with a time-to-live.
This is not as robust as platform-level secret injection, but it achieves the critical property: the credential does not exist in the MCP server's environment variables, configuration files, or persistent memory. It exists only in the sidecar and is provided to the MCP server on demand, per-request.
Rate Limiting Pattern
Implement rate limiting at the gateway or platform level, not inside individual MCP servers. If each MCP server implements its own rate limiting, you have no aggregate view. A user who is rate-limited on the content API can still hammer the analytics API and the CRM API simultaneously.
Centralised rate limiting gives you aggregate enforcement. A user's total tool calls per minute are counted across all servers. Individual server limits are applied on top of the aggregate. This prevents both targeted abuse (one server taking all the load) and distributed abuse (spreading calls across many servers to stay under per-server limits).
OWASP Alignment
The OWASP Top 10 for Agentic Applications provides the most widely referenced framework for agentic AI security risks. Here is how MCP security requirements map to specific OWASP risks.
ASI02: Tool Misuse. An agent invokes a tool in a way the developer did not intend. A query tool is used to exfiltrate data. A write tool is used to overwrite critical records. MCP governance addresses this through tool call audit trails (detecting misuse after the fact), rate limiting (constraining the volume of misuse), and configuration integrity (preventing agents from accessing tools they should not have).
ASI03: Identity and Privilege Abuse. An agent operates with more permissions than it needs. A read-only agent somehow has write access. A departmental agent can access cross-departmental data. Per-server OAuth2 with tool-level scoping addresses this directly. Each agent gets exactly the scopes it needs. RBAC layered on top ensures that the human behind the agent also has appropriate permissions.
ASI07: Agent Supply Chain. A third-party MCP server contains malicious behaviour. A community-contributed tool exfiltrates data through its responses. A compromised server update introduces a backdoor. The central registry addresses this through version pinning, health monitoring, ownership tracking, and audit requirements. You know exactly which servers are deployed, who owns them, what version they run, and when they were last reviewed.
ASI09: Resource Saturation. An agent enters a loop and calls the same tool thousands of times. A coordinated attack uses multiple agents to overwhelm a backend service through MCP. Rate limiting at the per-user, per-tool, and per-department levels prevents both accidental and intentional resource exhaustion.
ASI10: Communication Manipulation. An attacker intercepts or modifies MCP traffic between the agent and the server. OAuth2 over HTTPS provides authentication and transport encryption. Token validation at the server ensures that even if traffic is intercepted, replayed requests with expired or invalid tokens are rejected. For internal networks where HTTPS termination happens at a load balancer, mutual TLS between the gateway and the MCP server provides an additional layer.
These mappings are not one-to-one. No single security measure addresses any OWASP risk completely. But MCP governance provides the foundational controls that make comprehensive OWASP coverage achievable.
How systemprompt.io Addresses This
systemprompt.io was built as AI governance infrastructure, not as an MCP gateway. MCP governance is one part of a broader governance pipeline that covers skills, agents, connectors, and tool invocations.
The governance pipeline evaluates every action through four layers: authentication, authorisation, policy evaluation, and audit. MCP tool calls pass through the same pipeline as every other action on the platform. There is no separate MCP governance configuration. If a user has the content:write scope, they can use the create_article tool through MCP. If they do not, the pipeline rejects the call before it reaches the MCP server.
Secret isolation is built into the MCP service. Credentials are stored in the platform's secret management layer and injected server-side at execution time. The agent context never contains actual credentials. Resolution tokens expire after five minutes.
For organisations evaluating MCP governance, the MCP governance feature page covers the specifics. For those who want to understand how MCP governance fits into the broader governance architecture, the unified control plane documentation explains how MCP, skills, agents, and connectors are governed through a single policy layer.
Conclusion
MCP security is not a feature you add after deployment. It is an architectural decision you make before the first production MCP server goes live. The six requirements outlined here (per-server OAuth2, audit trails, secret isolation, rate limiting, central registry, and configuration integrity) are the minimum for any organisation running MCP servers in production.
The approach you choose depends on where you are. If you have existing MCP servers and need governance quickly, a gateway like MintMCP or TrueFoundry gets you there in hours. If you have the engineering capacity to build governance into your own architecture, Microsoft's AGT gives you powerful open-source components. If you want a complete governance platform that handles MCP alongside everything else, systemprompt.io is built for that.
Whatever you choose, do not leave MCP servers ungoverned in production. The attack surface is real, the compliance requirements are tightening, and the cost of an incident involving an autonomous agent with uncontrolled tool access is not a risk worth carrying.