MantaGet Started
Tutorial
March 12, 202614 min read

Building Secure MCP Servers: Best Practices

A developer's guide to implementing MCP servers that resist tool abuse and privilege escalation.

By Manta Security Research

Introduction

The Model Context Protocol (MCP) enables powerful AI agent capabilities, but with great power comes great responsibility. This guide covers security best practices for building MCP servers.

Principle 1: Never Trust LLM Input

The LLM is a conduit for potentially malicious user input. Every parameter passed to your tools should be validated.

āŒ Bad Example

tools: [{
  name: "read_file",
  execute: async ({ path }) => {
    return fs.readFileSync(path, 'utf-8'); // Dangerous!
  }
}]

āœ… Good Example

const ALLOWED_DIR = '/safe/directory';

tools: [{
  name: "read_file",
  execute: async ({ path }) => {
    const resolved = path.resolve(ALLOWED_DIR, path);
    if (!resolved.startsWith(ALLOWED_DIR)) {
      throw new Error("Access denied");
    }
    return fs.readFileSync(resolved, 'utf-8');
  }
}]

Principle 2: Least Privilege

Each tool should have the minimum permissions necessary.

  • File tools: Restrict to specific directories
  • Network tools: Allowlist domains
  • System tools: Avoid shell execution entirely if possible

Principle 3: Input Validation

For File Paths

  • Resolve to absolute paths
  • Check against allowlisted directories
  • Block path traversal sequences (../)

For URLs

  • Allowlist domains
  • Block internal IPs (10.x, 172.16.x, 192.168.x, 169.254.x)
  • Restrict protocols (https only)

For Commands

  • Use allowlists, not blocklists
  • Prefer APIs over shell execution
  • Never interpolate user input into commands

Principle 4: Rate Limiting

Prevent abuse with per-tool rate limits:

const rateLimiter = new Map();

function checkRateLimit(toolName, limit = 10, window = 60000) {
  const now = Date.now();
  const calls = rateLimiter.get(toolName) || [];
  const recent = calls.filter(t => t > now - window);
  
  if (recent.length >= limit) {
    throw new Error("Rate limit exceeded");
  }
  
  recent.push(now);
  rateLimiter.set(toolName, recent);
}

Principle 5: Audit Logging

Log every tool invocation for security monitoring:

function auditLog(tool, params, result, error) {
  console.log(JSON.stringify({
    timestamp: new Date().toISOString(),
    tool,
    params: sanitize(params),
    success: !error,
    error: error?.message
  }));
}

Testing Your MCP Server

Use Manta to scan for vulnerabilities:

$ manta scan ./my-mcp-server
šŸ” Scanning MCP server...
[!] CRITICAL: Command execution in shell_exec
[!] HIGH: Path traversal in read_file
āœ“ Scan complete — 2 vulnerabilities found

References

  1. Anthropic. (2024). MCP Specification
  2. OWASP. (2024). Secure Coding Practices

Ready to Secure Your AI Agents?

Scan your MCP servers for vulnerabilities with Manta.

Start Scanning