Control Kali Linux with AI — Claude Code MCP Setup 2026

·

The Model Context Protocol (MCP) turned the phrase "control Kali with AI" from a demo trick into a repeatable, auditable workflow. Instead of copy-pasting commands into a chat window, you register your security tools as MCP servers, and Claude Code calls them as structured, permission-gated functions — with the output flowing straight back into the agent's reasoning.

This guide covers three install paths (native on Kali, Docker, and WSL2), the exact configuration files and commands, how to build your own Python MCP server that wraps a scanner, and — critically — how to lock the whole thing down so the agent can only touch assets you have authorised. Everything here assumes lab or authorised engagement use only.

◈ Table of Contents

01 What MCP-Driven Control Is 02 Prerequisites & Requirements 03 Method 1 — Native on Kali 04 Method 2 — Docker 05 Method 3 — WSL2 / VM 06 Initial Configuration 07 Core Configuration 08 Integration & Reporting 09 Advanced — Custom MCP Server 10 Maintenance & Troubleshooting 11 Sources & References
🧠

01 · What MCP-Driven Kali Control Actually Is

why it matters

The Model Context Protocol is an open standard for connecting AI assistants to external tools and data through a uniform client/server interface. Claude Code — Anthropic's command-line coding and automation agent — acts as the MCP client. Each tool you expose (a port scanner, a fuzzer, a notes database) runs as an MCP server. When you ask the agent to "enumerate the web ports on the lab host", it does not guess a shell string; it selects a declared tool, fills in typed parameters, and the server returns structured output the model can reason over.

For a security practitioner, that distinction is the whole point. A raw "let the AI run bash" setup is fast but opaque and dangerous. An MCP setup gives you a typed contract per tool, per-tool permission prompts, an audit trail of exactly which tool ran with which arguments, and the ability to keep credentials and scope enforcement on the server side where the model can never see or bypass them.

MCP servers reach the client over one of three transports, and the one you pick shapes the rest of your setup. STDIO is the default and simplest: the client launches the server as a child process and they talk over standard input and output. It is perfect for a server that lives on the same host as Claude Code, which covers the native and Docker paths in this guide. SSE (server-sent events) and streamable HTTP are network transports — you register the server by URL instead of by launch command, which is what you want when the tools run on a separate box or you need multiple clients to share one server. Most single-analyst labs never need anything beyond STDIO; reach for the HTTP transports only when the topology demands it.

TransportHow you register itBest for
STDIOclaude mcp add name -- cmdServer on the same host (native, Docker) — the default
SSE--transport sse name urlRemote server, streaming, shared by clients
HTTP--transport http name urlRemote server behind a normal HTTP endpoint

It helps to be precise about what "the AI controls Kali" means here, because the phrase invites the wrong mental model. The model never gets a shell. It emits a request to call a named tool with named arguments; the server decides whether that request is legal, runs the underlying binary if so, and returns the result. Every decision that actually matters — what a tool can do, which targets it will accept, what happens to the output — is code you write and control, not behaviour the model improvises. That is why this approach is safe enough to recommend for authorised testing while "pipe the model into bash" is not.

MCP request flow: prompt → tool selection → server-side validation → binary → structured result
🔍

Guided Recon

Describe a scope in plain English; the agent runs discovery in the right order and summarises live hosts, open ports and service banners.

📝

Report Drafting

Tool output feeds straight into the model, so a first-pass findings write-up is generated alongside the raw evidence.

🧩

Tool Orchestration

Chain nmap → nuclei → ffuf with the model deciding follow-ups, while every call stays typed and logged.

🎓

Learning Aid

Ask why a flag was chosen or what a banner implies — the agent explains as it works, useful for OSCP-style practice labs.

AUTHORISATION IS NON-NEGOTIABLE. Running scanners against systems you do not own or lack written permission to test is illegal in most jurisdictions. Restrict every setup in this guide to your own lab (Metasploitable, DVWA, a VulnHub box) or an engagement with a signed scope.

📋

02 · Prerequisites & Requirements

before you start

You need a working Kali install, a modern Node.js runtime for Claude Code, Python 3.11+ for the custom server later, and either a Claude subscription (Pro or Max, which entitle Claude Code use) or an Anthropic API key. The table below is the baseline for a comfortable lab.

A quick word on the auth choice, because it trips people up. A Pro or Max subscription lets you use Claude Code through an interactive browser login and is the right call for hands-on lab work — you get a flat monthly cost and no token accounting to think about. An API key, set through the ANTHROPIC_API_KEY environment variable, is metered per token and suits automation or CI-style runs where no human is present to click a login prompt. You do not need both; pick the one that matches how you will actually drive the agent. Either way the default model is Opus 4.8, and you do not have to configure it explicitly.

ComponentRequirementNotes
OSKali Linux 2026.x (rolling)Bare metal, VM, or WSL2 all work
CPU / RAM2 vCPU / 4 GB MIN   4 vCPU / 8 GB RECScanners are the heavy part, not the agent
Disk25 GB freeKali tools + Node + Docker images
Node.js18 LTS or newer (20/22 preferred)Required by Claude Code
Python3.11+For the custom MCP server in Phase 9
AuthClaude Pro/Max or Anthropic API keyAPI key set via ANTHROPIC_API_KEY
NetworkIsolated lab segmentKeep targets off production VLANs
1
Confirm your Kali build
verify

Know exactly what you are on before layering software over it — version drift is a common source of package conflicts.

# Confirm your Kali version and kernel $ cat /etc/os-release | grep -E "VERSION|PRETTY" $ uname -r
2
Update before you install
baseline

A stale rolling release causes dependency conflicts the moment you add Node or Docker. Bring the box current first.

# Update the box first — a stale rolling release causes package conflicts $ sudo apt update && sudo apt full-upgrade -y

PRO TIP: Snapshot the VM (or the WSL2 distro export) before installing anything. If an agent-run command misbehaves in your lab, a two-minute rollback beats an afternoon of cleanup.

🖥️

03 · Method 1 — Native Install on Kali

recommended for labs

The native path runs Claude Code directly on Kali so the agent shares the same filesystem and tool binaries. This is the simplest setup and the one most people want. Before you commit, the table below compares the three install methods so you can pick by your constraints rather than by habit.

MethodIsolationSetup effortPick it when
Native (Phase 3)LowLowestDedicated Kali lab VM you can snapshot
Docker (Phase 4)HighMediumYou want disposable, reproducible tool sandboxes
WSL2 / remote (Phase 5)MediumMediumWindows workstation, or Kali on a separate box
1
Install a modern Node.js
runtime

Kali's default Node can lag behind. Use nvm so you control the version without fighting apt.

# Install nvm, then a current LTS Node $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash $ source ~/.bashrc $ nvm install --lts && nvm use --lts $ node -v && npm -v
2
Install Claude Code
agent

Install the CLI globally, then confirm it resolves on your PATH.

$ npm install -g @anthropic-ai/claude-code $ claude --version $ which claude

Do NOT run npm install -g with sudo. A root-owned global npm prefix is the #1 cause of "permission denied" errors on later updates. If you skipped nvm, set a user-writable prefix with npm config set prefix ~/.npm-global and add it to PATH.

3
Authenticate
auth

Launch Claude Code in your working directory and log in. Subscription users authenticate in the browser; API users export a key instead.

# Subscription (Pro/Max) — interactive login $ mkdir -p ~/engagements/lab01 && cd ~/engagements/lab01 $ claude # then type /login and follow the browser flow
# API key alternative (put this in ~/.bashrc for persistence) $ export ANTHROPIC_API_KEY="sk-ant-..." $ claude
4
Register your first MCP server
mcp

Add a server with claude mcp add. Everything after the -- is the command that launches the server. Here we add the reference filesystem server as a smoke test before wiring in security tools.

# Syntax: claude mcp add [--scope local|project|user] <name> -- <command> [args...] $ claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem ~/engagements $ claude mcp list $ claude mcp get filesystem
Working when
  • claude mcp list shows the server with a "connected" status
  • Running /mcp inside a session lists the server and its tools
  • No red "failed to connect" line in the startup banner

PRO TIP: Use --scope project when you want the server config committed to a repo (it writes .mcp.json), --scope user for servers you want in every project, and the default local for one-off experiments that stay private to the current directory.

🐳

04 · Method 2 — Docker Deployment

isolation + repeatability

Containerising the security tooling gives you a disposable, reproducible sandbox: the agent talks to a Kali-tools container over MCP, and if a scan wedges the box you just recreate it. The pattern below keeps Claude Code on the host and runs the MCP server plus tools inside the container.

1
Install Docker Engine on Kali
engine
$ sudo apt install -y docker.io docker-compose-v2 $ sudo systemctl enable --now docker $ sudo usermod -aG docker $USER # log out/in to apply $ docker run --rm hello-world
2
Build the tools image
dockerfile

Base off the official Kali rolling image, add the scanners you want the agent to reach, and install the Python MCP SDK. Save this as Dockerfile.

FROM kalilinux/kali-rolling RUN apt-get update && apt-get install -y \ nmap nuclei ffuf whatweb python3 python3-pip python3-venv \ && rm -rf /var/lib/apt/lists/* RUN python3 -m venv /opt/mcp && /opt/mcp/bin/pip install "mcp[cli]" COPY kali_mcp_server.py /opt/kali_mcp_server.py ENV PATH="/opt/mcp/bin:$PATH" ENTRYPOINT ["python3", "/opt/kali_mcp_server.py"]

The kali_mcp_server.py file referenced here is the one you build in Phase 9. Keep it in the same directory as the Dockerfile.

3
Compose file
compose

A minimal docker-compose.yml. The container joins a dedicated lab network and mounts a shared output directory so results land on the host.

services: kali-mcp: build: . container_name: kali-mcp stdin_open: true # keep STDIO open for MCP transport tty: true networks: [labnet] volumes: - ./loot:/loot:rw cap_drop: ["ALL"] cap_add: ["NET_RAW", "NET_ADMIN"] # nmap SYN scans need raw sockets networks: labnet: driver: bridge
$ docker compose build $ mkdir -p loot $ docker compose run --rm kali-mcp --help # sanity check the entrypoint
4
Point Claude Code at the container
wire-up

Register an MCP server whose launch command runs the container over STDIO. Claude Code starts the container on demand and speaks MCP through it.

$ claude mcp add kali-docker -- docker compose run --rm -T kali-mcp $ claude mcp list

cap_drop: ALL then re-adding only NET_RAW/NET_ADMIN is deliberate. Never run the tools container with --privileged — it hands the agent a path to the host kernel. If a tool complains it needs more, add the single capability it names, not the blanket flag.

🪟

05 · Method 3 — WSL2 / VM Setup

windows & remote

Many analysts drive Kali from a Windows workstation via WSL2, or keep Kali on a remote VM and connect over SSH. Both work; the only wrinkle is where Claude Code runs and how it reaches the tools.

A
Kali on WSL2
windows

Install the Kali distro under WSL2, then treat the WSL shell exactly like the native path in Phase 3 — Node, Claude Code and MCP servers all run inside the Linux userland.

# From an elevated PowerShell on the host PS> wsl --install -d kali-linux PS> wsl --set-default-version 2 PS> wsl -d kali-linux
# Now inside the Kali WSL shell — same as native install $ sudo apt update && sudo apt install -y kali-linux-headless $ npm install -g @anthropic-ai/claude-code

Raw-socket scans (nmap -sS) can behave oddly under WSL2's virtualised network stack. If SYN scans hang, fall back to a TCP connect scan (-sT) or run the tools in a proper Kali VM for anything network-timing sensitive.

B
Remote Kali VM over SSH
remote

Keep Claude Code on your laptop but run the MCP server on a remote Kali box. Wrap the launch command in SSH so the server process lives on the VM.

# Server binary lives on the remote box; SSH is just the transport $ claude mcp add kali-remote -- ssh [email protected] python3 /opt/kali_mcp_server.py $ claude mcp get kali-remote

PRO TIP: Use an SSH key with a dedicated, low-privilege account on the VM and lock that key to the single command with command= in authorized_keys. The agent then cannot use the SSH channel for anything except launching the MCP server.

A third remote option is a network transport instead of STDIO. If your server speaks HTTP or SSE, register it by URL rather than by command:

$ claude mcp add --transport sse kali-sse http://10.10.0.20:8009/sse $ claude mcp add --transport http kali-http http://10.10.0.20:8009/mcp
⚙️

06 · Initial Configuration & First Run

first launch

With at least one MCP server registered, start a session and confirm the agent can see the tools. The /mcp slash command is your health check inside Claude Code.

1
Launch and verify
health check

Start a session in the engagement directory, then use the built-in slash commands to confirm servers and auth are healthy.

$ cd ~/engagements/lab01 && claude # inside the session: > /mcp # lists connected servers and their tools > /status # shows model, working dir, auth state
2
Understand the config layers
scopes

Config is layered, and understanding the layers saves hours of confusion later. Server registrations resolve from three scopes in order of increasing reach: local (private to the current directory), project (written to .mcp.json, meant to be committed), and user (available in every project). When the same name exists in more than one scope, the narrower scope wins. Behaviour and permissions are separate and live in settings.json under .claude/. Keep servers in one file and permissions in another.

# Project-scoped server list (created by --scope project) $ cat .mcp.json

Keep the core claude mcp subcommands handy — these five cover almost everything you do with servers.

CommandWhat it does
claude mcp addRegister a server (append --transport and --scope as needed)
claude mcp listShow every registered server and its connection status
claude mcp get <name>Print one server's launch command and config
claude mcp remove <name>Unregister a server you no longer trust or need
/mcp (in session)List connected servers and the tools they expose
3
Write a minimal .mcp.json
project config

If you prefer editing the file by hand to running claude mcp add, this is the shape a project-scoped registration takes.

# A minimal .mcp.json for the container server { "mcpServers": { "kali-docker": { "command": "docker", "args": ["compose", "run", "--rm", "-T", "kali-mcp"] } } }

PRO TIP: Commit .mcp.json to your engagement repo but keep secrets out of it. Reference environment variables (for example an API token the server needs) rather than hardcoding values, so the file is safe to share with teammates.

🔧

07 · Core Configuration — Wiring Tools Through MCP

the settings that matter

This is the phase that separates a toy from a controlled setup. The two levers that matter most are permissions (which tools run without asking) and scope (what the tools are allowed to touch). Get these right before you let the agent loose.

Permission tierBehaviourUse for
allowRuns with no promptRead-only, non-network tools (banner grab, local parse)
askPrompts every timeAnything that touches the network (scanners, fuzzers)
denyBlocked outrightDestructive or exfil-shaped commands (rm, curl)
1
Permission model
safety

By default Claude Code prompts before running an MCP tool. You can pre-approve specific tools in settings.json to reduce friction — but only the read-only, safe ones. Keep anything that touches the network on a manual prompt at first.

# .claude/settings.json — allow one MCP tool, prompt for the rest { "permissions": { "allow": ["mcp__kali-docker__whatweb_scan"], "ask": ["mcp__kali-docker__nmap_scan"], "deny": ["Bash(rm*)", "Bash(curl*)"] } }

MCP tool permission keys follow the pattern mcp__<server>__<tool>. Naming the exact tool is far safer than a broad wildcard.

2
Scope enforcement lives on the server
boundary

Never trust the model to "remember the scope". Enforce the allowed target range inside the MCP server so an out-of-scope argument is rejected before any binary runs. You will implement exactly this check in Phase 9.

The single most important control in this whole guide: the server must validate every target against an allowlist and refuse anything outside it. A prompt-side instruction ("only scan 10.10.0.0/24") is a suggestion; a server-side check is a boundary.

3
Project context with CLAUDE.md
memory

Drop a CLAUDE.md in the engagement directory. Claude Code reads it automatically at session start — use it to record the authorised scope, the rules of engagement and preferred tools, so you are not re-typing them each session.

$ cat > CLAUDE.md <<'EOF' # Lab01 Engagement Authorised scope: 10.10.0.0/24 ONLY. Never scan outside it. Preferred tools: nmap for ports, nuclei for templates, ffuf for content. Save all output to ./loot/ with a timestamped filename. EOF

PRO TIP: Fast mode (toggle with /fast) runs the same Opus 4.8 model with faster output — handy during interactive recon when you want quick tool-call turnaround without downgrading the model.

🔗

08 · Integration — Workflow, Scoping & Reporting

day-to-day use

Once tools are wired and permissioned, the workflow becomes conversational. You describe intent; the agent selects tools, runs them within the server-enforced scope, and writes structured output you can review and turn into a report.

1
Drive recon by intent
workflow

State the goal in plain language and gate each network action. The agent selects tools; the server keeps them in scope.

# Example session — the agent chooses tools, you approve network actions > Enumerate live hosts and open web ports in the authorised lab range, then flag anything running an outdated server banner. # Claude Code proposes an nmap_scan tool call; you approve; results return # structured, and the agent summarises the interesting findings.
🎯

Scope-first prompts

Reference the range in CLAUDE.md; the server rejects anything outside it regardless of prompt wording.

🧾

Evidence to loot/

Have every tool write raw output to a mounted directory so findings are backed by artefacts, not just chat text.

📊

Draft findings

Ask the agent to produce a findings table from the collected output — a first draft you then verify by hand.

🔁

Chained follow-ups

Let the model propose the next tool (ports → templates → content discovery) while you gate each network action.

The workflow that scales best is a tight loop: state intent, review the proposed tool call, approve or refuse, read the structured result, and let the agent suggest the next step. Because the model sees the tool output in its own context, it can spot a follow-up you might miss — an open management port that warrants a template scan, a redirect that hints at a virtual host worth fuzzing. Your job shifts from typing commands to gating decisions and sanity-checking conclusions, which is exactly where a human adds the most value on an engagement.

2
Archive the evidence
audit

Pull the tool-call history and archive it with the loot. Because every MCP call is structured, you can tie a finding back to the exact command and arguments that produced it — the auditability that raw-bash AI setups lack.

# Timestamp and archive the run's evidence $ tar czf loot/lab01-$(date +%Y%m%d-%H%M).tgz loot/*.txt loot/*.json

Treat AI-drafted findings as a first pass, never a final report. The agent can misread a banner or over-state severity. Every finding needs human verification before it reaches a client deliverable.

🧬

09 · Advanced — Build a Custom Kali MCP Server

power users

The real leverage comes from your own MCP server that exposes exactly the tools you want, with scope validation baked in. The official Python SDK (mcp[cli], which bundles FastMCP) makes this short. Below is a complete, minimal server that wraps nmap and enforces an allowlist.

1
Install the MCP SDK
setup

Work in a virtualenv so the SDK stays isolated from Kali's system Python.

# Install the SDK into a venv $ python3 -m venv .venv && source .venv/bin/activate $ pip install "mcp[cli]"
2
Write the scoped server
code

Save this as kali_mcp_server.py. It declares one tool, validates every target against an allowlist, and never touches a shell.

# kali_mcp_server.py — scoped nmap wrapper import ipaddress, shlex, subprocess from mcp.server.fastmcp import FastMCP mcp = FastMCP("kali-tools") # Server-side scope allowlist — the model cannot bypass this ALLOWED = [ipaddress.ip_network("10.10.0.0/24")] def _in_scope(target: str) -> bool: try: ip = ipaddress.ip_address(target) except ValueError: return False return any(ip in net for net in ALLOWED) @mcp.tool() def nmap_scan(target: str, ports: str = "1-1024") -> str: """Run a TCP connect scan against an in-scope IP. Returns raw nmap output.""" if not _in_scope(target): return f"REFUSED: {target} is outside the authorised scope." cmd = ["nmap", "-sT", "-Pn", "-p", ports, target] out = subprocess.run(cmd, capture_output=True, text=True, timeout=300) return out.stdout or out.stderr if __name__ == "__main__": mcp.run() # STDIO transport by default

Two design choices carry most of the safety. First, the scope allowlist is a module-level constant the model cannot reach or rewrite — a target outside 10.10.0.0/24 is refused before nmap is invoked. Second, the command is assembled as a list and handed to subprocess.run with no shell, so a crafted target string cannot break out into arbitrary command execution. Extending the server means adding more @mcp.tool() functions of the same shape: validate inputs, build an argument list, cap the runtime, return the output.

3
Register and test
wire-up

Register the server exactly like any other, then confirm the tool appears inside a session.

$ claude mcp add kali-tools -- python3 /full/path/to/kali_mcp_server.py $ claude > /mcp # confirm kali-tools and its nmap_scan tool appear
4
Harden before you rely on it
safety

Run through this checklist for every tool you add. A server is only as safe as its least-checked tool.

Hardened server checklist
  • Every tool validates its target against the ALLOWED allowlist first
  • Arguments are passed as a list (no shell string interpolation)
  • A timeout caps every subprocess so a hung scan can't wedge the server
  • The tool docstring describes intent so the model calls it correctly
  • Sensitive tools stay on the permission "ask" list, never "allow"

Build commands as argument lists (["nmap", "-sT", ...]), never with shell=True and string concatenation. Passing model-supplied text into a shell is a command-injection sink — the exact class of bug you are paid to find in other people's code.

PRO TIP: Add one tool at a time and test each before exposing the next. A server that quietly exposes ten tools is ten times harder to reason about when the agent picks the wrong one.

🩺

10 · Monitoring, Maintenance & Troubleshooting

keep it running

MCP failures are almost always one of a handful of things: a server that won't launch, a transport mismatch, a permission wall, or a stale binary. Start with the built-in diagnostics, then work the table.

1
Run the built-in diagnostics
triage

First stop for any "tool not available" problem — confirm the server is registered, see its exact launch command, then get verbose startup output.

$ claude mcp list # is the server even registered? $ claude mcp get kali-tools # shows the exact launch command $ claude --debug # verbose startup, prints connection errors
2
Launch the server by hand
isolate

If the diagnostics say a server failed to connect, run its launch command directly. A broken import or syntax error surfaces here in plain text instead of being swallowed by the client.

# Launch the server by hand to see its real error output $ python3 /full/path/to/kali_mcp_server.py # a broken import or syntax error surfaces here immediately
SymptomLikely causeFix
Server shows "failed to connect"Launch command wrong or binary missingRun the command from mcp get manually; fix the path or install the missing dependency
Tools never appear in /mcpServer started but registered no toolsCheck the @mcp.tool() decorators and that mcp.run() is reached
"permission denied" on npm -gRoot-owned global prefixReinstall via nvm, or set a user-writable npm prefix — never sudo
Docker server hangs at startMissing -T / no STDIOAdd -T to docker compose run and stdin_open: true in compose
nmap SYN scan failsNo raw-socket capabilityAdd NET_RAW in compose, or use -sT connect scan (esp. under WSL2)
Agent scans out of scopeScope only in the promptEnforce the allowlist in the server code (Phase 9), not in prose
Tool runs but returns nothingTimeout too short or wrong streamReturn stderr as a fallback; raise the subprocess timeout
3
Routine maintenance
upkeep

Keep three things current: Claude Code, the Kali tool packages, and the Python SDK. A monthly cadence avoids most "it worked last week" surprises. Prune servers you no longer use in the same pass.

# Routine update pass $ npm update -g @anthropic-ai/claude-code $ sudo apt update && sudo apt full-upgrade -y $ source .venv/bin/activate && pip install -U "mcp[cli]"
# Remove a server you no longer trust or need $ claude mcp remove kali-remote

Review your MCP server list periodically. Every registered server is code the agent can invoke — a forgotten experimental server is attack surface. If you did not write it or vet it, remove it.

PRO TIP: Log the agent's tool calls into the engagement folder and diff them against your rules of engagement at the end of each day. It is the cheapest way to catch a mis-scoped action before it becomes a finding against you.

📚

11 · Sources & References

go deeper

Primary documentation for the tools and protocols used in this guide:

Model Context Protocol — official specification and introduction MCP Python SDK (FastMCP) — GitHub repository Claude Code — MCP configuration and slash commands Claude Code — install and getting started Kali Linux — WSL2 install documentation Nmap — official reference guide

Building an AI-assisted testing lab?

Pair this setup with our other hands-on guides — the CyberHawk blog covers Nmap, BloodHound and privilege escalation end to end, and our Live Tools and Courses take you from lab to engagement. Keep every scan inside an authorised scope.

◈ Stay Connected

Follow CyberHawk Threat Intel for threat intelligence, deployment guides and hands-on SOC tooling content.

🌐 Website ▶️ YouTube ▶️ YouTube (2) 𝕏 Twitter / X ♪ TikTok ✈️ Telegram
🔍 IOC Scanner 🛠️ Live Tools 📚 Courses 🚨 Threat Intel 📝 Blog 📋 SOPs

"They can't exploit you if you are the Exploit."