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.
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.
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