hackerone-mcp
# hackerone-mcp
A local, **read-only** MCP server that connects your HackerOne researcher account
to Claude Desktop and Claude Code. It helps you find the best targets, analyze
program scopes, review your reports/earnings, and draft bug reports (which you
submit yourself — the server never writes to your account).
## How it works
Claude Desktop or Claude Code spawns this server as a local subprocess and talks
to it over stdio using the Model Context Protocol. Every tool is read-only. The
server reaches HackerOne over **two separate paths**: your private account data
through the **authenticated official API**, and public disclosed-report data
through an **unauthenticated public endpoint** (so your account is never involved
in those requests).
```
┌──────────────────┐ ┌──────────────────┐
│ Claude Desktop │ │ Claude Code │
└────────┬─────────┘ └────────┬─────────┘
└───────────┬───────────────┘
│ MCP over stdio
│ (launches: python -m hackerone_mcp)
▼
┌───────────────────────────────────────────────────────────────────── ┐
│ hackerone-mcp (local server) │
│ │
│ server.py ── FastMCP tools │
│ │ programs · scopes · count/filter · rank · weaknesses │
│ │ my_reports · earnings · draft_report · raw_get │
│ │ search_disclosed_reports · list_cwe_types · directory │
│ │ │
│ ├── config.py ◄──────── .env (H1_ENV_FILE: H1_USERNAME / TOKEN) │
│ │ │
│ └── tools.py ── orchestrates each request │
│ │ │
│ ├── cache.py ......... disk cache (1h TTL) — hit? return │
│ │ │
│ ├── analysis.py ...... rank / filter / summarize ┐ │
│ ├── hacktivity.py .... build query / project │ pure │
│ │ (no I/O) ┘ funcs │
│ │ │
│ ├── client.py ........ httpx + HTTP Basic auth ─────────┐ │
│ │ (GET only, 429 retry) │ │
│ └── graphql_client.py httpx POST, NO auth ──────────┐ │ │
│ (read queries only) │ │ │
└────────────────────────────────────────────────────────────-----│--│--┘
│ │
authenticated, read-only GET (HTTPS) ────────┼──┘
your account data │
▼
┌──────────────────────────────┐
│ api.hackerone.com/v1 │
│ /hackers/programs … │
└──────────────────────────────┘
unauthenticated, read-only POST (HTTPS)
public disclosed reports │
▼
┌──────────────────────────────┐
│ hackerone.com/graphql │
│ (public hacktivity) │
└──────────────────────────────┘
```
**Two flows, one pattern:** Claude calls a tool → `tools.py` checks `cache.py` →
on a miss it hits the right backend → a pure function (`analysis.py` /
`hacktivity.py`) shapes the result → it goes back up to Claude.
- **Account path** (your programs, scopes, reports, earnings): `client.py` makes
an authenticated read-only **GET** to `api.hackerone.com/v1`. Your token never
leaves your machine except as the Basic-auth header.
- **Public path** (disclosed-report / CWE / directory search): `graphql_client.py`
makes an **unauthenticated** read-only **POST** to `hackerone.com/graphql` — no
token or cookie is ever attached, so these requests carry no account risk.
## Requirements
- Python 3.10+ (tested on 3.13)
- A HackerOne API token: hackerone.com → Settings → **API Token**. Use the
narrowest read scope available.
## Install
```bash
git clone <this repo> hackerone-mcp
cd hackerone-mcp
python -m pip install -e .
```
## Configure credentials
Set two environment variables (these go in your MCP client config below):
- `H1_USERNAME` — your HackerOne username
- `H1_API_TOKEN` — the API token you generated
Optional: `H1_CACHE_DIR`, `H1_CACHE_TTL` (seconds, default 3600).
Verify your token works:
```bash
H1_USERNAME=you H1_API_TOKEN=xxxx python -m hackerone_mcp --check-auth
```
On Windows PowerShell:
```powershell
$env:H1_USERNAME="you"; $env:H1_API_TOKEN="xxxx"; python -m hackerone_mcp --check-auth
```
Expected: `OK: authenticated as you. N program(s) accessible.`
## Connect to Claude Desktop
Edit `claude_desktop_config.json`
(Windows: `%APPDATA%\Claude\claude_desktop_config.json`):
```json
{
"mcpServers": {
"hackerone": {
"command": "python",
"args": ["-m", "hackerone_mcp"],
"env": {
"H1_USERNAME": "your_username",
"H1_API_TOKEN": "your_api_token"
}
}
}
}
```
Restart Claude Desktop.
## Connect to Claude Code
```bash
claude mcp add hackerone --env H1_USERNAME=your_username --env H1_API_TOKEN=your_api_token -- python -m hackerone_mcp
```
Or add an `.mcp.json` entry with the same `command`/`args`/`env`.
## Tools
- `list_programs` — programs your account can access (`compact=true` for a small
handle/name/bounty/state listing; the full list is several MB)
- `count_programs` — totals only: program count, bounty programs, VDPs, and a
submission-state breakdown (use this for "how many ..." questions)
- `get_program` — full policy/details for a handle
- `get_program_scopes` — structured scopes, summarized in/out of scope
- `get_program_weaknesses` — the CWE/weakness types a program tracks
- `filter_programs` — compact list filtered by offers_bounties / submission_state / bookmarked (e.g. all VDPs)
- `list_my_reports` — your own submitted reports (compact; use `get_report` for full detail)
- `search_scopes` — search assets across your programs (`limit` for a quick scan)
- `rank_programs` — rank programs for hunting (bounties, scope, severity; `limit` for a quick scan)
- `get_balance`, `list_earnings` — your payments
- `get_report` — read a report by id
- `draft_report` — format a report in markdown (you submit it yourself)
- `raw_get` — authenticated read-only GET against any v1 API path
- `search_disclosed_reports` — search PUBLIC disclosed reports by keyword / severity / CWE / CVE / program; `sort` ("relevance"/"recent", default relevance for keyword searches) and `since`/`until` (YYYY-MM-DD) date bounds
- `list_cwe_types` — valid CWE names for the `cwe` filter
- `search_directory` — search the public program directory by name
> **Note:** `search_scopes` and `rank_programs` scan every program you can access
> (one API call per program on a cold cache — potentially hundreds). Results are
> cached for an hour, so the first call is slow and later calls are fast. Pass
> `limit` (e.g. 50) for a quick partial scan, or `refresh=true` to bypass the cache.
## Security
Your API token is stored in plaintext in the client config file. Protect that
file (restrict permissions), use a narrow-scope token, and revoke/rotate it from
HackerOne if it is ever exposed. This server makes **only read-only requests**
(authenticated GETs to the official API, plus unauthenticated read-only GraphQL
POSTs to the public hacktivity endpoint) — it cannot submit, edit, or delete
anything on your account.
## Public hacktivity search (Part 2)
`search_disclosed_reports`, `list_cwe_types`, and `search_directory` read
HackerOne's **public** disclosed-report data through its undocumented GraphQL
endpoint, **unauthenticated** — no token or cookie is sent, so these calls carry
no risk to your account. They are read-only (the server never sends mutations).
Because the endpoint is undocumented, the baked-in queries can break if HackerOne
changes its schema. The exact queries were captured on 2026-06-28 and saved to
`docs/superpowers/reference/hackerone-graphql-captures-2026-06-28.json`; re-capture
from a browser and update `graphql_client.py` if a hacktivity tool stops working.
## Development
```bash
python -m pip install -e ".[dev]"
python -m pytest -v
```
TDQS
Scored across 17 tools
Most tools have distinct purposes, with clear boundaries between listing programs, filtering, searching, and getting details. However, `list_programs`, `filter_programs`, and `search_directory` could cause minor confusion, and `raw_get` overlaps with any read operation.
All tools follow a consistent `verb_noun` snake_case pattern (e.g., `count_programs`, `get_program`, `search_disclosed_reports`). Even `raw_get` fits the pattern as an adjective-verb combination.
17 tools cover the HackerOne domain well—program management, report viewing, earnings, and search—without being excessive. Each tool serves a clear purpose within the read-only scope.
The tool surface is read-only, lacking any write operations (e.g., submitting reports, updating programs, or managing account settings). `draft_report` prepares a report for manual submission, but there is no tool to actually submit it, creating a dead end.