recon-mcp
Loads HackerOne program scope from local H1-Scope-Watcher snapshots to enforce scope boundaries during recon activities.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@recon-mcpcheck scope for example.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
recon-mcp
recon-mcp is a local Python MCP server for authorized, low-risk, human-led bug bounty recon. It provides lightweight helpers for scope checks, headers, robots.txt, sitemap.xml, JavaScript URL collection, endpoint extraction, URL deduplication, evidence notes, manual test planning, and campaign-based recon organization.
This project complements a separate Go DirFuzz MCP server. It does not implement directory fuzzing in Python. For scope, it can use local JSON snapshots written by H1-Scope-Watcher as the source of truth.
Safety Model
This server is designed for authorized, low-risk security testing only. Every network-facing Python tool checks configured scope before making requests and before following redirect targets. HTTP behavior is read-only, uses timeouts and small request delays, and avoids custom attack payloads.
Recon MCP blocks literal local, loopback, private, link-local, multicast, reserved, and unspecified IP targets. It also resolves hostnames before requests and before following redirects, then blocks any hostname that resolves to those unsafe IP ranges. This helps reduce DNS rebinding and accidental internal-network request risks while preserving a fail-closed recon model.
Sitemap XML parsing uses defusedxml so unsafe XML constructs are rejected safely instead of being parsed by the standard library XML parser.
It does not exploit vulnerabilities, bypass authentication, brute-force accounts, create accounts, perform login testing, send destructive requests, run high-volume scans, or scan outside configured scope. DNS resolved-IP checks and hardened XML parsing are defensive controls for authorized recon, not bypass or exploitation features.
Directory fuzzing belongs in the separate Go DirFuzz MCP server, with tools such as dirfuzz_scan, dirfuzz_scan_status, dirfuzz_cancel, dirfuzz_analyze, dirfuzz_list_scope, and dirfuzz_build_scan.
Related MCP server: shodan-mcp
Campaign Workflow
Campaigns organize scoped recon artifacts, finding candidates, evidence, memory, and reports under output/campaigns/<campaign_id>/. Creating a campaign checks configured scope first and fails closed when the target is not authorized.
Each campaign stores:
output/campaigns/<campaign_id>/
campaign.json
scope.json
audit.jsonl
recon/
findings/
evidence/
memory/
reports/Campaign-aware tools save JSON artifacts into the matching recon/ subfolder and append audit events to audit.jsonl. Network-facing campaign tools still rely on the existing scope-enforced fetch and JavaScript helpers.
Recommended campaign flow:
create_campaignfetch_headers_for_campaignfetch_robots_for_campaignfetch_sitemap_for_campaigncollect_js_urls_for_campaignextract_endpoints_for_campaignscore_endpointscreate_finding_candidatepromote_findingonly after manual validationcreate_campaign_evidence_notegenerate_campaign_summarygenerate_report_candidate_markdown
generate_campaign_summary writes reports/summary.md, and generate_manual_test_plan_for_campaign writes reports/manual_test_plan.md. Reports are local Markdown files only; nothing is auto-submitted anywhere.
Campaign Cleanup
Campaign cleanup is archive-first. archive_campaign moves a campaign from output/campaigns/ to output/archived_campaigns/ and marks its metadata as archived. This preserves evidence, findings, reports, and audit logs while keeping active campaign lists tidy.
Active campaigns are not directly deleted by MCP for safety. Permanent deletion, when used, only works on archived campaigns and requires the exact campaign ID as confirmation through delete_archived_campaign.
Finding Pipeline
Possible issues are not vulnerabilities. Every new candidate starts in the hallucination bin at findings/hallucinations/ with manual_validation_required: true.
Allowed status flow:
hallucinationtoneeds_manual_validationneeds_manual_validationtovalidatedvalidatedtoreport_candidateany status to
rejected
Report candidates require all gates to be true: scope confirmed, evidence saved, reproduced manually, impact proven, safe non-destructive testing, and report ready. The pipeline blocks direct jumps from hallucination to validated or report candidate.
Negative-result memory is stored in memory/negative_results.jsonl. These records document useful checks that did not produce findings; they are included in summaries and manual plans, but they are not treated as vulnerabilities.
The hallucination bin is intentional. It keeps AI-assisted or speculative leads separate until a human validates scope, evidence, reproducibility, impact, and safety.
Source Map Recon
Source maps can reveal original frontend source files, routes, API paths, GraphQL usage, environment names, feature flags, client configuration, and source file names. These are recon leads, not vulnerabilities by themselves.
Recon MCP handles source maps inside a campaign with a safe, explicit workflow:
Fetch JavaScript through the existing scope-checked HTTP helpers.
Detect
sourceMappingURLreferences without downloading by default.Resolve and scope-check every source map URL.
Skip out-of-scope source map URLs instead of fetching them.
Download only bounded, in-scope source map JSON.
Extract embedded
sourcesContentlocally inside the campaign folder.Analyze extracted files for endpoint candidates and manual-review signals.
Redact likely sensitive values in previews.
Recon MCP does not use unsafe remote external modes such as sourcemapper -jsurl https://target/app.js or sourcemapper -url https://target/app.js.map. External sourcemapper, if used later, must be local-file-only: it should accept only .map files already stored inside the campaign and write only inside the campaign extracted folder. No cookies, Authorization headers, tokens, custom auth headers, or remote URLs are passed to external tools. No reports are auto-submitted.
Source map workflow:
create_campaigncollect_js_urls_for_campaigndetect_sourcemap_references_for_campaigndownload_sourcemap_for_campaignextract_sourcemap_sources_for_campaignanalyze_sourcemap_sources_for_campaigngenerate_manual_test_plan_for_campaigncreate_finding_candidateonly if manual validation suggests a real issuepromote_findingonly after impact is provengenerate_campaign_summary
Installation
Use Python 3.11 or newer.
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"Configure Scope
Create a local config/scope.json from config/scope.example.json, then edit it for your authorized target scope. The local config/scope.json file is ignored so personal snapshot paths and active program scope do not get pushed.
{
"scope_source": "manual",
"h1_snapshot_dir": "",
"include_only_bounty_eligible": false,
"include_only_submission_eligible": true,
"allowed_domains": [
"example.com"
],
"user_agent": "ReconMCP/0.1",
"request_delay_ms": 500,
"max_requests_per_tool_call": 20,
"fetch_headers_method": "HEAD",
"blocked_domains": [
"localhost",
"127.0.0.1",
"0.0.0.0",
"::1"
]
}Set scope_source to h1_snapshots to load local H1-Scope-Watcher JSON files for scope checks. Scope config is cached briefly, and new snapshots are picked up without restarting the MCP server. Set scope_source to manual to use allowed_domains instead.
Exact domains and subdomains are allowed. For example, api.example.com matches example.com. H1 wildcard entries like *.example.com are normalized into host rules. Localhost, loopback, private IPs, link-local IPs, and blocked domains are rejected. If H1 snapshots are missing or invalid, scope checks fail closed.
Request hygiene settings:
user_agentsets the User-Agent used by read-only HTTP helpers. The default isReconMCP/0.1.request_delay_msadds a small delay before network requests. The default is500.max_requests_per_tool_callcaps collection helpers that can discover many request targets. The default is20.check_scope_batchaccepts up to 200 hosts or URLs per call.fetch_headers_methoddefaults toHEAD. IfHEADis blocked or fails before useful headers are available,fetch_headersfalls back to a safeGETthat requests only the first byte and still checks scope before every redirect hop.
H1-Scope-Watcher Snapshots
This project does not call any bug bounty platform API directly. H1-Scope-Watcher should fetch program scope and write plain JSON snapshots to disk.
When running H1-Scope-Watcher in Docker on Windows, use a bind mount so snapshots are visible on the host:
volumes:
- ./config.yaml:/app/config.yaml:ro
- ./snapshots:/app/snapshotsThat creates local JSON files such as:
D:/Tools/H1-Scope-Watcher/snapshots/program_handle.jsonPoint h1_snapshot_dir at that folder. Do not point Recon MCP at H1-Scope-Watcher config.yaml, .env, or any file containing API tokens.
Run the MCP Server
python .\server.pyThe server runs over stdio:
if __name__ == "__main__":
mcp.run(transport="stdio")Codex MCP Config Example
Replace paths with your real local paths.
[mcp_servers.recon]
command = "python"
args = ["D:/Tools/recon-mcp/server.py"]You can run this alongside your Go DirFuzz MCP server:
[mcp_servers.recon]
command = "python"
args = ["D:/Tools/recon-mcp/server.py"]
[mcp_servers.dirfuzz]
command = "D:/Tools/DirFuzz-Mcp-Monitor/dirfuzz-mcp.exe"
args = []
env = {
DIRFUZZ_WORDLIST_DIR = "D:/Tools/DirFuzz-Mcp-Monitor/wordlists",
DIRFUZZ_SCOPE_DIR = "D:/Tools/H1-Scope-Watcher/snapshots",
DIRFUZZ_OUTPUT_DIR = "D:/Tools/DirFuzz-Mcp-Monitor/output"
}The key idea: Python Recon MCP h1_snapshot_dir and Go DirFuzz MCP DIRFUZZ_SCOPE_DIR should point to the same H1-Scope-Watcher snapshots folder.
Available Python MCP Tools
health()check_scope(domain: str)resolve_scope_target(host_or_url: str, format: str | None = None)check_scope_batch(hosts_or_urls: list[str], format: str | None = None)get_scope_map()recommend_bugmap_parent(host_or_url: str, available_bugmap_targets: list[dict])explain_scope_decision(host_or_url: str)list_loaded_scope()fetch_headers(url: str)fetch_robots(url: str)fetch_sitemap(url: str)collect_js_urls(url: str)extract_endpoints_from_js(file_or_url: str)dedupe_urls(urls: list[str])create_evidence_note(finding: dict)generate_manual_test_plan(target_summary: dict)dirfuzz_integration_info()create_campaign(program: str, target: str, notes: str | None = None)list_campaigns(limit: int = 50)get_campaign(campaign_id: str)archive_campaign(campaign_id: str, reason: str | None = None)list_archived_campaigns(limit: int = 50)get_archived_campaign(campaign_id: str)delete_archived_campaign(campaign_id: str, confirm_campaign_id: str)fetch_headers_for_campaign(campaign_id: str, url: str)fetch_robots_for_campaign(campaign_id: str, url: str)fetch_sitemap_for_campaign(campaign_id: str, url: str)collect_js_urls_for_campaign(campaign_id: str, url: str)extract_endpoints_for_campaign(campaign_id: str, file_or_url: str, source_type: str | None = None)save_dirfuzz_analysis_for_campaign(campaign_id: str, analysis: dict)create_finding_candidate(campaign_id: str, finding: dict)get_finding(campaign_id: str, finding_id: str)list_findings(campaign_id: str, status: str | None = None)promote_finding(campaign_id: str, finding_id: str, target_status: str, reason: str, gate_updates: dict | None = None)demote_finding(campaign_id: str, finding_id: str, target_status: str, reason: str)reject_finding(campaign_id: str, finding_id: str, reason: str)create_campaign_evidence_note(campaign_id: str, finding: dict)score_endpoint(endpoint: dict | str)score_endpoints(endpoints: list[dict | str])record_negative_result(campaign_id: str, target: str, check_type: str, result: str, repeat_after: str | None = None, metadata: dict | None = None)list_negative_results(campaign_id: str, check_type: str | None = None)generate_manual_test_plan_for_campaign(campaign_id: str)generate_campaign_summary(campaign_id: str)generate_report_candidate_markdown(campaign_id: str, finding_id: str)detect_sourcemap_references_for_campaign(campaign_id: str, js_url: str)download_sourcemap_for_campaign(campaign_id: str, sourcemap_url: str)extract_sourcemap_sources_for_campaign(campaign_id: str, map_path: str)analyze_sourcemap_sources_for_campaign(campaign_id: str, extracted_dir: str | None = None)sourcemap_workflow_for_campaign(campaign_id: str, js_url: str)external_sourcemapper_info()
Legacy Example Workflow
Run H1-Scope-Watcher in Docker with snapshots written to a host-accessible folder.
Point Python Recon MCP
h1_snapshot_dirat that snapshots folder.Point Go DirFuzz MCP
DIRFUZZ_SCOPE_DIRat that same snapshots folder.Check scope with Python Recon MCP.
Fetch headers, robots.txt, and sitemap.xml.
Collect JavaScript URLs from in-scope pages.
Extract possible endpoints from JavaScript.
Use Go DirFuzz MCP for directory fuzzing after scope is confirmed.
Analyze DirFuzz results with
dirfuzz_analyze.Generate a manual test plan.
Create evidence notes for manually validated findings.
For campaign mode, prefer the campaign workflow above. Candidate findings are not vulnerabilities, everything starts in hallucinations until validated manually, reports are not auto-submitted, and DirFuzz remains separate in the Go DirFuzz MCP server.
Project Layout
recon-mcp/
├── pyproject.toml
├── README.md
├── server.py
├── config/
│ └── scope.example.json
├── recon/
│ ├── __init__.py
│ ├── h1_scope.py
│ ├── scope.py
│ ├── http_fetch.py
│ ├── js_analysis.py
│ ├── urls.py
│ ├── notes.py
│ ├── planner.py
│ ├── campaigns.py
│ ├── audit.py
│ ├── workflow.py
│ ├── findings.py
│ ├── endpoint_scoring.py
│ ├── memory.py
│ ├── sourcemaps.py
│ └── reports.py
├── output/
│ ├── logs/
│ ├── evidence/
│ ├── campaigns/
│ └── reports/
└── tests/
├── test_scope.py
├── test_h1_scope.py
├── test_urls.py
└── test_js_analysis.pyDevelopment
Run tests:
pytestRun the server:
python .\server.pyDisclaimer
Use this only for authorized bug bounty and security testing workflows. The server is intentionally scoped and conservative, and it is not an autonomous hacking agent.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/tobiasGuta/recon-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server