MCP Security Overview
The Model Context Protocol (MCP) is Anthropic's open standard for connecting AI models to external tools, data sources, and services. It's powerful, flexible, and increasingly adopted — and it introduces significant security considerations that most teams are not prepared for.
MCP creates a direct channel between an AI model and real-world systems. This is the feature. The security challenge: that same channel can be exploited to perform unauthorized actions, extract sensitive data, or pivot to other systems.
Authentication & Authorization
MCP Server Authentication
MCP servers should never be accessible without authentication. Implement at minimum:
- API key authentication for programmatic access
- JWT tokens with short expiry for session-based access
- OAuth 2.0 for production deployments with multiple clients
Configuration example for a Nginx-fronted MCP server:
server {
listen 443 ssl;
server_name mcp.yourdomain.com;
# Require API key header
if ($http_x_api_key != $valid_api_key) {
return 401 "Unauthorized";
}
# Rate limiting
limit_req zone=mcp_zone burst=20 nodelay;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
}
Tool-Level Authorization
Not every tool should be available to every client. Implement a permission matrix:
# MCP tool permissions config
tools:
file_read:
allowed_paths: ["/app/data/", "/app/public/"]
require_scope: "read"
file_write:
allowed_paths: ["/app/output/"]
require_scope: "write"
require_audit_log: true
shell_execute:
enabled: false # Disable unless explicitly needed
http_request:
allowed_domains: ["api.openai.com", "api.anthropic.com"]
require_scope: "network"
Tool Permissions: The Principle of Least Privilege
The golden rule: give agents the minimum tool set required to complete their task. Every additional tool is an additional attack vector.
High-Risk Tools (Require Explicit Justification)
shell_execute/bash— near-arbitrary code executionfile_writeto arbitrary paths — can overwrite configs, scriptshttp_requestto arbitrary URLs — SSRF risk, data exfiltrationdatabase_write— data modification
Medium-Risk Tools (Require Logging)
file_read— sensitive data exposure if paths not restrictedhttp_getto allowlisted domains — can be used for indirect injectionmemory_store— persistent injection risk
Low-Risk Tools (Standard Monitoring)
calculatordatetimetext_transform
Network Hardening
Firewall Configuration (UFW)
# Default deny all incoming
ufw default deny incoming
ufw default allow outgoing
# Allow SSH (restricted to your IP)
ufw allow from YOUR_IP to any port 22
# Allow HTTPS only (no direct MCP port)
ufw allow 443/tcp
# Block everything else
ufw enable
Docker Network Isolation
# docker-compose.yml
version: '3.8'
services:
mcp-server:
build: .
networks:
- internal
# Never expose port directly to host
# expose:
# - "8080" # Internal only
environment:
- MCP_BIND=127.0.0.1:8080
nginx:
image: nginx:alpine
ports:
- "443:443"
networks:
- internal
- external
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
networks:
internal:
internal: true # No external access
external:
Monitoring & Alerting
What to Log
Every MCP tool call should be logged with:
- Timestamp (UTC)
- Tool name and parameters
- Requesting client ID / session
- Result status (success/error)
- Execution time
Alert Triggers
- More than 5 tool calls per minute from a single session
- Any call to
shell_execute(should alert even if allowed) - File access outside permitted paths (attempted)
- HTTP requests to unexpected domains
- Authentication failures (3+ in 5 minutes = lockout)
Production Checklist
- ☐ MCP server bound to localhost only (nginx/caddy proxy for external)
- ☐ API key authentication on all endpoints
- ☐ Rate limiting configured (max 100 req/min per key)
- ☐ Tool allowlist — disabled tools explicitly set to
enabled: false - ☐ File system access restricted to specific directories
- ☐ HTTP tool restricted to allowlisted domains
- ☐ Shell execution disabled unless absolutely required
- ☐ Audit logging enabled for all tool calls
- ☐ Alert thresholds configured and tested
- ☐ Incident response runbook documented
- ☐ Secrets stored in environment variables (not config files)
- ☐ Regular secret rotation scheduled (every 90 days)
