Skip to content

2026-02-26

Securing MCP Servers: The Complete Guide

Intended Team · Founding Team

Securing MCP Servers: The Complete Guide

The Model Context Protocol has become the standard for how AI agents interact with tools and services. MCP provides typed tool definitions, structured parameter passing, and result handling. It is well-designed for its purpose: giving AI agents a clean interface to external capabilities.

MCP was not designed for security. The protocol specification does not include authorization, rate limiting, audit logging, or risk evaluation. These are not oversights. They are scope decisions. MCP is a communication protocol, not a security framework. But the absence of security primitives in the protocol means that every MCP deployment needs to fill these gaps at the application level.

This guide covers what MCP lacks, why those gaps matter, and how to address them.

What MCP Provides

MCP provides three core capabilities. Tool discovery: agents can query an MCP server for available tools and their schemas. Tool invocation: agents can call tools with typed parameters and receive structured results. Resource access: agents can read and subscribe to data sources through a standard interface.

The protocol handles serialization, transport, error reporting, and schema validation. If an agent calls a tool with the wrong parameters, MCP returns a validation error. If the tool throws an exception, MCP returns a structured error response. The protocol is robust for its communication purpose.

What MCP Does Not Provide

No Authorization

MCP has no concept of authorization. When an agent calls a tool, the MCP server executes the tool with whatever permissions the server process has. There is no check on whether this specific agent should be allowed to call this specific tool with these specific parameters.

In practice, this means that every tool exposed through MCP is callable by every agent connected to that MCP server. If the server has a tool that deletes database records and a tool that reads customer names, both tools are equally accessible to every connected agent. There is no way within the MCP protocol to restrict which agents can call which tools.

No Rate Limiting

MCP does not limit how frequently tools can be called. An agent can call the same tool a thousand times per second if it decides to. There is no built-in mechanism for throttling, quotas, or velocity detection.

For tools that call external APIs with rate limits, this means the agent can exhaust the API quota. For tools that write data, this means the agent can generate an unbounded volume of writes. For tools that cost money per invocation, this means the agent can generate an unbounded bill.

No Audit Trail

MCP does not log tool invocations. The protocol handles the request-response cycle and discards the details. Unless the MCP server implementation includes custom logging, there is no record of which agent called which tool with which parameters and what the result was.

For development, this is fine. For production, the absence of an audit trail means you cannot answer basic questions: What did the agent do last Tuesday? How many times was the payment tool called this month? Did any agent access customer PII?

No Risk Evaluation

MCP treats all tool calls identically. A tool call that reads a public configuration value and a tool call that initiates a $100,000 wire transfer are both just tool calls. The protocol has no concept of risk, impact, or severity.

This means that governance decisions about which actions need extra scrutiny must be implemented entirely outside the protocol, with no support from the protocol layer.

Why These Gaps Matter

In a development environment with a single developer testing an agent, these gaps are irrelevant. The developer is watching. The data is not real. The stakes are low.

In production, the gaps are severe. Consider a typical MCP deployment for a customer operations agent:

The MCP server exposes tools for reading customer records, updating account details, processing refunds, and sending emails. The server runs with a service account that has permissions for all of these operations. Three different agents connect to the server: a lookup agent, a support agent, and an analytics agent.

Without authorization, all three agents can call all four tools. The analytics agent, which should only read data, can process refunds. The lookup agent, which should only search customers, can send emails. Each agent has access to capabilities it should not have.

Without rate limiting, any agent can call any tool without restriction. The analytics agent could enumerate every customer record in the database. The support agent could process refunds in a loop. Nothing prevents it.

Without an audit trail, nobody knows this is happening. When a customer complains that they received a hundred automated emails, there is no log to trace which agent sent them.

Without risk evaluation, a $10 refund and a $10,000 refund are processed with the same lack of scrutiny.

Securing MCP with Intended

Intended's MCP Gateway sits between agents and MCP servers. It intercepts every tool call, evaluates it against your policies, and either passes it through or blocks it. The gateway is transparent to both the agent and the MCP server. The agent thinks it is calling the MCP server directly. The MCP server thinks it is receiving calls from a normal client.

Setup

typescript
import { IntendedMCPGateway } from "@intended/mcp-gateway";

const gateway = new IntendedMCPGateway({
  apiKey: process.env.Intended_API_KEY,
  orgId: process.env.Intended_ORG_ID,
  upstream: "http://localhost:3001/mcp", // your MCP server
  domainPack: "saas-ops",
});

// Agents connect to the gateway instead of the MCP server directly
gateway.listen(3002);

Per-Agent Authorization

The gateway authenticates each connecting agent and maps it to an agent identity in Intended. Policies can then be scoped to specific agents:

yaml
policies:
  - intent: data.customer.read
    agents: [lookup-agent, support-agent, analytics-agent]
    decision: allow

  - intent: financial.refund.process
    agents: [support-agent]
    decision: escalate
    escalation:
      type: single
      reviewers: [role:support-lead]

  - intent: financial.refund.process
    agents: [lookup-agent, analytics-agent]
    decision: deny
    reason: "Only support agents can process refunds"

  - intent: comms.email.send
    agents: [support-agent]
    decision: allow
    conditions:
      max_recipients: 10

  - intent: comms.email.send
    agents: [lookup-agent, analytics-agent]
    decision: deny

Now each agent can only call the tools it should be able to call, with the appropriate level of scrutiny.

Velocity Controls

The gateway tracks tool call velocity per agent and per tool:

yaml
velocity_rules:
  - agent: analytics-agent
    intent: data.customer.read
    window: 60s
    max_calls: 100
    exceeded_action: deny
    reason: "Rate limit exceeded -- possible data enumeration"

  - agent: support-agent
    intent: financial.refund.process
    window: 3600s
    max_calls: 50
    exceeded_action: escalate

When the analytics agent exceeds 100 customer reads per minute, subsequent reads are blocked. When the support agent exceeds 50 refunds per hour, subsequent refunds require human approval. These limits catch both runaway agent behavior and potential exploitation.

Full Audit Trail

Every tool call through the gateway is recorded with the complete context: agent identity, tool name, parameters, risk scores, policy evaluation results, and the decision. The audit entries are hash-linked and signed.

typescript
// Query the audit trail
const events = await gateway.audit.query({
  timeRange: { from: "2026-02-25", to: "2026-02-26" },
  agent: "support-agent",
  intent: "financial.refund.*",
});

Risk-Aware Evaluation

The gateway evaluates each tool call against the domain pack's risk model. A refund for $10 scores differently than a refund for $5,000. A customer record read scores differently when it is the 5th read today versus the 500th. The risk scores feed into policy evaluation, enabling nuanced decisions.

Defense in Depth

The Intended MCP Gateway is one layer. A complete MCP security strategy includes additional measures:

**Transport encryption.** MCP connections should use TLS. The gateway enforces TLS for agent connections and can be configured to require TLS for upstream MCP server connections.

**Credential rotation.** MCP server credentials (API keys, service account tokens) should be rotated regularly. The gateway manages its own credentials to the upstream MCP server independently from agent credentials.

**Tool scoping.** Expose only the tools that agents need. If an MCP server has 50 tools and an agent needs 5, configure the gateway to expose only those 5 to that agent.

**Network segmentation.** The MCP server should not be directly accessible to agents. Agents connect to the gateway. The gateway connects to the MCP server. The MCP server is on an internal network segment.

MCP is a powerful protocol for AI agent tool use. Securing it requires adding the authorization, rate limiting, audit, and risk evaluation that the protocol intentionally does not provide. The Intended MCP Gateway adds these capabilities without changing your MCP server, your agent code, or your tool definitions.