Every MCP server I audit, I end up running the same twenty curl commands. Fingerprint the endpoint. Pull the three well-known OAuth documents and diff them. Enumerate the tool list. Poke the error responses. Test the CORS headers. Over a dozen servers the pattern got old, so I packaged the methodology into one CLI.

mcp-recon is an open-source scanner that runs ten generic checks against a Model Context Protocol server and flags behavior that matches classes of publicly disclosed bugs. It does not declare a server “safe” or “unsafe.” It reports observations, and you interpret them in context.


Why I Built This

Three pieces of my own prior research kept recurring as the “starter move” on every MCP audit:

  1. OAuth scope enforcement bypass on a production MCP server (Zomato MCP writeup). The initial tell was that two .well-known/ documents on the same server advertised different scopes_supported lists. Inconsistent discovery docs are a smell.

  2. DNS rebinding in mcp-server-fetch (GHSA filed, CVE pending). The server made two outbound HTTP calls per tool invocation, each with an independent DNS resolution, and no IP pinning between them. Any MCP tool that takes a URL and does N > 1 outbound requests has this shape.

  3. Permission-prompt misrepresentation in Claude Code’s MCP trust model (five findings at jashidsany.com/security-research/ai-security). What the user saw in the consent dialog did not match what the server was about to execute. If a malicious MCP server can embed zero-width or bidi-override characters in tool names, the same class extends.

Each of those audits started with the same reconnaissance: fingerprint the server, enumerate tools, pull the well-known docs, read the error responses. After the fourth time, writing scripts for each one felt silly. A single tool that runs all the checks in order and flags the patterns I know to look for is a strict time-saver for me, and if other researchers find it useful, even better.

I also deliberately named it mcp-recon, not mcp-scan. Invariant Labs / Snyk ship a product called mcp-scan that is a more mature, commercial MCP security tool. mcp-recon is explicitly a lightweight reconnaissance scanner, not a competitor to their auditing platform. Picking a different name avoids inviting the wrong comparison.


What It Checks

Ten checks, all generic. None of them hard-code fingerprints of past bugs. Each one describes what it observed rather than declaring a verdict.

Check What it looks for Related bug class
fingerprint MCP protocol version, tools/list, resources/list, prompts/list baseline recon
transport-hygiene HTTP (not HTTPS), unexpected success on GET/OPTIONS, Server: headers transport confidentiality (CWE-319), routing misconfig
cors-policy Wildcard-with-credentials, echoed-Origin-with-credentials, null allowance browser-based cross-origin abuse (CWE-942)
auth-header-hygiene Infra hints, filesystem paths, stack traces inside WWW-Authenticate information disclosure in auth errors (CWE-209)
discovery-consistency Inconsistent scopes_supported / grant_types_supported across .well-known documents scope enforcement bypass
error-verbosity Stack traces, filesystem paths, secret-shaped tokens in error responses information disclosure (CWE-209, CWE-200)
tool-description-anomalies Zero-width, control, or bidi-override characters in tool names and descriptions permission-prompt misrepresentation
multi-request-pattern Tools whose inputs accept URLs; flags N > 1 outbound-request risk DNS rebinding TOCTOU
undocumented-capabilities MCP methods returning results outside advertised capabilities debug endpoint exposure
scope-binding Can a token with one scope call tools that advertised different scopes? Requires --token. authorization bypass (CWE-863, CWE-285)

Every flagged observation ships with a plain-English summary, the concrete evidence that triggered it, a suggested manual follow-up command, and references to the public CVEs or writeups that exemplify the class. The tool surfaces signals. The operator makes the judgment call.


Usage

Basic scan

$ mcp-recon scan https://example.com/api/mcp

target:     https://example.com/api/mcp
started:    2026-04-22T19:30:15+00:00
schema:     1.0    tool: 0.1.0
duration:   117 ms

+ fingerprint   (ran, 40 ms)
    protocol_version: 2024-11-05
    server_info: {'name': 'ExampleMCP', 'version': '1.0'}
    capabilities: ['tools', 'resources']
    tools: <list[2]>

+ discovery-consistency   (ran, 17 ms)
    paths_found: ['.well-known/oauth-authorization-server', '.well-known/openid-configuration']
    ! discovery documents disagree on scopes_supported   [medium]
        Two OAuth/OIDC discovery documents advertise different sets of
        supported scopes. This is a smell: it has preceded scope enforcement
        bypass bugs in other MCP and OAuth deployments.
        follow-up:
          curl https://example.com/.well-known/oauth-authorization-server
          curl https://example.com/.well-known/openid-configuration
          # compare scopes_supported manually

+ multi-request-pattern   (ran, 0 ms)
    tools_inspected: 2
    ! tools with URL-shaped input parameters   [low]
        One or more advertised tools accept URL-like parameters. If the
        server performs more than one outbound request per invocation,
        each request resolves DNS independently by default. A DNS-rebinding
        attacker can split the two lookups across different IPs.

... (8 more checks) ...

summary
  observations flagged:  2
  checks run:            9
  checks skipped:        1
  checks errored:        0
  exit code:             1

Two observations flagged, exit code 1. Worth reviewing before moving on. Neither is a vulnerability claim; both are patterns worth investigating manually.

Three output formats

mcp-recon scan <url>                      # human-readable (default)
mcp-recon scan <url> --output json        # machine-readable, versioned schema
mcp-recon scan <url> --output markdown    # paste into bug-bounty reports

The JSON format carries a schema_version field so downstream tools can pin to a version.

Proxy + token

# route through Burp or mitmproxy
mcp-recon scan <url> --proxy http://127.0.0.1:8080

# scope-binding probe on an OAuth-gated server
MCP_RECON_TOKEN=<access-token> mcp-recon scan <url>

The token is redacted from artifact files by default. Pass --include-secrets only when you need raw evidence and understand the risk.

Exit codes

Code Meaning
0 Clean. All checks ran, no observations flagged.
1 One or more observations flagged for review.
2 Scan error (target unreachable, protocol error).
3 Invalid arguments.

Exit codes make CI integration straightforward. Drop mcp-recon scan into a release pipeline for your own MCP server and fail the build on exit 1.


Artifacts

Every scan writes a directory of raw JSON artifacts to ./mcp-recon-artifacts/<target>_<timestamp>/:

report.json        the structured result (schema-versioned)
exchanges.json     every HTTP request/response pair, Authorization/Cookie
                   headers redacted by default

Directory is created chmod 700, files chmod 600. Secrets are redacted unless you pass --include-secrets.

The artifacts directory is the nmap -oA pattern: you can re-analyze without re-scanning, diff scans over time, and keep evidence for bug-bounty submissions without needing to replay the scan.


Honest Limits

Worth stating up front so nobody mistakes the tool for something it isn’t:

  • A clean scan does not mean a server is secure. The tool checks a finite set of known-issue patterns. It does not attempt comprehensive vulnerability coverage.
  • Observations are not vulnerabilities. They are signals that match classes of previously disclosed bugs. Always validate manually before reporting.
  • It is read-only at the MCP protocol layer. The scanner never calls state-changing tools (no update_cart, no send_message, no file writes). Worst case, it makes a tools/call with empty arguments during the scope-binding probe, which servers generally handle as a validation error rather than a mutation.
  • Rate limiting is on by default (100ms between requests). Use --aggressive only against infrastructure you own.
  • Do not run it against servers you don’t have permission to test. Unauthorized scanning may violate computer misuse laws in your jurisdiction. The tool is a scanner, and scanners belong to the operator who runs them responsibly.

The README opens with the same caution. I’d rather be clear up front than have someone run a clean scan, assume their server is audited, and get popped.


Security Considerations

The tool makes outbound HTTP requests to user-provided endpoints. The intended trust boundaries:

  1. The user is trusted. They choose what to scan.
  2. The target MCP server is not trusted. Its responses are attacker-controlled from the tool’s perspective.
  3. The artifacts directory is trusted (created chmod 700).

The main hardening choices:

  • No subprocess or shell execution. Nothing the server returns can become a command on the operator’s machine.
  • Authorization / Cookie / API-key headers redacted in saved artifacts by default.
  • No pickle, no arbitrary deserialization. All structured data is JSON.
  • Dependencies pinned to major versions (httpx, typer, rich).
  • CI runs with permissions: contents: read. A compromised third-party action cannot push commits or mint releases.
  • PyPI publishing uses Trusted Publishing (OIDC). No long-lived API tokens stored anywhere.

Full threat model in SECURITY.md on the repo.


Install

pipx install mcp-recon
mcp-recon --version

Plain pip install also works inside a venv. Requires Python 3.10 or later. Runs on Linux, macOS, Windows.


What Comes Next

The MVP is ten generic checks. A few things I want to add as the MCP ecosystem matures:

  • MCP stdio transport. Right now the tool is HTTP-only. Scanning a locally launched stdio MCP server would be useful for developer workflows.
  • Known-bad signature database. A small curated list of published advisories against specific MCP server projects + versions. I deliberately left this out of the MVP to avoid maintenance burden, but the ecosystem is picking up enough CVEs that it’ll start paying off.
  • Differential scanning. Compare two scans and flag only new findings. Handy for CI jobs that re-scan staging environments on every deploy.

If you use it and find a rough edge or a bug class I should cover, open an issue. Feedback from other researchers is what shapes where this goes.


Try It

github.com/jashidsany/mcp-recon · pypi.org/project/mcp-recon

pipx install mcp-recon
mcp-recon scan https://your-mcp-server.example/api/mcp

Related research this tool distilled from:


Jashid Sany - github.com/jashidsany