Skip to main content
Glama

nmap-mcp

CI License: MIT Python 3.11+

A scoped MCP server that lets an AI assistant run nmap scans — but only against networks you are authorized to test, using a fixed, non-extensible set of tools instead of raw nmap flags.

⚠️ Authorization notice

Only scan networks and hosts you own or have explicit written authorization to test. Unauthorized scanning of third-party networks may violate the Computer Fraud and Abuse Act (US), the Computer Misuse Act (UK), or equivalent laws elsewhere, and may violate your ISP's or employer's acceptable-use policy. This server enforces a scope allowlist (NMAP_ALLOWED_TARGETS) as a technical safeguard, but you are responsible for having authorization before you set it.

Related MCP server: Security MCP Server

Why this exists

An AI assistant with unrestricted nmap access is a liability: it could be steered (by a prompt injection, a typo, or its own mistake) into scanning a network you don't own, writing files outside the sandbox, or running an intrusive/exploit script. This server closes those doors structurally:

  • The AI never supplies raw nmap flags — every tool builds its own fixed argv from validated scalar parameters.

  • Every target is checked against an allowlist (and an optional deny-list carve-out) before anything runs; hostnames are resolved and pinned to their IP so DNS can't move the target after the check.

  • Every NSE script or category is resolved against an allowlist derived from nmap's own script.db, so dos/exploit/brute/malware/fuzzer scripts can never run, and vuln/intrusive scripts only run (in vuln_scan) if you explicitly opt in.

  • No output-file flags, no evasion flags (decoys, spoofing, fragmentation, proxies), no -T5.

  • The container runs as a non-root user with just the capabilities nmap needs (cap_net_raw, cap_net_admin) — not root.

Architecture

                 ┌─────────────────────────┐
  AI assistant   │        server.py        │   thin MCP tool layer;
  (Claude, etc.) │  (FastMCP tool defs)     │   no validation/nmap logic
      │          └───────────┬──────────────┘
      │ stdio/MCP            │ calls into
      ▼                      ▼
┌──────────┐  ┌──────────┐  ┌──────────┐  ┌───────────┐  ┌──────────┐
│ scope.py │  │scripts.py│  │runner.py │  │ parser.py │  │history.py│
│ allowlist│  │ NSE      │  │ argv     │  │ nmap XML  │  │ SQLite   │
│ + DNS    │  │ allowlist│  │ templates│  │  -> typed │  │ history  │
│ pinning  │  │from      │  │ + sandbox│  │  models   │  │ + diff   │
│          │  │script.db │  │ subprocess│  │           │  │          │
└──────────┘  └──────────┘  └────┬─────┘  └───────────┘  └──────────┘
                                  │ asyncio.create_subprocess_exec
                                  ▼
                            ┌──────────┐
                            │   nmap   │
                            └──────────┘

server.py never talks to nmap directly. runner.py is the only module that invokes a subprocess, always via create_subprocess_exec (never a shell), always with -oX -, always under a hard timeout.

Tools

Tool

What it does

get_scope()

Show configured scope, limits, and whether intrusive scripts are enabled

discover_hosts(target)

Ping-sweep (-sn) to find live hosts

quick_scan(target, top_ports=100)

Scan the N most common TCP ports

port_scan(target, ports, scan_type="syn")

SYN / connect / UDP scan of specific ports

service_scan(target, ports="", intensity=7)

Service/version detection

os_detect(target)

OS fingerprinting

script_scan(target, scripts, ports="")

Run allowlisted NSE scripts/categories

network_inventory(target)

Two-phase sweep + service scan of live hosts

host_summary(target)

OS + ports + versions + default scripts, as a report

ssl_audit(target, ports="443")

Certificate, cipher suites, clock skew

http_audit(target, ports="80,443")

Title, headers, server banner, methods, robots.txt

ssh_audit(target, ports="22")

Algorithm support, host key fingerprints

smb_audit(target)

SMB protocol versions, security mode

rdp_audit(target)

RDP encryption level, NTLM info

dns_audit(target)

Open recursion, NSID (no zone transfer/brute unless intrusive)

database_audit(target)

Exposed MySQL/MSSQL/MongoDB/Redis info (no brute)

vuln_scan(target, ports="")

vuln+safe scripts, or full vuln category if intrusive mode is on

list_scans(limit=20, target="")

Recent scan history

get_scan(scan_id)

Full stored result for one scan

diff_scans(scan_id_a, scan_id_b)

Diff two scans: hosts/ports/OS changes

diff_latest(target)

Diff the two most recent scans of a target

Configuration (environment variables)

Var

Default

Purpose

NMAP_ALLOWED_TARGETS

(empty → refuse all scans)

Comma-separated CIDRs/IPs you're authorized to scan

NMAP_DENY_TARGETS

(empty)

CIDRs/IPs carved out of the allowlist

NMAP_MAX_HOSTS

256

Max addresses per scan

NMAP_TIMEOUT

600

Hard kill, seconds, per scan

NMAP_MAX_PARALLEL

2

Concurrent scans

NMAP_MAX_TIMING

4

Highest allowed -T (never above 4)

NMAP_ALLOW_INTRUSIVE

0

1 enables vuln/intrusive scripts, only in vuln_scan

NMAP_HISTORY_DB

/data/history.db

SQLite history file (mount a volume over it)

NMAP_MAX_OUTPUT_CHARS

20000

Truncate tool output beyond this

The effective config is logged to stderr at startup.

Install (Docker; Windows 11 + WSL2 walkthrough)

0. Prerequisites — Docker (on Windows: WSL2 and Docker Desktop). Install both first:

wsl --install              # installs a default Linux distro + WSL2 kernel
# reboot if prompted, then open the new Linux distro once to finish setup

Install Docker Desktop for Windows, and in Settings → General confirm "Use the WSL 2 based engine" is checked, and in Settings → Resources → WSL Integration enable integration with your distro. Verify from a Windows terminal:

wsl -l -v        # your distro should show VERSION 2
docker version   # should succeed, not "command not found"

1. Build the image (from this project directory, in PowerShell or WSL):

docker build -t nmap-mcp .

2. Create the history volume (persists history.db across container restarts):

docker volume create nmap-mcp-data

3. Decide your authorized ranges. NMAP_ALLOWED_TARGETS is empty by default, and every scan tool refuses with a clear error until you set it. Pick the CIDR(s)/IP(s) you own or are explicitly authorized to test, e.g. 192.168.1.0/24.

4. Claude Code:

claude mcp add nmap -- docker run -i --rm --network host \
  --cap-add NET_RAW --cap-add NET_ADMIN \
  -v nmap-mcp-data:/data \
  -e NMAP_ALLOWED_TARGETS=<your-authorized-ranges> \
  nmap-mcp

5. Claude Desktop — add to claude_desktop_config.json (%APPDATA%\Claude\claude_desktop_config.json on Windows):

{
  "mcpServers": {
    "nmap": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm", "--network", "host",
        "--cap-add", "NET_RAW", "--cap-add", "NET_ADMIN",
        "-v", "nmap-mcp-data:/data",
        "-e", "NMAP_ALLOWED_TARGETS=<your-authorized-ranges>",
        "nmap-mcp"
      ]
    }
  }
}

6. Optional: Docker MCP Toolkit gateway catalog entry. Honest answer: use the direct method above instead. The Toolkit gateway's custom.yaml/registry.yaml catalog format doesn't have a way to express --cap-add NET_RAW, --cap-add NET_ADMIN, or --network host on the container it launches — without raw-socket capabilities nmap falls back to slow, less-accurate connect-scan-only behavior, and without host networking on Linux you'd only see the container's own virtual network. If you want to try it anyway, the catalog entry would look like:

# custom.yaml
registry:
  nmap:
    description: Scoped nmap scanning, restricted to authorized targets
    title: nmap-mcp
    image: nmap-mcp:latest
    dateAdded: "2026-11-07T00:00:00Z"
    tools:
      - get_scope
      - discover_hosts
      - quick_scan
      - port_scan
      - service_scan
      - os_detect
      - script_scan
      - network_inventory
      - host_summary
      - ssl_audit
      - http_audit
      - ssh_audit
      - smb_audit
      - rdp_audit
      - dns_audit
      - database_audit
      - vuln_scan
      - list_scans
      - get_scan
      - diff_scans
      - diff_latest

but expect degraded scan capability versus the direct docker run method.

7. Networking caveat on Docker Desktop (WSL2 backend). --network host is accepted but behaves differently than on native Linux: Docker Desktop's WSL2 VM sits between the container and your real LAN, so:

  • Works well: TCP connect scans (port_scan scan_type=connect), service/version detection, OS/protocol audits against targets you can already reach by IP.

  • May not work or may be inaccurate: ARP-based host discovery (discover_hosts may need to fall back to ICMP/TCP probing), raw SYN scans and OS fingerprinting (-sS, -O) depending on Docker Desktop version and WSL2 kernel capabilities.

  • Fallback: if LAN visibility is unreliable through Docker Desktop, run the server natively instead: uv sync && uv run nmap-mcp directly inside your WSL2 distro (with real nmap installed there via sudo apt install nmap), which has an unvirtualized view of the network. You lose the container's non-root/capability sandboxing in exchange for full nmap fidelity — a reasonable trade for a machine you control.

Example prompts

  1. "What's my scan scope?"

  2. "Discover live hosts on my LAN."

  3. "Run a quick scan on 192.168.1.10 and tell me what's open."

  4. "Give me a host summary for my router."

  5. "Diff the last two scans of 192.168.1.10 — what changed?"

Development

uv sync
uv run pytest -m "not live"

See CLAUDE.md for the safety invariants any change must keep, DECISIONS.md for design rationale, and CONTRIBUTING.md / SECURITY.md.

Live tests (opt-in, require a real nmap binary and loopback access):

uv run pytest -m live

License

MIT

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      D
      maintenance
      Provides AI agents like Claude with secure, controlled access to network security tools like nmap for scanning private networks and lab environments. Features comprehensive safety controls, circuit breakers, and production-ready monitoring.
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables network scanning and security assessment using Nmap through MCP, allowing AI assistants to perform port scans, service detection, and network reconnaissance on specified targets with configurable scan parameters.
      -
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to perform authorized security testing and penetration testing operations including SSL/TLS analysis, port scanning, vulnerability scanning, and HTTP security header audits through natural language interactions.
      1
      MIT