MCP Security Integration: Hardening MCP Servers Step by Step
Integrating the Model Context Protocol is the moment your model stops generating text and starts acting: reading files, querying databases, calling APIs — with your credentials. This is the hands-on companion to our MCP security hub: hub for the security model, this page for the integration work. If you want the attack walkthroughs first, read MCP Security: Protecting AI Agents from MCP Threats.
The Integration Checklist
- Authenticate every transport — no MCP endpoint reachable without an identity.
- Scope each tool to the caller — deny by default, grant per user and per role.
- Treat tool descriptions and outputs as untrusted — scan them like user prompts.
- Sandbox filesystem and network access — explicit roots, explicit egress.
- Log every tool call with identity — without the trail, incidents are undiagnosable.
- Test with hostile servers — assume a connected server is adversarial until proven otherwise.
1. Authenticate Every Transport
The MCP specification defines authentication for remote (HTTP-based) transports using OAuth 2.1, and the first integration mistake is ignoring it: a streamable HTTP or SSE server exposed without auth is a remote tool-execution API for anyone who finds the URL. Local stdio servers are not "safe by default" either — they inherit the full privileges of the process that spawns them.
- Remote servers: OAuth 2.1 with audience-bound tokens, or JWT/API keys with rotation for internal machine-to-machine clients.
- Local servers: run each server as its own restricted user, not as the agent's user.
- Never share one service account across integrations — per-user identity is what makes the next step possible.
2. Scope Each Tool to the Caller
Authorization must answer "may this user, through this agent, call this tool?" — not "is the client application allowed to use MCP?". A shared service account collapses every user into one permission set, and one injected instruction then reaches every tool.
- Deny by default: a tool not explicitly granted to the caller's role returns an authorization error.
- Grant per user, per integration: the same principle as our capability bitmask model for LLMs — capabilities as data, not as code branches.
- Separate read from write: reading a record and deleting it are different capabilities; most agents only need the first.
resk-mcp (published as mcp-resk on PyPI) implements this layer over the official MCP Python SDK — JWT authentication, per-user authorization, request validation, rate limiting, and audit logging, configured through YAML:
pip install mcp-resk
import os
from resk_mcp import SecureMCPServer
# Secrets come from the environment — never hard-code credentials
server = SecureMCPServer(
name="internal-tools",
jwt_secret=os.environ["MCP_JWT_SECRET"],
)
@server.tool()
def read_report(report_id: str) -> str:
"""Fetch a report by id. The caller's role must grant this tool."""
See the GitHub repository for the full YAML configuration (roles, tool grants, rate limits).
3. Treat Tool Descriptions and Outputs as Untrusted Input
In MCP, the server writes text that lands in your model's context: tool names, descriptions, and results. That makes a connected server a prompt-injection vector — a benign-looking tool description can carry hidden instructions ("tool poisoning"), and a tool result can smuggle a payload back into the conversation. This is prompt injection arriving through a channel most teams never classify as user input.
- Validate tool arguments against their schema before execution, and scan results for injection patterns before they enter the model's context — resk-mcp runs this validation inside the server, where tool output is still plain data.
- Pin server versions and review description changes: a tool description that mutates after trust was established is a red flag.
- Keep retrieved content and instructions in separate context regions where your framework supports it — and never let tool output reconfigure the agent.
4. Sandbox Filesystem and Network Access
Most MCP incidents end with "the tool did what it was allowed to do". Make that set small:
- Filesystem: explicit root directories per server, read-only unless writes are the tool's purpose.
- Network: egress allowlists. A "fetch URL" tool without an allowlist is an SSRF primitive pointed at your internal network and cloud metadata endpoints.
- Shell: no shell-executing tools in production agents; if unavoidable, wrap them behind approval workflows and log every invocation.
- Quotas: per-user rate limits and token budgets contain runaway agents (least privilege for agent tools).
5. Log Every Call with Identity
Every tool invocation should produce an audit record: caller identity, tool, arguments, result status, timestamp. Without it, you cannot answer the only question that matters during an incident — what did the agent actually do, as whom? resk-mcp logs calls with interaction counters; for a full observability pipeline, ReskPoints exports agent activity to Datadog, Prometheus, or OpenTelemetry. If you deploy the LLM firewall, tool-call authorization and audit also happen at the request path, before the MCP server is even reached.
6. Test with Hostile Servers
Integration security is verified adversarially: connect a malicious server to your client, a hostile client to your server, and check what gets through. Malicious tool descriptions, poisoned results, argument schema bypasses, replay of tool calls — our AI pentesting practice runs MCP-specific scenarios against real deployments.
Common Integration Mistakes
- Exposing an unauthenticated HTTP/SSE MCP server "temporarily" — it is scanned for within days.
- One shared service account for all users, making per-user authorization impossible.
- Wildcard tool grants ("the agent may use everything") because role setup is tedious — the integration checklist exists precisely to make this deliberate.
- Trusting tool descriptions because they came from a "known" server — descriptions change, and supply chains get compromised.
- No audit trail until after the first incident.
Go Deeper
- MCP Security for AI Agents — mechanisms, layers and the attack surface
- resk-mcp — the security layer used in the code above
- MCP Security: Protecting AI Agents from MCP Threats — attack walkthroughs
- AI Agent Security — tool permissions and observability beyond MCP
Connecting agents to MCP servers? Put authentication, authorization, and audit in front of every tool call.
Explore resk-mcp View on GitHub Talk to Us