MCP server by bineeg
MCP FINGERPRINT
A passive fingerprinting tool for detecting and enumerating Model Context Protocol (MCP) servers across all standard transports.
CAUTION — PENETRATION TESTING TOOL
MCP Fingerprint is intended exclusively for authorised security assessments, penetration testing engagements, and defensive research. Running this tool against systems you do not own or have explicit written permission to test is illegal in most jurisdictions. The authors accept no liability for unauthorised or unlawful use.
This is a passive scanner — it performs standard MCP handshakes only. It does not exploit vulnerabilities, modify server state, or exfiltrate data.
What It Does
MCP Fingerprint identifies MCP servers by probing common paths and attempting the MCP initialisation handshake across every standard transport:
| Transport | Protocol | Layer | |---|---|---| | HTTP POST (Streamable HTTP) | JSON-RPC over HTTP | L7 | | Hybrid SSE (POST + streaming) | JSON-RPC + SSE | L7 | | SSE (Server-Sent Events) | GET stream + POST endpoint | L7 | | WebSocket | JSON-RPC over WS | L4/L7 | | Raw TCP Socket | Newline-delimited JSON-RPC | L4 | | Unix Domain Socket | Newline-delimited JSON-RPC | Local |
Installation
git clone https://github.com/bineeg/mcp-fingerprint
cd mcp-fingerprint
python -m venv .venv
source .venv/bin/activate
pip install httpx
Optional — WebSocket support:
pip install websockets
Usage
usage: mcp-scanner.py [-h] --host HOST [--port PORT] [--timeout TIMEOUT]
[-q] [--list-tools] [--no-color] [--debug]
[--concurrency CONCURRENCY] [--wordlist WORDLIST]
Options
| Flag | Default | Description |
|---|---|---|
| --host | (required) | Target hostname or IP address |
| --port | (optional) | Single port, range 8000-9000, or omit to probe the domain directly |
| --timeout | 5 | Per-request timeout in seconds |
| -q, --quiet | off | Suppress informational output — only show discovered servers |
| --list-tools | off | Enumerate and display available MCP tools after detection |
| --no-color | off | Disable ANSI colour output |
| --debug | off | Show raw HTTP status codes and responses during tool enumeration; suppresses the "run with --debug" hint |
| --concurrency | 10 | Max parallel probes in port-range mode |
| --wordlist | wordlists.txt | Path wordlist file — one path per line |
Examples
Probe a domain (no port)
python mcp-scanner.py --host target.com
Probe a specific port
python mcp-scanner.py --host 127.0.0.1 --port 9876
Probe a port range
python mcp-scanner.py --host 127.0.0.1 --port 8000-9000
Port range with higher concurrency
python mcp-scanner.py --host 127.0.0.1 --port 8000-9000 --concurrency 25
Enumerate tools on a found server
python mcp-scanner.py --host 127.0.0.1 --port 9876 --list-tools
Quiet mode — hits only
python mcp-scanner.py --host 127.0.0.1 --port 8000-9000 -q
Use a custom path wordlist
python mcp-scanner.py --host target.com --wordlist /path/to/custom-paths.txt
Debug tool enumeration failures
python mcp-scanner.py --host 127.0.0.1 --port 9876 --list-tools --debug
No colour output (for logging / piping)
python mcp-scanner.py --host target.com --no-color -q | tee results.txt
Path Wordlist
Paths probed are loaded from wordlists.txt in the tool's base directory. Edit this file to add or remove paths — no code changes required.
Default wordlists.txt:
# MCP Fingerprint - Path Wordlist
# One path per line. Lines starting with # are ignored.
/mcp
/sse
/
/api/mcp
/v1/mcp
/api/v1/mcp
Supply a custom wordlist at runtime with --wordlist:
python mcp-scanner.py --host target.com --wordlist ~/wordlists/mcp-extended.txt
Output
Server discovered
╔════════════════════════════════════════╗
║ MCP FINGERPRINT ║
╚════════════════════════════════════════╝
[*] Target: 127.0.0.1:9876
[✓] Port 9876 is reachable
[FOUND] DISCOVERED 1 MCP SERVER(S)!
[MCP-1]
URL : http://127.0.0.1:9876/sse
Transport : SSE (Server-Sent Events)
Layer : HTTP (L7)
Bidirectional : Asymmetric
Proxy Friendly : Yes
With --list-tools
Tools:
[1] read_file
Read the contents of a file from the filesystem
[2] web_search
Search the web and return results
Tool extraction failure (without --debug)
Tools:
[!] Tool extraction failed — tools/list rejected with HTTP 400
[*] Try running with --debug for more details
Tool extraction failure (with --debug)
Tools:
[!] initialize → HTTP 200
[!] tools/list → HTTP 400: {"error":"method not allowed"}
[!] Tool extraction failed — tools/list rejected with HTTP 400
Server exposes no tools
Tools:
[*] Server exposes no tools
Port range summary
[FOUND] Port 9876 — SSE (Server-Sent Events)
[FOUND] Port 8080 — HTTP POST (Streamable HTTP)
[✓] Found 2 MCP server(s)
Passive Scanning Notice
MCP Fingerprint is a passive tool. Its behaviour is limited to:
- Sending standard MCP
initializehandshakes - Sending
notifications/initializedas required by the MCP spec - Sending
tools/listrequests when--list-toolsis specified
It does not:
- Exploit any vulnerability
- Modify server-side state
- Inject malicious payloads
- Perform brute-force or denial-of-service attacks
Project Structure
mcp-fingerprint/
├── mcp-scanner.py # Entry point & CLI
├── wordlists.txt # Default path wordlist
└── scanner/
├── __init__.py
├── colors.py # ANSI colour codes
├── logger.py # Logging with quiet-mode support
├── protocol.py # MCP protocol constants (INIT, INITIALIZED, TOOLS_REQUEST)
├── transport_tester.py # All 6 transport probers
├── tool_enumerator.py # Tool listing via HTTP, Hybrid SSE, Legacy SSE
├── result_printer.py # Formatted result output
├── scanner.py # MCPScanner orchestrator
└── range_scanner.py # Concurrent port-range scanning
Legal Disclaimer
This tool is provided for educational and authorised testing purposes only. Usage against systems without prior written consent is prohibited and may violate computer fraud laws including but not limited to the Computer Fraud and Abuse Act (CFAA), the Computer Misuse Act (CMA), and equivalent legislation in your jurisdiction. Always obtain proper authorisation before use.