Skip to main content
Glama
README.md
# h1-mcp

A small, **read-only** [Model Context Protocol](https://modelcontextprotocol.io) server for the
[HackerOne Hacker API](https://api.hackerone.com/getting-started-hacker-api). Use it from
**Claude Code**, **Codex** and **opencode** to pull program policy, structured scope, scope
exclusions, hacktivity (dedup / prior art) and your own reports straight into the model.

Deliberately **eight terse tools** — every tool schema is a permanent context cost, so the surface
stays small and the output is compact JSON.

> Read-only by design: it only ever issues `GET` requests. It cannot submit or modify anything.

---

## What you get

| Tool | What it does |
|------|--------------|
| `hackerone_list_programs` | Programs your token can see. Filter by bounty eligibility, submission state or name. |
| `hackerone_get_program` | Program metadata + policy; optionally include scopes and/or exclusions in one call. |
| `hackerone_get_structured_scopes` | In-scope assets: identifier, type, bounty eligibility, max severity. |
| `hackerone_get_scope_exclusions` | Report categories the program excludes from rewards. |
| `hackerone_check_in_scope` | Is this host/URL/IP/CIDR in scope? Matches wildcards, domains, URLs, IPs and CIDRs. |
| `hackerone_hacktivity_search` | Disclosed reports by Lucene query (dedup and prior art). |
| `hackerone_search_disclosed_reports` | Disclosed reports for one program. |
| `hackerone_my_reports` | Your own submitted reports (state, severity, bounty). |

Why this over the stock API wrapper:

- **`list_programs`** so the agent can *discover* handles instead of being told them.
- **`check_in_scope`** — a real wildcard/domain/URL/IP/CIDR matcher with exclusions as caveats.
- **Batched context** — `get_program(with_scopes=True, with_exclusions=True)` in one round-trip.
- **Polite client** — `Retry-After`-aware backoff on `429`/`5xx`, automatic pagination, typed models.

---

## Requirements

- Python **3.11+**
- [uv](https://docs.astral.sh/uv/) (recommended) or pipx/pip
- A HackerOne account with an API token: <https://hackerone.com/settings/api_token/edit>

---

## Install

### 1. Install the server

```bash
uv tool install git+https://github.com/gabdevele/h1-mcp
```

This puts an `h1-mcp` executable on your `PATH` (`~/.local/bin`). Make sure that directory is on
`PATH` (it usually is).

<details>
<summary>No uv? use pipx</summary>

```bash
pipx install git+https://github.com/gabdevele/h1-mcp
```
</details>

<details>
<summary>Zero-install (run straight from git)</summary>

```bash
uvx --from git+https://github.com/gabdevele/h1-mcp h1-mcp --help
```

`h1-mcp` falls back to this form automatically when it is not installed, so the generated client
configs work either way.
</details>

### 2. Store your credentials (once)

```bash
h1-mcp init
# HackerOne username: your-handle
# HackerOne API token: ****
```

This writes `~/.config/h1-mcp/env` with mode `0600`. Credentials live in **one** place, so no client
config ever embeds a secret. You can also override the path with `H1_MCP_ENV`, or just export
`H1_USERNAME` / `H1_API_TOKEN`.

### 3. Verify

```bash
h1-mcp doctor
# OK - authenticated. Example program visible: security
```

### 4. Register the server in your client

```bash
h1-mcp install --client all        # claude + codex + opencode
# or individually
h1-mcp install --client claude
h1-mcp install --client codex
h1-mcp install --client opencode
```

`install` uses each client's own CLI where possible, and prints a snippet when it cannot. To just
see the config without writing anything:

```bash
h1-mcp config --client all
```

Restart the client afterwards.

---

## Client setup (manual)

### opencode

Add to `~/.config/opencode/opencode.jsonc`:

```jsonc
{
  "mcp": {
    "hackerone": {
      "type": "local",
      "command": ["h1-mcp"],
      "enabled": true
    }
  }
}
```

### Claude Code

```bash
claude mcp add hackerone -s user -- h1-mcp
claude mcp list
```

Or add this to `.mcp.json` / `~/.claude.json`:

```json
{
  "mcpServers": {
    "hackerone": { "command": "h1-mcp", "args": [] }
  }
}
```

### Codex

```bash
codex mcp add hackerone -- h1-mcp
codex mcp list
```

Or in `~/.codex/config.toml`:

```toml
[mcp_servers.hackerone]
command = "h1-mcp"
args = []
```

### Any other MCP client

It is a plain stdio server: run `h1-mcp` (no arguments). Credentials are read from the environment
or `~/.config/h1-mcp/env`, so nothing else needs configuring.

---

## Usage

Once registered, just talk to your agent. Examples:

- “List programs that offer bounties and mention their max severity in scope.”
- “Is `api.acme.com` in scope for the `acme` program? Any exclusions I should worry about?”
- “Summarize the `acme` policy and list the top 10 in-scope assets.”
- “Find disclosed XSS reports for `acme` from the last year.”
- “Show my reports that are still `new`.”

You can also drive it directly:

```bash
h1-mcp serve            # run the stdio server (what the clients call)
h1-mcp doctor           # check credentials + connectivity
h1-mcp --version
```

---

## Configuration

| Env var | Default | Purpose |
|---------|---------|---------|
| `H1_USERNAME` | – | HackerOne username (wins over the file). |
| `H1_API_TOKEN` | – | HackerOne API token. |
| `H1_MCP_ENV` | `~/.config/h1-mcp/env` | Path to the shared credentials file. |
| `H1_MCP_HOME` | `~/.config/h1-mcp` | Directory for the default file. |

Resolution order: process environment → `H1_MCP_ENV` file → `./.env`.

### Security notes

- `h1-mcp init` writes the credentials file as `0600`.
- `.env` and `*.env` are git-ignored; never commit tokens.
- The server is read-only and only sends the token to `api.hackerone.com` over HTTPS.

---

## Development

```bash
git clone https://github.com/gabdevele/h1-mcp
cd h1-mcp
uv sync --extra dev
uv run pytest
uv run ruff check src tests
uv run h1-mcp doctor
```

Layout:

```
src/h1_mcp/
  client.py    # HackerOne Hacker API client (retries, pagination, typed models)
  models.py    # pydantic response models
  scope.py     # pure in-scope matcher (wildcard/domain/URL/IP/CIDR)
  server.py    # the MCP server + 8 tools
  config.py    # credential loading/storage
  cli.py       # serve / init / doctor / install / config
tests/         # unit tests for scope, client and server (no network)
```

---

## License

MIT — see [LICENSE](LICENSE).

TDQS

B3/5.0

Scored across 8 tools

Disambiguation3/5

There is meaningful overlap: get_program can optionally return structured scope and exclusions, duplicating get_structured_scopes and get_scope_exclusions, and hacktivity_search vs search_disclosed_reports both search disclosed reports. Descriptions clarify scope (global Lucene vs per-program) and intent, but an agent can reasonably hesitate between the program-metadata tool with flags and the dedicated scope tools.

Naming Consistency3/5

Most tools use a readable snake_case verb_noun pattern (list_programs, get_program, get_structured_scopes, check_in_scope). However hacktivity_search reverses the order compared to search_disclosed_reports, and my_reports is a possessive noun rather than a verb, creating mixed conventions.

Tool Count4/5

Eight tools is a well-sized surface for the HackerOne domain, comfortably within the 3-15 range. There is slight redundancy because get_structured_scopes and get_scope_exclusions overlap with get_program's flags, so not every tool strictly earns an independent place.

Completeness4/5

The set covers program discovery, policy/scope lookup, scope checking, disclosed-report research, and a user's own reports—core hunting workflows. Gaps are minor for a read-oriented server: no report submission, no direct get-by-ID for disclosed reports, and program policy is noted as truncated.

Maintenance

ActivityMaintained
ResponsivenessNo issues