Skip to main content
Glama
README.md
<img width="1928" height="608" alt="Frame 2" src="https://github.com/user-attachments/assets/4de72020-70d5-4079-9899-0bec793e9e6c" />

<div align="center">

<div align="center">

![Python](https://img.shields.io/badge/python-%3E%3D3.10-3776AB?logo=python&logoColor=white)
![Version](https://img.shields.io/badge/version-3.0.0-blue)
![License](https://img.shields.io/badge/license-GPLv3-green)
![MCP](https://img.shields.io/badge/MCP-FastMCP-orange)
![Ollama](https://img.shields.io/badge/LLM-Ollama-black?logo=ollama)
![Platform](https://img.shields.io/badge/platform-Linux-lightgrey?logo=linux)

</div>

### MCP server + Ollama-driven autonomous penetration testing framework.

mcpstrike connects an LLM (via Ollama) to security tools through the Model Context Protocol (MCP), enabling autonomous or guided penetration testing from a terminal interface.

</div>

## Architecture

```
mcpstrike-client          mcpstrike-server (MCP)         hexstrike_server
 (TUI + Ollama)   --->    (FastMCP, port 8889)    --->   (port 8888, must be running)
      |
      v
  Ollama LLM
  (llama3.2, qwen3.5, etc.)

  Optional: mcpstrike-backend can replace hexstrike_server for local testing
```

**Components:**

| Component | Role | Default port |
|---|---|---|
| **hexstrike_server** | External backend — must be started separately | 8888 |
| `mcpstrike-server` | MCP server exposing 15 tools for session/command management | 8889 |
| `mcpstrike-client` | Interactive TUI that drives an Ollama LLM to call MCP tools | — |
| `mcpstrike-backend` *(optional)* | Lightweight local alternative to hexstrike_server | **8890** |

## Installation

Install mcpstrike in a project-local virtual environment. Its Python
dependencies and all command-line entry points stay isolated from the system
Python.

```bash
git clone https://github.com/ente0/mcpstrike.git
cd mcpstrike
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e .
```

Install the optional standalone backend in the same environment:

```bash
python -m pip install -e ".[backend]"
```

For development tools and the standalone backend:

```bash
python -m pip install -e ".[dev,backend]"
```

After pulling changes, refresh the active environment:

```bash
git pull
python -m pip install -e ".[dev,backend]"
```

### Optional: expose the commands globally

While `.venv` is active, `mcpstrike`, `mcpstrike-server`,
`mcpstrike-client`, `mcpstrike-prompt` and `mcpstrike-backend` are already on
your `PATH`. To use them from any directory without activating the environment,
run this from the repository root once:

```bash
printf '\nexport PATH="%s/.venv/bin:$PATH"\n' "$PWD" >> ~/.zshrc
source ~/.zshrc
```

For Bash, replace `~/.zshrc` with `~/.bashrc` in both commands. The command
stores the repository's absolute `.venv/bin` path; recreate the environment if
you move the repository.

Leave the environment when finished:

```bash
deactivate
```

## Quick Start

**hexstrike_server must already be running** on port 8888 before starting mcpstrike.

### Automated (recommended)

```bash
mcpstrike
```

`mcpstrike` is the stack launcher. It opens three tiled xterm windows (or falls back to tmux, then background processes). All options can be overridden via flags:

```bash
mcpstrike --model qwen3:8b
mcpstrike --ollama-url http://10.0.0.5:11434
mcpstrike --sessions-dir /opt/pentest/sessions
mcpstrike --font-size 15 --screen-width 2560 --screen-height 1440
mcpstrike --tmux                         # force tmux even if DISPLAY is set
```

See `mcpstrike --help` for all options.

> **Note:** `start.sh` / `my_start.sh` are still available as personal launcher scripts with hardcoded IPs/model names.

### Manual

```bash
# Terminal 1: MCP server (points to hexstrike_server on 8888)
HEXSTRIKE_BACKEND_URL=http://localhost:8888 mcpstrike-server

# Terminal 2: Client
mcpstrike-client --ollama-url http://<ollama-host>:11434 --model qwen3.5
```

The MCP server and client share a bearer token generated automatically at
`~/.config/mcpstrike/auth-token` with owner-only permissions. The local MCP
endpoint uses a generated, pinned TLS identity under `~/.config/mcpstrike/`,
so the client validates the server before sending the bearer token. Plaintext
HTTP is rejected even on loopback; remote MCP URLs must also use HTTPS.

### With standalone backend (no hexstrike_server needed)

```bash
# Terminal 1: Local backend (port 8890, no conflict with hexstrike on 8888)
mcpstrike-backend

# Terminal 2: MCP server pointing to mcpstrike-backend
HEXSTRIKE_BACKEND_URL=http://localhost:8890 mcpstrike-server

# Terminal 3: Client
mcpstrike-client
```

Requires `python -m pip install -e ".[backend]"` in the active project
environment.

## Commands

### mcpstrike (stack launcher)

Starts the full stack in a single command. Automatically picks between xterm, tmux, and background mode.

```
mcpstrike [OPTIONS]

Network options:
  --ollama-url URL        Ollama daemon URL (default: http://localhost:11434)
  --model NAME            Ollama model to use (default: qwen3.5:latest)
  --hexstrike-port PORT   hexstrike_server port (default: 8888)
  --mcp-port PORT         mcpstrike-server port (default: 8889)

Session options:
  --sessions-dir PATH     Directory for session files (default: ~/hexstrike_sessions)

GUI xterm options:
  --font-size PT          xterm font size in points (default: 13)
  --screen-width PX       Screen width for window tiling (default: 1920)
  --screen-height PX      Screen height for window tiling (default: 1080)

Launch mode:
  --tmux, --no-xterm      Force tmux even if a display is available
  --xterm                 Force xterm (fails if DISPLAY is not set)
```

All network options also respect their environment variable equivalents (`OLLAMA_URL`, `OLLAMA_MODEL`, `HEXSTRIKE_PORT`, `MCPSTRIKE_PORT`, `HEXSTRIKE_SESSION_PATH`).

**Window layout (xterm, 1920×1080):**

```
┌─────────────────────────┬─────────────────────────┐
│     hexstrike_server    │     mcpstrike-server    │  top ~54%
├─────────────────────────┴─────────────────────────┤
│              mcpstrike-client                     │  bottom ~46%
└───────────────────────────────────────────────────┘
```

---

### mcpstrike-client

Interactive TUI for driving penetration tests with an Ollama LLM.

```
mcpstrike-client [OPTIONS]

Options:
  --mcp-url URL          MCP server URL (default: https://localhost:8889/mcp)
  --ollama-url URL       Ollama API URL (default: http://localhost:11434)
  --model, -m NAME       Ollama model (default: llama3.2)
  --sessions-dir PATH    Session files directory (default: ~/hexstrike_sessions)
  --no-native-tools      Force JSON fallback mode (for older models)
  --no-auto-parse        Disable automatic parser dispatch
  --debug                Enable verbose error tracebacks
```

#### Interactive Commands

| Command | Description |
|---|---|
| `/help` | Show all available commands |
| `/tools` | List MCP tools discovered on the server |
| `/agent` | Toggle autonomous agent mode (ON by default) |
| `/prompt <#> <target>` | Generate and load a pentest prompt template |
| `/prompts` | List available prompt templates with index numbers |
| `/status` | Show connection, model, and session info |
| `/model <name>` | Switch Ollama model at runtime |
| `/native` | Toggle native tool-calling vs JSON fallback |
| `/clear` | Clear conversation history |
| `/quit`, `/exit` | Exit the client |

#### Input Modes

| Mode | Usage |
|---|---|
| Normal | Type a message and press Enter |
| Multi-line | Start with `<<<`, type multiple lines, end with `>>>` |
| File input | `@path/to/file.txt` loads the file content as input |

#### Prompt Workflow

mcpstrike ships with pentest prompt templates. Use them to bootstrap an assessment:

```
/prompts                              # list templates with numbers
/prompt 1 192.168.1.100               # generate autonomous prompt for target
/prompt 2 10.0.0.5 -d example.com     # guided prompt with domain
go                                    # send any message to start execution
```

Templates are in `src/mcpstrike/client/prompts/templates/` — you can add your own `.txt` or `.md` files there.

---

### mcpstrike-server

FastMCP server exposing penetration testing tools via MCP protocol.

```
mcpstrike-server
```

Environment variables:

| Variable | Default | Description |
|---|---|---|
| `HEXSTRIKE_BACKEND_URL` | `http://localhost:8888` | Backend API URL (hexstrike or mcpstrike-backend) |
| `MCPSTRIKE_HOST` | `127.0.0.1` | MCP server bind address (loopback only) |
| `MCPSTRIKE_PORT` | `8889` | Server bind port |
| `MCPSTRIKE_AUTH_TOKEN` | generated private token | Shared MCP bearer token (minimum 32 characters) |
| `MCPSTRIKE_AUTH_TOKEN_PATH` | `~/.config/mcpstrike/auth-token` | Private token file |
| `MCPSTRIKE_AUTH_SCOPES` | `read,write,execute` scopes | Scopes assigned to the shared token |
| `MCPSTRIKE_TLS_CERT_PATH` | `~/.config/mcpstrike/mcp-local.crt` | Pinned local MCP TLS certificate |
| `MCPSTRIKE_TLS_KEY_PATH` | `~/.config/mcpstrike/mcp-local.key` | Owner-only local MCP TLS private key |
| `MCPSTRIKE_BACKEND_AUTH_TOKEN` | — | Explicit token for a standalone backend on a custom URL |
| `MCPSTRIKE_BACKEND_AUTH_TOKEN_PATH` | `~/.config/mcpstrike/backend-auth-token` | Dedicated private backend token; never reused for MCP |
| `HEXSTRIKE_SESSION_PATH` | — | Absolute path for sessions (highest priority) |
| `HEXSTRIKE_SESSION_DIR` | — | Folder name in `$HOME` for sessions |

---

### mcpstrike-backend (optional)

Lightweight local backend — alternative to hexstrike-server. Executes security tools as subprocesses directly on the local machine.

**Requires the `backend` extra:** `python -m pip install -e ".[backend]"`

```
mcpstrike-backend [OPTIONS]

Options:
  --host TEXT    Bind address (loopback only; default: 127.0.0.1)
  --port INT     Bind port (default: 8890)
```

Environment variables: `MCPSTRIKE_BACKEND_HOST`, `MCPSTRIKE_BACKEND_PORT`,
`MCPSTRIKE_BACKEND_AUTH_TOKEN`, `MCPSTRIKE_BACKEND_AUTH_TOKEN_PATH`.

The standalone backend proves its identity with a short-lived challenge bound
to a fresh client nonce. Each request and response then uses a one-time,
AES-GCM authenticated channel plus an exact request HMAC. The shared backend
key and plaintext command are never transmitted to a process that races to
occupy or relay the configured loopback port.

The `timeout` field bounds the direct process, its process group and descendants
that can still be identified at cleanup time. It is deliberately reported as
best-effort containment, not an OS sandbox: an already approved executable can
daemonize and escape PID-based cleanup. Run adversarial binaries inside an
external sandbox or container rather than relying on this timeout boundary.

Endpoints:

| Method | Path | Description |
|---|---|---|
| GET | `/health` | Health check with uptime |
| POST | `/api/command` | Execute a command, returns stdout/stderr/exit_code |

---

### mcpstrike-prompt

Standalone prompt generator CLI. Fills template placeholders and writes ready-to-use prompt files.

```bash
# Basic usage
mcpstrike-prompt -t 192.168.1.100
mcpstrike-prompt -t 10.0.0.5 -d site.com --test-type web_app

# With User-Agent (alias or raw string)
mcpstrike-prompt -t 10.0.0.5 --ua burp
mcpstrike-prompt -t 10.0.0.5 --ua "Mozilla/5.0 (authorized-test)"

# With out-of-scope file
mcpstrike-prompt -t 10.0.0.5 --out-of-scope-file scope.txt

# Generate a blank scope file to fill in
mcpstrike-prompt --scope-template > scope.txt

# Preview without writing
mcpstrike-prompt -t 10.0.0.5 -d site.com --dry-run

# List templates / test types
mcpstrike-prompt --list
mcpstrike-prompt --list-test-types
```

#### Out-of-scope file format

Generate a pre-filled template with:

```bash
mcpstrike-prompt --scope-template > scope.txt
```

Then edit and pass it:

```bash
mcpstrike-prompt -t 10.0.0.5 -d site.com --out-of-scope-file scope.txt
```

File format:

```
# Lines starting with # are comments — ignored by the parser
# One entry per line under each section header

[domains]
admin.example.com
staging.example.com
*.internal.example.com

[ips]
10.0.0.1
192.168.0.0/24

[paths]
/api/internal
/admin
/health
/metrics

[vulns]
dos
ddos
account-lockout

[notes]
Do not test outside 09:00-18:00 UTC
Maximum 10 requests/second
Do not use automated scanners on /checkout
```

| Rule | Detail |
|------|--------|
| Sections | `[domains]` `[ips]` `[paths]` `[vulns]` `[notes]` |
| Order | Sections can appear in any order |
| Fallback | Lines before the first header go to `[notes]` |
| Comments | Any line starting with `#` is ignored |
| Empty lines | Ignored |

Each section maps to a template placeholder:

| Section | Placeholder |
|---------|-------------|
| `[domains]` | `{{OUT_OF_SCOPE_DOMAINS}}` |
| `[ips]` | `{{OUT_OF_SCOPE_IPS}}` |
| `[paths]` | `{{OUT_OF_SCOPE_PATHS}}` |
| `[vulns]` | `{{OUT_OF_SCOPE_VULNS}}` |
| `[notes]` | `{{OUT_OF_SCOPE_NOTES}}` |

Entries within each section are rendered as a comma-separated inline string. Unused sections render as `N/A`.

#### User-Agent

`--ua` accepts either a predefined alias or any raw UA string:

```bash
mcpstrike-prompt -t 10.0.0.5 --ua burp
mcpstrike-prompt -t 10.0.0.5 --ua "Mozilla/5.0 (X11; Linux x86_64) MyTool/1.0"
```

| Alias | Expands to |
|-------|------------|
| `burp` | `BurpSuite-Authorized-Test` |
| `mobile` | iPhone UA + `(bounty-authorized)` |
| `googlebot` | `Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)` |
| `curl` | `curl/8.5.0 (authorized-pentest)` |
| `firefox` | Firefox 124 UA + `(bounty-authorized)` |

The resolved string is injected into `{{USER_AGENT}}` and applied to all HTTP tools in the prompt (curl, nikto, feroxbuster, gobuster, nuclei, sqlmap, dalfox, whatweb, wpscan).

#### Test types

`--test-type` controls which phases and tools the LLM prioritizes:

| Type | LLM behavior |
|------|-------------|
| `full` | All phases: recon → enum → exploitation → report. Default. |
| `web_app` | Web-only: skips port scan, focuses dalfox / sqlmap / nuclei / feroxbuster |
| `network` | Network-first: heavy nmap / masscan / SMB / LDAP. Web only if port found. |
| `black_box` | No credentials assumed. Adds brute-force and default credential checks. |
| `gray_box` | Credentials provided. Focuses post-auth: IDOR, privesc, session abuse. |

Run `mcpstrike-prompt --list-test-types` for the full description of each type.

---

## MCP Tools Reference

The MCP server exposes 14 tools that the LLM can invoke:

### Configuration

| Tool | Description |
|---|---|
| `get_config` | Return current server configuration |
| `set_session_directory` | Change session directory at runtime |

### Session Discovery

| Tool | Description |
|---|---|
| `discover_sessions` | Find sessions across multiple directories |
| `import_external_session` | Import a session folder from an external path |

### Execution

| Tool | Description |
|---|---|
| `health_check` | Ping the backend |
| `execute_command` | Run a security command on the backend |

### Session Files

| Tool | Description |
|---|---|
| `create_session` | Create a new pentest session |
| `list_sessions` | List all sessions |
| `write_session_file` | Write content to a session file |
| `read_session_file` | Read content from a session file |
| `list_session_files` | List files in a session |

### Parsers

| Tool | Description |
|---|---|
| `parse_output` | Parse raw tool output (nmap, whatweb, nuclei, nikto, dirb) |
| `auto_parse_output` | Auto-detect the tool and route to the correct parser |

### Findings

| Tool | Description |
|---|---|
| `update_session_findings` | Merge parsed findings into session_metadata.json |

---

## Agent Mode

When agent mode is ON (default), the client runs an autonomous loop:

1. Send the conversation + system prompt to Ollama
2. If the model returns tool calls, execute them via MCP
3. Feed tool results back into the conversation
4. Repeat until the model responds with text only (no tool calls)

Safety features:
- **Human approval**: Model-requested commands, writes, sensitive reads, external session discovery and model-service queries require an explicit `y`
- **Authenticated MCP**: Bearer validation and per-tool scopes are enforced by FastMCP
- **Local-only listeners**: Privileged MCP and subprocess services reject non-loopback binds
- **Contained sessions**: Session reads and writes cannot escape the configured session root
- **Untrusted tool results**: Tool output is returned with the `tool` role, never as a user instruction
- **Max iterations**: Stops after 20 consecutive tool-call cycles
- **Context pruning**: Sliding window keeps the last 40 messages to prevent Ollama context overflow
- **Ctrl+C**: Abort the current generation at any time
- **Auto-save**: Command output is automatically saved to session files
- **Auto-parse**: Output is parsed for structured findings (ports, vulns, etc.)
- **Findings persistence**: Parsed findings are merged into `session_metadata.json`

---

## Prompt Templates

Two templates ship with mcpstrike:

### autonomous

Full-autonomy prompt with decision framework. The model receives:
- Target information and scope boundaries
- Out-of-scope restrictions (domains, IPs, paths, vuln classes, notes)
- User-Agent to inject in all HTTP tool invocations
- Complete tool arsenal reference
- Decision framework (discovery → enumeration → exploitation → documentation)
- Tool usage best practices and anti-patterns
- XSS/SQLi workflow examples

### guided

Step-by-step methodology with numbered phases (0-9). More structured, walks the model through each phase sequentially.

### Custom Templates

Add `.txt` or `.md` files to `src/mcpstrike/client/prompts/templates/`. Use `{{PLACEHOLDER}}` syntax:

| Placeholder | Description |
|---|---|
| `{{TARGET}}` | Target IP or hostname |
| `{{DOMAIN}}` | Domain name |
| `{{SESSION_ID}}` | Auto-generated session ID |
| `{{DATE}}` | Current date (YYYY-MM-DD) |
| `{{DATETIME}}` | Full ISO datetime |
| `{{TIMESTAMP}}` | Unix timestamp |
| `{{TEST_TYPE}}` | Test type (black_box, gray_box, web_app, network, full) |
| `{{USER_AGENT}}` | Full User-Agent string for HTTP tools |
| `{{USER_AGENT_SUFFIX}}` | User-Agent suffix (backward compat) |
| `{{OUT_OF_SCOPE_DOMAINS}}` | Excluded domains, comma-separated |
| `{{OUT_OF_SCOPE_IPS}}` | Excluded IPs/ranges, comma-separated |
| `{{OUT_OF_SCOPE_PATHS}}` | Excluded paths/endpoints, comma-separated |
| `{{OUT_OF_SCOPE_VULNS}}` | Excluded vulnerability classes, comma-separated |
| `{{OUT_OF_SCOPE_NOTES}}` | Additional out-of-scope restrictions |

---

## Configuration

All configuration is via environment variables or `.env` file:

```env
# Backend (hexstrike-server or mcpstrike-backend)
HEXSTRIKE_BACKEND_URL=http://localhost:8888

# MCP Server
MCPSTRIKE_HOST=127.0.0.1
MCPSTRIKE_PORT=8889
MCPSTRIKE_AUTH_SCOPES=mcpstrike:read,mcpstrike:write,mcpstrike:execute
MCPSTRIKE_TLS_CERT_PATH=~/.config/mcpstrike/mcp-local.crt
MCPSTRIKE_TLS_KEY_PATH=~/.config/mcpstrike/mcp-local.key

# Optional standalone backend
MCPSTRIKE_BACKEND_HOST=127.0.0.1
MCPSTRIKE_BACKEND_PORT=8890

# Client
MCPSTRIKE_MCP_URL=https://localhost:8889/mcp
OLLAMA_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2

# Sessions
HEXSTRIKE_SESSION_PATH=/absolute/path/to/sessions
HEXSTRIKE_SESSION_DIR=my_sessions  # relative to $HOME
```

---

## Project Structure

```
src/mcpstrike/
  config.py                     # Centralized settings (pydantic-settings)
  launcher.py                   # `mcpstrike` entry point — stack launcher with argparse
  backend/                      # OPTIONAL — standalone local backend
    app.py                      # FastAPI subprocess execution server
  server/
    wrapper.py                  # MCPServerWrapper (FastMCP lifecycle)
    app.py                      # MCP tool definitions (14 tools)
  client/
    wrapper.py                  # MCPClientWrapper (JSON-RPC + SSE)
    ollama_bridge.py            # Ollama streaming + tool-call dispatch
    tui.py                      # Interactive TUI (rich + prompt_toolkit)
    prompts/
      generator.py              # Template manager + prompt generation + CLI
      templates/
        autonomous.txt          # Full-autonomy pentest prompt
        guided.txt              # Step-by-step guided prompt
  common/
    filenames.py                # Smart filename allocation for output
    formatters.py               # Output extraction + report formatting
    parsers.py                  # nmap/whatweb/nuclei/nikto/dirb parsers
```

## Requirements

- Python >= 3.10
- Ollama running locally (or remotely via `--ollama-url`)
- **hexstrike_server** running on port 8888, OR install with `.[backend]` for the standalone alternative
- Security tools installed on the backend machine (nmap, nikto, sqlmap, etc.)