Post

Understanding MCP and AI-Powered Security Testing - A Practical Guide

Understanding MCP and AI-Powered Security Testing - A Practical Guide

Understanding MCP and AI-Powered Security Testing: A Practical Guide

What is the Model Context Protocol (MCP)?

The Model Context Protocol (MCP) is an open standard developed by Anthropic that enables AI applications to securely connect with external data sources and tools. Think of it as a standardized way for AI models like Claude to interact with your local tools, databases, and services.

Important: This guide focuses on the actual MCP protocol and its real-world applications in security testing, not fictional tools or packages.

How MCP Actually Works

Core Components

1. MCP Servers

  • Run locally or remotely
  • Expose tools and resources to AI models
  • Handle authentication and security
  • Provide structured data access

2. MCP Clients

  • AI applications that consume MCP services
  • Currently supported: Claude Desktop, some custom implementations
  • Send requests to MCP servers
  • Process responses from tools

3. The Protocol

  • JSON-RPC based communication
  • Standardized message formats
  • Built-in security and authentication
  • Tool discovery and capability negotiation

Real MCP Implementation for Security Testing

Setting Up Claude Desktop with MCP

Step 1: Install Claude Desktop

1
2
# Download from: https://claude.ai/download
# Available for Windows, macOS, and Linux

Step 2: Configure MCP Servers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Create Claude Desktop config directory
mkdir -p ~/.config/claude-desktop

# Create configuration file
cat > ~/.config/claude-desktop/claude_desktop_config.json << 'EOF'
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/directory"]
    },
    "brave-search": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-brave-search"],
      "env": {
        "BRAVE_API_KEY": "your-api-key-here"
      }
    }
  }
}
EOF

Building Custom Security Tools with MCP

Example: Network Scanner MCP Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env python3
"""
Custom MCP Server for Network Security Tools
Real implementation using the MCP SDK
"""

import asyncio
import subprocess
import json
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

# Initialize MCP server
server = Server("security-tools")

@server.list_tools()
async def list_tools():
    """List available security tools"""
    return [
        Tool(
            name="nmap_scan",
            description="Perform network scan using nmap",
            inputSchema={
                "type": "object",
                "properties": {
                    "target": {"type": "string", "description": "Target IP or hostname"},
                    "scan_type": {"type": "string", "enum": ["quick", "full", "stealth"], "default": "quick"}
                },
                "required": ["target"]
            }
        ),
        Tool(
            name="dns_lookup",
            description="Perform DNS lookup",
            inputSchema={
                "type": "object",
                "properties": {
                    "domain": {"type": "string", "description": "Domain to lookup"},
                    "record_type": {"type": "string", "enum": ["A", "AAAA", "MX", "TXT"], "default": "A"}
                },
                "required": ["domain"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    """Execute security tools"""
    
    if name == "nmap_scan":
        target = arguments["target"]
        scan_type = arguments.get("scan_type", "quick")
        
        # Define scan options
        scan_options = {
            "quick": ["-sS", "-T4", "-F"],
            "full": ["-sS", "-sV", "-sC", "-O", "-p-"],
            "stealth": ["-sS", "-T2", "-f"]
        }
        
        try:
            # Execute nmap scan
            cmd = ["nmap"] + scan_options[scan_type] + [target]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
            
            return [TextContent(
                type="text",
                text=f"Nmap scan results for {target}:\n\n{result.stdout}"
            )]
            
        except subprocess.TimeoutExpired:
            return [TextContent(type="text", text="Scan timed out")]
        except Exception as e:
            return [TextContent(type="text", text=f"Error: {str(e)}")]
    
    elif name == "dns_lookup":
        domain = arguments["domain"]
        record_type = arguments.get("record_type", "A")
        
        try:
            cmd = ["dig", "+short", domain, record_type]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            return [TextContent(
                type="text",
                text=f"DNS {record_type} records for {domain}:\n{result.stdout}"
            )]
            
        except Exception as e:
            return [TextContent(type="text", text=f"Error: {str(e)}")]
    
    else:
        return [TextContent(type="text", text=f"Unknown tool: {name}")]

async def main():
    """Run the MCP server"""
    async with stdio_server() as streams:
        await server.run(streams[0], streams[1])

if __name__ == "__main__":
    asyncio.run(main())

Running the Custom Server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Install MCP SDK
pip install mcp

# Make the server executable
chmod +x security_mcp_server.py

# Add to Claude Desktop config
{
  "mcpServers": {
    "security-tools": {
      "command": "python3",
      "args": ["/path/to/security_mcp_server.py"]
    }
  }
}

Practical Security Testing Workflows

1. Automated Reconnaissance

Claude Prompt:

1
2
3
4
5
Using the security tools MCP server, perform reconnaissance on the domain example.com:

1. Start with DNS lookups for A, MX, and TXT records
2. Perform a quick nmap scan on discovered IPs
3. Analyze the results and suggest next steps

What Happens:

  1. Claude calls the dns_lookup tool multiple times
  2. Extracts IP addresses from DNS results
  3. Calls nmap_scan tool on discovered IPs
  4. Analyzes results and provides recommendations

2. Vulnerability Assessment Pipeline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Extended MCP server with vulnerability scanning
@server.list_tools()
async def list_tools():
    return [
        # ... previous tools ...
        Tool(
            name="nuclei_scan",
            description="Run Nuclei vulnerability scanner",
            inputSchema={
                "type": "object",
                "properties": {
                    "target": {"type": "string"},
                    "templates": {"type": "string", "default": "cves,exposures"}
                },
                "required": ["target"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    # ... previous implementations ...
    
    if name == "nuclei_scan":
        target = arguments["target"]
        templates = arguments.get("templates", "cves,exposures")
        
        try:
            cmd = ["nuclei", "-u", target, "-t", templates, "-json"]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
            
            # Parse JSON results
            vulnerabilities = []
            for line in result.stdout.strip().split('\n'):
                if line:
                    vuln = json.loads(line)
                    vulnerabilities.append({
                        "template": vuln.get("template-id"),
                        "severity": vuln.get("info", {}).get("severity"),
                        "url": vuln.get("matched-at")
                    })
            
            return [TextContent(
                type="text",
                text=f"Found {len(vulnerabilities)} potential vulnerabilities:\n" + 
                     json.dumps(vulnerabilities, indent=2)
            )]
            
        except Exception as e:
            return [TextContent(type="text", text=f"Error: {str(e)}")]

Real-World MCP Servers for Security

Available Community Servers

1. Filesystem Server

1
2
# Access local files securely
npx @modelcontextprotocol/server-filesystem /path/to/security/reports

2. Database Server

1
2
# Query security databases
npx @modelcontextprotocol/server-sqlite /path/to/vulnerability.db

3. Web Search Server

1
2
# OSINT and threat intelligence
npx @modelcontextprotocol/server-brave-search

Building Your Security MCP Ecosystem

Directory Structure:

1
2
3
4
5
6
7
8
9
security-mcp/
├── servers/
│   ├── network-scanner.py
│   ├── vuln-scanner.py
│   └── osint-tools.py
├── configs/
│   └── claude-desktop-config.json
└── scripts/
    └── setup.sh

Setup Script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# setup.sh - Security MCP Environment Setup

echo "Setting up Security MCP Environment..."

# Install required tools
sudo apt update
sudo apt install nmap nuclei dig whois curl -y

# Install Python dependencies
pip install mcp asyncio subprocess

# Create config directory
mkdir -p ~/.config/claude-desktop

# Copy configuration
cp configs/claude-desktop-config.json ~/.config/claude-desktop/

# Make servers executable
chmod +x servers/*.py

echo "Setup complete! Restart Claude Desktop to load MCP servers."

Security Considerations

Authentication and Authorization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Add authentication to MCP server
import hashlib
import hmac

class SecureMCPServer:
    def __init__(self, api_key: str):
        self.api_key = api_key
    
    def verify_request(self, request_data: str, signature: str) -> bool:
        """Verify request signature"""
        expected = hmac.new(
            self.api_key.encode(),
            request_data.encode(),
            hashlib.sha256
        ).hexdigest()
        return hmac.compare_digest(expected, signature)

Rate Limiting and Safety

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import time
from collections import defaultdict

class RateLimiter:
    def __init__(self, max_requests: int = 10, window: int = 60):
        self.max_requests = max_requests
        self.window = window
        self.requests = defaultdict(list)
    
    def allow_request(self, client_id: str) -> bool:
        now = time.time()
        client_requests = self.requests[client_id]
        
        # Remove old requests
        client_requests[:] = [req for req in client_requests if now - req < self.window]
        
        if len(client_requests) >= self.max_requests:
            return False
        
        client_requests.append(now)
        return True

Best Practices

1. Tool Validation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def validate_target(target: str) -> bool:
    """Validate scan targets to prevent abuse"""
    import ipaddress
    import re
    
    # Block private networks in production
    try:
        ip = ipaddress.ip_address(target)
        if ip.is_private:
            return False
    except ValueError:
        # Domain name validation
        if not re.match(r'^[a-zA-Z0-9.-]+$', target):
            return False
    
    return True

2. Logging and Auditing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import logging

# Configure security logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('/var/log/mcp-security.log'),
        logging.StreamHandler()
    ]
)

logger = logging.getLogger('mcp-security')

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    logger.info(f"Tool called: {name} with args: {arguments}")
    # ... tool implementation ...

3. Error Handling

1
2
3
4
5
6
7
8
9
10
11
12
13
async def safe_tool_execution(tool_func, *args, **kwargs):
    """Safely execute tools with proper error handling"""
    try:
        return await tool_func(*args, **kwargs)
    except subprocess.TimeoutExpired:
        logger.warning(f"Tool execution timed out: {tool_func.__name__}")
        return [TextContent(type="text", text="Operation timed out")]
    except PermissionError:
        logger.error(f"Permission denied: {tool_func.__name__}")
        return [TextContent(type="text", text="Permission denied")]
    except Exception as e:
        logger.error(f"Tool execution failed: {e}")
        return [TextContent(type="text", text=f"Error: {str(e)}")]

Getting Started Checklist

  • Install Claude Desktop
  • Set up basic MCP configuration
  • Install security tools (nmap, nuclei, etc.)
  • Create custom MCP server for security tools
  • Test basic functionality
  • Implement security controls (auth, rate limiting)
  • Set up logging and monitoring
  • Document your MCP security workflow

Conclusion

MCP represents a powerful way to integrate AI with security tools, but it requires careful implementation. Focus on:

  1. Real implementations using the actual MCP protocol
  2. Security-first design with proper authentication and validation
  3. Practical workflows that enhance rather than replace human expertise
  4. Responsible disclosure and ethical testing practices

The future of AI-powered security testing lies in thoughtful integration of human intelligence with automated tools, and MCP provides a solid foundation for building these capabilities.

Resources

  • MCP Specification: https://spec.modelcontextprotocol.io/
  • MCP GitHub: https://github.com/modelcontextprotocol
  • Claude Desktop: https://claude.ai/download
  • Community Servers: https://github.com/modelcontextprotocol/servers
  • MCP Python SDK: https://pypi.org/project/mcp/
This post is licensed under CC BY 4.0 by the author.