MCP Security: Integrating Tools Safely
What this article covers
- How to securely integrate MCP tools for AI agents.
- How to implement tool validation and injection protection.
- How to use sandboxing for critical tools.
- Practical examples of secure tool integration.
- Best practices for security and risk minimization.
Introduction: MCP Security explained
MCP security means your tools are protected against misuse, injection attacks, and unauthorized access. An agent should not be able to call arbitrary tools, send random parameters, or exfiltrate sensitive data.
This article is for users who want to integrate MCP tools safely. For foundational concepts, see MCP and Agent Security.
Why do you need MCP security?
Imagine your agent has a tool called “execute_command”. Without security: it could run rm -rf /. With security: only approved commands, only approved parameters, all actions logged. MCP security prevents misuse.
MCP security at a glance
MCP tool + security = input validation, permissions, sandboxing, audit logging. Your agent can only run approved tools, with approved parameters, performing approved actions.
The core principle is simple: prevent misuse through validation and control.
Who should read this article?
- Security-conscious developers who want to harden their agents.
- Developers building secure tools.
- Admins implementing access control.
- DevOps engineers deploying agents safely.
Key concepts
- MCP - Model Context Protocol. Use when: integrating tools.
- Tool Permissions - Access control. Use when: securing systems.
- Prompt Injection - Attack vectors. Use when: assessing risks.
- Sandboxing - Isolation. Use when: protecting critical tools.
- Audit Logging - Recording actions. Use when: maintaining accountability.
Security layers
Agent request
│
▼
1. Input validation
├─ Check parameter types
├─ Check value ranges
└─ Detect injection patterns
│
▼
2. Permissions
├─ Tool allowed?
├─ Action allowed?
└─ Scope allowed?
│
▼
3. Sandboxing (for critical tools)
├─ Isolated environment
├─ No system access
└─ Timeout limits
│
▼
4. Audit log
├─ Who? What? When?
├─ Success? Failure?
└─ Alert on anomalies
│
▼
Tool execution
Practical example 1: Input validation
import re
from typing import Any
class SecureTool:
"""Secure tool with input validation"""
def validate_input(self, param_name: str, value: Any, param_type: type):
"""Validate input"""
# Check type
if not isinstance(value, param_type):
raise ValidationError(f"{param_name} must be {param_type.__name__}")
# Check for injection patterns
if isinstance(value, str):
dangerous_patterns = [
r"rm\s+-rf", r"sudo", r"eval\(", r"exec\(",
r"__import__", r"subprocess", r"os\.system"
]
for pattern in dangerous_patterns:
if re.search(pattern, value, re.IGNORECASE):
raise SecurityError(f"Dangerous pattern detected: {pattern}")
return True
def safe_execute(self, command: str):
"""Execute safely"""
# Validate
self.validate_input("command", command, str)
# Only allow approved commands
allowed_commands = ["ls", "pwd", "cat", "grep", "find"]
cmd = command.split()[0]
if cmd not in allowed_commands:
raise PermissionError(f"Command '{cmd}' not allowed")
# Execute
import subprocess
result = subprocess.run(
command.split(),
capture_output=True,
text=True,
timeout=10
)
return result.stdout
Practical example 2: Sandboxing
import docker
class SandboxedTool:
"""Tool in sandbox"""
def __init__(self):
self.client = docker.from_env()
def execute_in_sandbox(self, code: str):
"""Execute code in sandbox"""
# Docker container for isolation
container = self.client.containers.run(
image="python:3.11-slim",
command=f"python -c '{code}'",
remove=True,
network_disabled=True, # No network
mem_limit="128m", # Memory limit
cpu_period=100000,
cpu_quota=50000, # CPU limit
security_opt=["no-new-privileges"],
cap_drop=["ALL"] # Drop all capabilities
)
return container.decode("utf-8")
Practical example 3: Injection protection
class InjectionProtectedTool:
"""Tool with injection protection"""
def sanitize_input(self, user_input: str) -> str:
"""Sanitize input"""
# Remove/escape dangerous characters
sanitized = user_input
sanitized = sanitized.replace(";", "")
sanitized = sanitized.replace("|", "")
sanitized = sanitized.replace("&", "")
sanitized = sanitized.replace("`", "")
sanitized = sanitized.replace("$(", "")
sanitized = sanitized.replace("${", "")
return sanitized
def safe_query(self, table: str, filters: dict):
"""Execute database query safely"""
# Validate table name (prevent SQL injection)
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', table):
raise ValidationError("Invalid table name")
# Sanitize filters
sanitized_filters = {}
for key, value in filters.items():
sanitized_filters[key] = self.sanitize_input(str(value))
# Parameterized query
return self.db.query(table, sanitized_filters)
Practical example 4: Audit logging
import logging
from datetime import datetime
class AuditedTool:
"""Tool with audit logging"""
def __init__(self):
self.logger = logging.getLogger("mcp_tool")
def log_tool_call(self, tool_name, params, result, status):
"""Log tool call"""
self.logger.info({
"timestamp": datetime.now().isoformat(),
"tool": tool_name,
"params": params,
"result": str(result)[:1000], # Truncate for logging
"status": status
})
def execute_with_audit(self, tool_name, params):
"""Execute tool with audit"""
try:
result = self.execute(tool_name, params)
self.log_tool_call(tool_name, params, result, "success")
return result
except Exception as e:
self.log_tool_call(tool_name, params, str(e), "error")
raise
Security guidelines
- Input validation: Validate all parameters (type, format, range).
- Injection protection: Prevent SQL injection, command injection, and code injection.
- Sandboxing: Use sandboxing for critical tools (code execution). See Sandboxing.
- Permissions: Apply least privilege to all tools. See Tool Permissions.
- Audit: Log all tool calls. See Audit Logging.
- Rate limiting: Set rate limits for external APIs.
Common Pitfalls
- No input validation: An agent can send arbitrary parameters. Always validate.
- String concatenation: For SQL and commands, use parameterized queries instead of string concatenation.
- Missing sandboxing: Critical tools like code execution without isolation are dangerous.
- Excessive permissions: Agents should not have access to every tool.
- No audit trail: Without logging, you won’t know what the agent actually did.
Further Reading
- MCP - Model Context Protocol.
- MCP Permissions - Access control.
- Building Custom MCP Tools - Creating tools.
- Tool Permissions - Authorization.
- Sandboxing - Isolation.
- Prompt Injection - Attack vectors.
- Audit Logging - Logging and tracking.
Key Takeaways:
- MCP security relies on input validation, permissions, sandboxing, and audit logging.
- Defend against injection attacks in SQL, commands, and code execution.
- Sandbox critical tools that execute code.
- Apply least privilege to all tools.
- Maintain an audit log for traceability.
FAQ
What is MCP security?
What are the main risks?
How do I protect my tools?
What is sandboxing?
How do I prevent injection attacks?
Why is audit logging important?
What is prompt injection?
What are the best practices?
References and Further Reading
- MCP - Model Context Protocol.
- OWASP - Security practices.
- Prompt Injection - Understanding attacks.


