Skip to content
BotServBotServ
MCPSecurityInjectionSandboxingValidation

MCP Security: Integrate Tools Safely

MCP security for AI agents. Tool validation, injection protection, sandboxing and best practices.

S

schutzgeist

5 min read
MCP Security: Integrate Tools Safely

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

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?

Security measures for MCP tools: input validation, permissions, sandboxing, injection protection, and audit logging. These prevent misuse and unauthorized access.

What are the main risks?

Prompt injection (agent executing malicious commands), SQL injection, command injection, data exfiltration, and unauthorized system access.

How do I protect my tools?

Input validation (type, format, injection patterns), permissions (least privilege), sandboxing (isolation), and audit logging (traceability).

What is sandboxing?

Isolation for critical tools: Docker containers, no network access, memory and CPU limits. Essential for code execution or critical system calls.

How do I prevent injection attacks?

For SQL: use parameterized queries. For commands: whitelist allowed commands and sanitize input. For code: avoid eval/exec and use sandboxing.

Why is audit logging important?

For traceability: who used which tool, when, and with what parameters? In case of attacks or errors, you can trace exactly what happened.

What is prompt injection?

An attack where an agent is manipulated into performing harmful actions. Prevent it through input validation, permissions, and sandboxing.

What are the best practices?

Least privilege, input validation, sandboxing for critical tools, audit logging, rate limiting, and regular security reviews.

References and Further Reading

Back to Blog
Share:

Related Posts