har-mcp
# har-mcp
**Let your AI agent debug web performance and failures from a HAR file, without ever seeing your secrets.**
<!-- mcp-name: io.github.0xmortuex/har-mcp -->
har-mcp is an [MCP](https://modelcontextprotocol.io) server that analyzes HAR files exported from
browser DevTools (Chrome, Firefox, Safari, Postman, mitmproxy). It answers the questions you
actually ask of a capture: what is slow and *why* (blocked, DNS, connect, TLS, server wait or
download), what failed and what triggered it, what the page-load waterfall and critical path look
like, and what is inside one specific request.
**How it differs from the other HAR MCP servers.** Several exist
([tjamet/har-mcp](https://github.com/tjamet/har-mcp),
[katana-security/har-mcp](https://lobehub.com/mcp/katana-security-har-mcp),
[xuxu777xu/har-mcp](https://github.com/xuxu777xu/har-mcp),
[naotaka3/mcp-har-server](https://github.com/naotaka3/mcp-har-server),
[polybeta2/har-mcp-server](https://glama.ai/mcp/servers/polybeta2/har-mcp-server)). From their READMEs
they lean towards listing endpoints, security auditing or reverse-engineering an API (replay,
curl export). har-mcp is built for the other job, **performance and failure debugging**, and adds:
- **Timing math, not just a list.** Every request gets a phase breakdown and the dominant
phase with a plain-English hint. `waterfall` draws the timeline and computes the **critical path**.
- **Real streaming.** A hand-rolled incremental JSON reader decodes one entry at a time. A 100 MB HAR
is indexed in under a second using about 30 MB of RAM (measured, and tested). No database, **no
dependencies beyond `mcp`**.
- **Secrets are masked by default, and that is tested.** Authorization, cookies, tokens in URLs,
headers and JSON/form bodies, JWTs and API-key shapes show as `<redacted:N>` (name and length
only). The test suite plants 18 distinct fake secrets in a HAR and asserts none of them appears in the
output of any tool.
- **`redact_har`** writes a sanitized copy you can attach to a bug report. It never overwrites.
- **A `--dir` sandbox** so the agent can only read and write where you allow.
## What it looks like
Real output on a generated Chrome-style capture:
```
> slowest_requests limit=2
Slowest 2 of 15 requests by total time:
1. #3 GET 200 910 ms https://example.com/api/data?api_key=<redacted:20>&page=2
send 1 ms | wait 900 ms | receive 9 ms
dominated by wait (99%): the server took long to answer (time to first byte): look at the backend, not the network
2. #11 POST 503 630 ms https://api.example.com/oauth/token#access_token=<redacted:20>
dns 8 ms | connect 5 ms | tls 15 ms | send 1 ms | wait 600 ms | receive 1 ms
dominated by wait (95%): ...
> request_detail index=0
#0 GET https://example.com/
Status: 200 OK h2 server 93.184.216.34 connection 443
Timings: blocked 5 ms | dns 20 ms | connect 10 ms | tls 30 ms | send 1 ms | wait 200 ms | receive 50 ms
Request headers (3):
Authorization: Bearer <redacted:31>
Cookie: sessionid=<redacted:23>; theme=<redacted:4>
X-Custom: <redacted:57>
Response headers (2):
Set-Cookie: refresh=<redacted:23>; Path=/; HttpOnly
> waterfall
0 GET 200 example.com/ ds========rr 316 ms
1 GET 200 example.com/app.js ====rrrrrrrrrrrrrrr 503 ms
3 GET 200 example.com/api/data?api_ke... ================================== 910 ms
Critical path (4 requests, basis: initiator and redirect links): 2086 ms wall-clock from #0 start to #6 end, 1140 ms busy, 946 ms idle between
```
## Install
You need [uv](https://docs.astral.sh/uv/) (or pip).
**Claude Code**
```bash
claude mcp add har -- uvx har-mcp --dir "/path/to/your/hars"
```
**Claude Desktop** (`claude_desktop_config.json`)
```json
{
"mcpServers": {
"har": {
"command": "uvx",
"args": ["har-mcp", "--dir", "C:\\Users\\you\\Downloads"]
}
}
}
```
`--dir` is the folder the server may read HARs from and write redacted copies to. Repeat it for
several folders. Without it, the current directory is used, which for a desktop app is rarely what
you want, so set it. Relative paths in tool calls are resolved against the first `--dir`.
With pip: `pip install har-mcp`, then run `har-mcp --dir <folder>`.
## Tools
| Tool | What it does |
|------|--------------|
| `har_overview` | Entries, pages and page timings, time range, totals by type / domain / status class, transferred vs uncompressed bytes, cache hit/304 stats. Start here. |
| `slowest_requests` | Top N by total time, each with its phase breakdown and the dominant phase plus a hint. |
| `failed_requests` | 4xx/5xx, status 0 and browser-flagged errors (`net::ERR_...`), with the reason and the initiator when recorded. |
| `find_requests` | Filter by URL substring or regex, method, status (`404`, `4xx`, `200-299`), MIME, domain, start-time window. Capped, with the total match count. |
| `request_detail` | One request by `#index`: headers, query params, sizes, timings, redirect chain, initiator, body preview (truncated, binary-safe, base64-aware). |
| `waterfall` | ASCII timeline with DOMContentLoaded/load markers and the critical path. |
| `redact_har` | Write a sanitized copy. Never overwrites. |
Every tool except `har_overview` and `redact_har` takes `include_secrets` (default `false`).
## Try asking
- "Open `C:\Users\me\Downloads\checkout.har`. Why is the page slow?"
- "Which three requests dominate load time, and is it the server or the network?"
- "What failed in this capture, and what script triggered each failure?"
- "Show me the waterfall for page_1 and tell me what the critical path is."
- "Find all POSTs to `/api/` that returned 5xx and show me the first one in detail."
- "Is anything blocked behind a long TLS handshake or DNS lookup?"
- "Make a redacted copy of this HAR I can attach to a support ticket."
## Timing math (so you can trust the numbers)
- A timing of `-1` or a missing key means "does not apply" and counts as 0 ms.
- Per the HAR spec `ssl` is **part of** `connect`; the report shows TCP connect and TLS separately
(`connect 10 ms | tls 30 ms` for a `connect: 40, ssl: 30` entry) and does not double count. If a
tool reports `ssl` larger than `connect`, it is treated as separate and added.
- The total is the entry's `time` when present, otherwise the sum of the phases.
- "Dominant phase" is the largest phase as a share of the summed phases.
- Transfer size prefers Chrome's `_transferSize`, else `headersSize + bodySize`. "Served from
cache" means Chrome's `_fromCache` or a HAR `cache.beforeRequest`; HTTP 304 is counted as revalidated.
- The critical path follows redirects and `_initiator` links to the chain that finishes last. If
the HAR has neither (most non-Chrome exports), it falls back to the set of non-overlapping requests
with the most busy time and says so.
## Security
HAR files hold everything a browser sent: session cookies, bearer tokens, OAuth codes, passwords.
- **Masked by default.** URLs, headers, cookies, query parameters, request and response bodies pass
through the masker before they reach the model. A masked value is `<redacted:N>` where N is its
length. Masking works by name (authorization, cookie, token, password, api_key, ...), by shape
(JWT, GitHub, AWS, Slack, Stripe, Google keys, `Bearer ...`) and by context (`token=...` in text,
`"password": "..."` in JSON, `<apiKey>..</apiKey>` in XML, multipart fields).
- **Filters match what you may see.** `url_contains` / `url_regex` run against the masked URL, so the
agent cannot binary-search a masked token through filters.
- **`include_secrets=true` is opt-in per call.** Only use it when you asked for raw values.
- **Sandbox.** Only files under `--dir` (symlinks resolved, `..` rejected) can be read or written.
`redact_har` refuses to overwrite and refuses `output == input`.
- **Limits you should know.** A secret with an innocent name and shape in a URL *path*, an HTML page
or a binary body is not recognised. Binary bodies are copied unchanged by `redact_har`. Always
skim a redacted HAR before sharing it. Response bodies sent to the model are text previews you
can shorten with `body_chars`.
- Nothing is sent anywhere by har-mcp itself. It makes no network requests.
## Compatibility
Tested with generated Chrome, Firefox, Safari, Postman (UTF-8 BOM, string status, UTC offsets,
no pages) and mitmproxy (microsecond timestamps, missing timings and `time`, no `startedDateTime` on
some entries) shaped files. Chrome extensions `_initiator`, `_priority`, `_resourceType`,
`_transferSize`, `_fromCache`, `_error` are used when present and not required. I have not run it
on hand-exported captures from every browser version, so tell me if a real file misbehaves.
Entries are numbered by their 0-based position in `log.entries`. If a file has no `startedDateTime`
for an entry, it is listed but cannot be drawn on the waterfall; the output says so.
## Tests
```bash
uv sync --extra test
uv run pytest tests # 148 tests, ~10 s
uv run pytest tests -m slow # builds and indexes a 100 MB HAR, asserts bounded memory
uv run ruff check src tests && uv run mypy --strict src
```
The tests generate realistic HARs with hand-computed numbers (every total, dominant phase, byte
count and critical path is asserted exactly), the reader is checked against `json.load` at chunk
sizes from 1 byte up, and a stdio test launches the real server and calls every tool over MCP.
## Learn how it is built
[har-mcp-the-hard-way](https://github.com/0xmortuex/har-mcp-the-hard-way) is a 7-module tutorial that
builds a minimal version from scratch: HAR anatomy, streaming JSON, timing math, redaction design,
waterfall rendering, the MCP wrapper and testing.
## License
MIT
TDQS
Scored across 7 tools
Each tool has a distinct role in the HAR workflow: overview, slowest requests, failed requests, discovery, single-request detail, timeline visualization, and sanitization. Although find_requests overlaps conceptually with slowest_requests and failed_requests, their outputs and intended use are clearly differentiated.
All names use snake_case and are readable, but they mix noun-phrase names (har_overview, slowest_requests, failed_requests, request_detail, waterfall) with verb-phrase names (find_requests, redact_har). The convention is not a single predictable pattern, though it remains understandable.
Seven tools is well-scoped for HAR analysis, covering discovery, drill-down, visualization, and sanitization without redundant endpoints. Each tool earns its place and supports a clear step in the analysis workflow.
The surface covers the full practical lifecycle for examining and sharing a HAR: high-level summary, bottleneck and failure inspection, request lookup and detail, page-load visualization, and safe redaction. No obvious operational gap remains for the stated purpose.