Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,46 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.1.0] - 2026-07-31

Feature parity with the official Rapid7 MCP server, plus modern MCP-protocol
capabilities. See [`docs/MCP_API.md`](docs/MCP_API.md) for the full tool/resource
reference and MCP specification conformance.

### Added
- **Workspace database intelligence (read-only):** `list_hosts`, `list_services`,
`list_vulnerabilities`, `list_notes`, `list_credentials`, `list_loot` — expose
the Metasploit workspace database, scoped by workspace, degrading gracefully to
a structured error when no database is attached.
- **`check_vulnerability`:** runs a module's non-destructive `check` (never fires
the exploit, delivers a payload, or opens a session), mapping the outcome to a
structured state (vulnerable / safe / unsupported / unknown).
- **`get_module_results`:** retrieves status/output for an asynchronously launched
module by its execution UUID.
- **Tool annotations:** every tool advertises MCP hints (`readOnlyHint`,
`destructiveHint`, `idempotentHint`, `openWorldHint`).
- **MCP resources:** `msf://server/info` (identity, safety posture, tool taxonomy)
and `msf://module/{module}` (module documentation).
- **Elicitation confirmation (opt-in):** `--confirm-dangerous` /
`MSF_MCP_CONFIRM_DANGEROUS` asks the client to confirm destructive actions,
falling back to the safety gate when the client cannot elicit.

### Security / Safety
- **Opt-in safe mode (dangerous actions ENABLED by default):** state-changing
tools (exploit/module execution, payload generation, session control,
listeners/jobs) remain available by default so existing users are not
regressed. Harden a deployment with `--safe-mode` / `MSF_MCP_ALLOW_DANGEROUS=false`
to expose read-only tools only. This intentionally inverts the official Rapid7
server's default-off posture.
- **Optional rate limiting:** off by default; enable with `--rate-limit` /
`MSF_MCP_RATE_LIMIT`. `health_check` reports the safety posture.
- **Optional elicitation confirmation:** `--confirm-dangerous`.

### Changed
- `health_check` now reports `database_connected` and the `safety` posture.
- Evaluated the FastMCP 3.x upgrade: cap retained at `<3.4.0` (3.4.x fails to
import; 3.3.x is used and verified). Fixed the stale in-package `__version__`.

## [3.0.1] - 2026-07-31

First release published to PyPI (`pip install metasploit-mcp`).
Expand Down
67 changes: 49 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,26 @@ An **unofficial**, modern, secure Model Context Protocol (MCP) server that provi

### Core Capabilities
- **Exploit Management**: Search, configure, and execute Metasploit exploits
- **Non-destructive checks**: `check_vulnerability` runs a module's `check` without exploiting
- **Payload Generation**: Create custom payloads with advanced encoding options
- **Session Management**: Control active sessions with command execution
- **Listener Management**: Start and manage reverse handlers
- **Security Validation**: Built-in bind address validation and input sanitization
- **Workspace database intelligence**: Read hosts, services, vulnerabilities, notes, credentials, and loot from the Metasploit database
- **Async results**: Retrieve results of long-running module runs with `get_module_results`

### MCP protocol features
- **Tool annotations**: every tool advertises `readOnly` / `destructive` hints
- **Structured output**: typed results with a text fallback for older clients
- **Resources**: `msf://server/info` and `msf://module/{module}` documentation
- **Elicitation**: optional client confirmation before destructive actions

See **[docs/MCP_API.md](docs/MCP_API.md)** for the full tool/resource reference,
MCP specification conformance, and a comparison with the official Rapid7 MCP.

### Security Features
- **Optional safe mode**: offensive tools (exploit/module execution, payload generation, session/listener control) are **enabled by default** (this is an offensive tool). Harden a deployment with `--safe-mode` (or `MSF_MCP_ALLOW_DANGEROUS=false`) to expose **read-only tools only**. *(This intentionally inverts the official Rapid7 server's default-off posture to avoid regressing existing users.)*
- **Optional rate limiting**: off by default; enable a per-minute cap with `--rate-limit N`
- **Optional confirmation**: `--confirm-dangerous` asks the client to approve each destructive action via MCP elicitation
- **Bind Address Validation**: Rejects bind addresses that are neither a wildcard nor an IP configured on the host
- **Input Sanitization**: Comprehensive validation of all parameters, including rejection of control characters in module options (command-injection guard)
- **Error Handling**: Prevents information leakage through proper error management
Expand Down Expand Up @@ -54,12 +68,20 @@ An **unofficial**, modern, secure Model Context Protocol (MCP) server that provi

### 1. Installation

**From PyPI (recommended):**

```bash
pip install metasploit-mcp
```

This installs the `metasploit-mcp` CLI. To try it without installing into your
environment, use [`pipx`](https://pipx.pypa.io/): `pipx run metasploit-mcp --help`.

**From source (for development):**

```bash
# Clone the repository
git clone https://github.com/setuidloot/MetasploitMCP.git
cd MetasploitMCP

# Install with Poetry
poetry install
poetry shell
```
Expand Down Expand Up @@ -92,22 +114,27 @@ export MSF_RPC_PROTOCOL=msgpack # Options: 'msgpack' (default) or 'jsonrpc'
### 4. Run the Server

```bash
# Using the CLI entry point (recommended)
# Full toolset (default) — offensive tools enabled
metasploit-mcp --transport http --host 127.0.0.1 --port 8085

# Or using Poetry directly
poetry run metasploit-mcp --transport http --host 127.0.0.1 --port 8085
# Hardened: read-only tools only
metasploit-mcp --transport http --safe-mode

# Or run the module
poetry run python -m metasploit_mcp
# Optional: require client confirmation before each destructive action
metasploit-mcp --transport http --confirm-dangerous

# Using Make
make run
# Optional: cap dangerous requests per minute
metasploit-mcp --transport http --rate-limit 60

# Debug mode
make run-debug
# From source
poetry run metasploit-mcp --transport stdio
make run # or: make run-debug
```

> By default the server exposes the **full toolset** (offensive tools enabled).
> Pass `--safe-mode` (or set `MSF_MCP_ALLOW_DANGEROUS=false`) to expose read-only
> tools only. See [docs/MCP_API.md](docs/MCP_API.md#safety-model) for the full safety model.

## Development

### Development Setup
Expand Down Expand Up @@ -179,26 +206,30 @@ MetasploitMCP/

### Claude Desktop

Configure `claude_desktop_config.json`:
Configure `claude_desktop_config.json` (after `pip install metasploit-mcp`):

```json
{
"mcpServers": {
"metasploit": {
"command": "poetry",
"command": "metasploit-mcp",
"args": [
"run", "metasploit-mcp",
"--transport", "stdio"
],
"cwd": "/path/to/MetasploitMCP",
"env": {
"MSF_PASSWORD": "yourpassword"
"MSF_PASSWORD": "yourpassword",
"MSF_SERVER": "127.0.0.1",
"MSF_PORT": "55553"
}
}
}
}
```

Add `"--safe-mode"` to the args to expose read-only tools only. If you installed
from source instead of PyPI, use `"command": "poetry"` with
`"args": ["run", "metasploit-mcp", …]` and a `"cwd"` pointing at the checkout.

### Other MCP Clients

For HTTP-based MCP clients:
Expand Down
155 changes: 155 additions & 0 deletions docs/MCP_API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# MetasploitMCP — MCP API & Specification Conformance

> **Unofficial project.** Not affiliated with, sponsored by, or supported by
> Rapid7. "Metasploit" is a trademark of Rapid7.

This document is the reference for every tool and resource the server exposes and
for how the server maps onto the [Model Context Protocol](https://modelcontextprotocol.io)
specification. It complements the [README](../README.md) and
[`docs/API.md`](API.md).

- **Transports:** `stdio` and streamable HTTP (`--transport stdio|http`).
- **Server name:** `MetasploitMCP` · **Package:** `metasploit-mcp` (PyPI).
- **Backend:** Metasploit Framework RPC (`msfrpcd`), via `pymetasploit3`.

## Safety model

This is an offensive-security tool, so state-changing / offensive tools are
**enabled by default**. Deployments can be hardened with an opt-in **safe mode**
(read-only tools only) and/or a rate limit. *(This intentionally inverts the
official Rapid7 server's default-off posture to avoid regressing existing users.)*

| Control | Flag | Environment | Default |
|---|---|---|---|
| Disable destructive tools (safe mode) | `--safe-mode` | `MSF_MCP_ALLOW_DANGEROUS=false` | dangerous **enabled** |
| Rate limit (req/min, 0=off) | `--rate-limit N` | `MSF_MCP_RATE_LIMIT` | 0 (off) |
| Confirm destructive via elicitation | `--confirm-dangerous` | `MSF_MCP_CONFIRM_DANGEROUS` | off |

- In safe mode, a blocked destructive call returns `{"status":"error","error":"dangerous_actions_disabled"}`.
- Over-limit calls (when a rate limit is set) return `{"status":"error","error":"rate_limited","retry_after_seconds":N}`.
- `health_check` reports the active posture under `safety`.

## Tool reference

Every tool advertises MCP annotation hints. `RO` = `readOnlyHint:true`,
`DESTRUCTIVE` = `destructiveHint:true` (gated by the safety model above).

### Discovery & module info — read-only

| Tool | Key parameters | Returns |
|---|---|---|
| `list_exploits` | `search` | List of matching exploit module paths |
| `list_payloads` | `platform`, `arch`, `compatible_with` | List of payload module paths |
| `describe_module` | `module`, `module_type` | Options, targets, metadata |
| `get_module_documentation` | `module` | Human-readable module documentation |

### Workspace database intelligence — read-only

All accept an optional `workspace` (defaults to the current workspace) and return
`{status, workspace, count, <items>}`. When no database is attached they return
`{"status":"error","error":"database_unavailable"}`.

| Tool | Extra parameters | Items key |
|---|---|---|
| `list_hosts` | — | `hosts` |
| `list_services` | `host`, `ports`, `proto` | `services` |
| `list_vulnerabilities` | `host` | `vulns` |
| `list_notes` | `host`, `ntype` | `notes` |
| `list_credentials` | — | `creds` |
| `list_loot` | `host` | `loots` |

### Assessment — read-only

| Tool | Key parameters | Returns |
|---|---|---|
| `check_vulnerability` | `module`, `options`, `module_type`, `timeout_seconds` | `{check_state: vulnerable\|safe\|unsupported\|unknown, code, message, session_created:false}` — runs the module's `check` only; never exploits |
| `get_module_results` | `execution_id` (UUID) | `{execution_status: completed\|running\|errored, result}` |

### Execution — destructive (gated)

| Tool | Key parameters | Returns |
|---|---|---|
| `run_exploit` | `module`, `options`, `payload_*`, `run_as_job` | Job/session result incl. `uuid`, `session_id` |
| `run_auxiliary_module` | `module`, `options`, `run_as_job` | Module result incl. `uuid` |
| `run_post_module` | `module`, `session_id`, `options` | Module result incl. `uuid` |
| `generate_payload` | `payload`, `format`, `options`, `encoder`, … | Generated payload metadata + server save path |

The `uuid` returned by these can be passed to `get_module_results`.

### Session, listener & job control — destructive (gated)

| Tool | Key parameters | Returns |
|---|---|---|
| `send_session_command` | `session_id`, `command` | Command output |
| `terminate_session` | `session_id`, `kill_associated_job` | Termination status |
| `start_listener` | `payload`, `lhost`, `lport`, `reverselistenerbindaddress` | Handler job info |
| `stop_job` | `job_id` | Stop status |
| `kill_all_handler_jobs` | — | Count of handlers stopped |

> **Listener binding:** handlers bind `0.0.0.0` (all interfaces) by default for
> reverse-connection compatibility — a convenience default, **not** a hardened
> one. Restrict it with `reverselistenerbindaddress` on shared networks.

### Status — read-only

| Tool | Returns |
|---|---|
| `list_active_sessions` | Active sessions map |
| `list_listeners` | Handler jobs and other jobs |
| `health_check` | `{status, msf_version, database_connected, safety:{…}}` |

## Resources

| URI | Description |
|---|---|
| `msf://server/info` | Server identity, unofficial/no-affiliation flags, safety posture, and the full tool annotation taxonomy |
| `msf://module/{module}` | Documentation for a module; `{module}` is the full path with the type as the first segment (e.g. `exploit/windows/smb/ms17_010_eternalblue`). Percent-encode slashes (`%2F`) if your client cannot place them in a single URI segment |

## Input safety

Module option names and values are rejected if they contain newline, carriage
return, or NUL characters, on both the RPC and console execution paths — a guard
against console command injection (CVE-2026-5463 in the underlying
`pymetasploit3`, which has no upstream fix).

## MCP specification conformance

| Capability | Status | Notes |
|---|---|---|
| **Tools** | ✅ | 24 tools |
| **Tool annotations** | ✅ | `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint` on every tool |
| **Structured tool output** | ✅ | Tools emit `structuredContent` with an output schema; the text representation is preserved for clients without structured-output support |
| **Resources** | ✅ | `msf://server/info` |
| **Resource templates** | ✅ | `msf://module/{module}` |
| **Elicitation** | ✅ (opt-in) | Destructive-action confirmation via `ctx.elicit`; falls back to the safety gate when the client cannot elicit |
| **Progress notifications** | ✅ | Long-running tools report progress via the MCP context |
| **Logging** | ✅ | Server-side structured logging |
| **Transports** | ✅ | `stdio` and streamable HTTP |
| **Prompts** | ➖ | Not implemented |
| **Sampling** | ➖ | Not used |

Protocol features are provided through **FastMCP** (pinned `>=2.10.3,<3.4.0`;
3.4.x currently fails to import — see `pyproject.toml`) on top of the official
`mcp` SDK (`>=1.28.1`).

## Comparison with the official Rapid7 MCP

| Capability | MetasploitMCP | Official Rapid7 MCP |
|---|---|---|
| Module search / info | ✅ | ✅ |
| Module execution | ✅ typed (exploit/aux/post) | ✅ generic |
| Non-destructive check | ✅ `check_vulnerability` | ✅ `ModuleCheck` |
| Async results | ✅ `get_module_results` | ✅ `ModuleResults` |
| DB intel (hosts/services/vulns/notes/creds/loot) | ✅ | ✅ |
| Payload generation | ✅ | ❌ |
| Listener / job lifecycle | ✅ | ❌ |
| Sessions | ✅ list / interact / terminate | ✅ list / read / write / stop |
| Safety gate for dangerous actions | ✅ (opt-in safe mode; **enabled by default**) | ✅ (default-off) |
| Rate limiting | ✅ (opt-in) | ✅ |
| Tool annotations / structured output / resources / elicitation | ✅ | partial |

## Hosting the docs (GitHub)

These Markdown files render directly on GitHub. To publish a docs **site**, enable
**GitHub Pages** (Settings → Pages → Build from `main` `/docs`), optionally with a
static generator (MkDocs/Jekyll). No site is required to read the docs in-repo.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## ADDED Requirements

### Requirement: Dangerous actions enabled by default with opt-in safe mode

Because this is an offensive-security tool whose full toolset has always been available, the system SHALL treat state-changing / offensive operations (exploit execution, payload delivery, session command execution, session termination, listener/job control) as "dangerous actions" that are ENABLED by default, and SHALL provide an opt-in "safe mode" (CLI flag or environment variable) that disables them while leaving read-only tools available. This deliberately inverts the official Rapid7 server's default-off posture to avoid regressing existing users.

#### Scenario: Dangerous tool allowed by default

- **WHEN** a client invokes a dangerous tool with no safety configuration applied
- **THEN** the system performs the operation normally

#### Scenario: Dangerous tool blocked in safe mode

- **WHEN** the operator has enabled safe mode and a client invokes a dangerous tool
- **THEN** the system refuses the operation and returns a structured error explaining that the server is in safe mode and how to re-enable dangerous tools

#### Scenario: Read-only tools always available in safe mode

- **WHEN** safe mode is enabled and a client invokes a read-only tool (e.g., database intel, module info, check)
- **THEN** the system performs the read-only operation normally

### Requirement: Optional rate limiting

The system SHALL support a configurable request rate limit that is OFF by default (to avoid throttling existing automation) and, when enabled, rejects requests that exceed the limit.

#### Scenario: Requests within limit succeed

- **WHEN** a client issues requests at or below the configured rate limit
- **THEN** all requests are processed

#### Scenario: Requests over limit are throttled

- **WHEN** a client exceeds the configured rate limit within the window
- **THEN** the system rejects the excess requests with a structured rate-limit error and does not execute the underlying operation

#### Scenario: Rate limit is configurable

- **WHEN** the operator sets a rate-limit configuration value
- **THEN** the enforced limit reflects the configured value

### Requirement: Safety configuration is discoverable

The system SHALL document and expose the current safety posture (whether dangerous actions are enabled and the active rate limit) via the health/status surface.

#### Scenario: Health output reports safety posture

- **WHEN** a client queries the health/status tool
- **THEN** the response indicates whether dangerous actions are enabled and the active rate-limit setting
Loading
Loading