Skip to main content
  1. Blog/

Building an MCP Server for AI-Powered Pentesting in Natural Language

Introduction

Remembering every tool, command, and capability within Kali Linux can be a challenge, therefore pentesters often rely on their personal cheat sheets accumulated throughout their careers. However, successful pentesting isn’t about memorizing commands - it’s about performing tasks and obtaining specific information.

Using AI and Large Language Models (LLMs) can simplify this process dramatically. By using Anthropic’s MCP (Master Control Program) protocol, it is possible to seamlessly integrate AI with pentesting tools, for executing complex commands in natural language — no memorization required.

Visualization of the architecture

In this post, I’ll show how to set up an MCP server to control Kali Linux’s pentesting tools using simple, natural language commands.

What is MCP?

MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.

Screenshot of Claude Desktop showing the results of an nmap scan that was executed using natural language.

Core Components

MCP Framework

The MCP framework allows you to define and expose tools or commands as functions. AI agents can discover these tools and execute them based on natural language requests. I’ll use the lightweight FastMCP implementation to build a basic MCP server for interacting with Kali Linux.

Python Server

A Python script is the core of the system. It initializes the MCP server, defines specific pentesting tools as callable functions, and manages their execution.

Docker

I use Docker and Docker Compose to containerize the MCP server and Kali Linux, ensuring consistency across environments and easy dependency management. The Dockerfile defines the build process, while docker-compose.yml simplifies deployment and management.

Dockerfile Setup

Below is a Dockerfile that provides a ready-to-use Kali Linux environment equipped with essential pentesting tools:

FROM kalilinux/kali-rolling:latest
ARG DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    python3 \
    python3-pip \
    python3-dev \
    python3-venv \
    build-essential \
    libssl-dev \
    libffi-dev \
    nmap \
    gobuster \
    && apt-get clean && \
    rm -rf /var/lib/apt/lists/*

RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

WORKDIR /app
RUN pip install --no-cache-dir mcp
COPY security_tools_server.py /app/
RUN chmod +x /app/security_tools_server.py

CMD ["python", "/app/security_tools_server.py"]

Docker Compose Configuration

To deploy the container I use a simple Docker Compoes file:

version: '3'

services:
  security-tools-mcp:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: security-tools-mcp
    restart: unless-stopped
    # Mount any additional wordlists or directories if needed
    # volumes:
    #   - ./wordlists:/opt/wordlists

Python Script

Here’s how to define and expose pentesting tools like Nmap and Gobuster via MCP:

from mcp.server.fastmcp import FastMCP, Context
import subprocess
import shlex
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("security-tools-mcp")

# Create the MCP server
mcp = FastMCP("SecurityTools")

@mcp.tool()
def run_nmap(target: str, options: str = "-sV") -> str:
    """Run nmap scan on a target.
    
    Args:
        target: Target IP address or hostname
        options: Nmap scan options (default: -sV for service/version detection)
    """
    logger.info(f"Running nmap scan on {target} with options: {options}")
    
    # Validate input
    if not validate_input(target) or not validate_options(options):
        return "Invalid input. Please provide a valid target IP, hostname, or subnet."
    
    # Construct and execute the command
    try:
        cmd = f"nmap {options} {target}"
        logger.info(f"Executing command: {cmd}")
        result = subprocess.run(
            shlex.split(cmd),
            capture_output=True,
            text=True,
            check=False,
            timeout=300  # 5 minute timeout
        )
        
        if result.returncode != 0:
            logger.error(f"nmap error: {result.stderr}")
            return f"Error running nmap: {result.stderr}"
        
        return result.stdout
    except subprocess.TimeoutExpired:
        return "Nmap scan timed out after 5 minutes"
    except Exception as e:
        logger.error(f"Error executing nmap: {str(e)}")
        return f"Error executing nmap: {str(e)}"

@mcp.tool()
def run_gobuster(target: str, wordlist: str = "/usr/share/wordlists/dirb/common.txt", options: str = "-q") -> str:
    """Run gobuster directory scan on a target.
    
    Args:
        target: Target URL (e.g., http://example.com)
        wordlist: Path to wordlist file (default: common.txt from dirb)
        options: Additional gobuster options (default: -q for quiet mode)
    """
    logger.info(f"Running gobuster on {target} with wordlist: {wordlist}")
    
    # Validate input 
    if not validate_input(target) or not validate_options(options) or not validate_wordlist(wordlist):
        return "Invalid input. Please check your parameters."
    
    # Construct and execute the command
    try:
        cmd = f"gobuster dir -u {target} -w {wordlist} {options}"
        logger.info(f"Executing command: {cmd}")
        result = subprocess.run(
            shlex.split(cmd),
            capture_output=True,
            text=True,
            check=False,
            timeout=300  # 5 minute timeout
        )
        
        if result.returncode != 0 and "Error:" in result.stderr:
            logger.error(f"gobuster error: {result.stderr}")
            return f"Error running gobuster: {result.stderr}"
        
        output = result.stdout if result.stdout else "No results found."
        return output
    except subprocess.TimeoutExpired:
        return "Gobuster scan timed out after 5 minutes"
    except Exception as e:
        logger.error(f"Error executing gobuster: {str(e)}")
        return f"Error executing gobuster: {str(e)}"

def validate_input(input_str: str) -> bool:
    """Basic validation to help prevent command injection"""
    dangerous_chars = [';', '&', '|', '>', '<', '`', '$', '(', ')', '{', '}', '\\']
    return not any(char in input_str for char in dangerous_chars)

def validate_options(options: str) -> bool:
    """Validate command-line options"""
    dangerous_chars = [';', '&', '|', '>', '<', '`', '$', '(', ')', '{', '}', '\\']
    return not any(char in options for char in dangerous_chars)

def validate_wordlist(wordlist: str) -> bool:
    """Validate wordlist path"""
    # Only allow wordlists in specific directories
    allowed_prefixes = ["/usr/share/wordlists/", "/opt/wordlists/"]
    dangerous_chars = [';', '&', '|', '>', '<', '`', '$', '(', ')', '{', '}', '\\']
    
    return (
        any(wordlist.startswith(prefix) for prefix in allowed_prefixes) and
        not any(char in wordlist for char in dangerous_chars)
    )

if __name__ == "__main__":
    logger.info("Starting MCP Security Tools Server")
    mcp.run(transport='stdio')

Conclusion

With the MCP server running, AI can now seamlessly interact with pentesting tools using natural language. You no longer need extensive cheat sheets or command memorization—just describe your tasks plainly, and let AI-driven MCP do the rest.

This will change pentesting dramatically. It will become more task focused instead of tool focues. No need for complex and messy cheatsheets anymore. Tell the AI what you want to achieve and it will perform the task for you and even explain the result. I guess it’s just a matter of time until Offsec implements an MCP server into Kali Linux by default.

But not only pentesting will change forever, also attackers will leverage MCPs heavily. If they put in some offorts into their infrastructure and the creation of complex MCP systems, their capabilities will grow dramatically. Targeting te CEO of a company? Just ask the AI to attack them. The AI could perform an OSINT research, attack and navigate the companies infrastructure and run social engineering attacks all at the same time at endless scale. Defenders should buckle up, there are interesting times ahead…

If you want to try the MCP server yourself, heres the link to the source code:

GitHub repository
Lars Ursprung
Author
Lars Ursprung