hartrace
An MCP server for analyzing HTTP traffic captures (HAR files) — built so an AI agent can answer questions about a capture without reading the raw JSON into its context window.
Its distinguishing feature is value provenance tracing: given any token, cookie, id, or payload field, hartrace reconstructs where the value was produced (which response set it) and where it was consumed (which later requests sent it), as a compact timeline. Every other tool — search, inspection, diffing — is built to return small, structured results with hard size caps, so analysis stays cheap regardless of how large the capture is.
load_har("session.har")
trace_value("session", "<csrf token>")
→ set_by: response #4 body, JSON path data.csrf
→ used_in: request #9 header X-CSRF, request #9 body field token
Why this exists
HAR files are large, deeply nested, and repetitive. The two common ways an AI ends up analyzing them are both bad: writing throwaway extraction scripts every session, or pasting raw HAR JSON into the context window (slow, expensive, and it overflows on anything real). A 100-entry capture can be several megabytes; a single gzipped response can be hundreds of kilobytes.
hartrace moves the extraction and correlation to the server. Tools return only what was asked for, capped. The questions that normally require reading many entries by hand — where did this auth token come from? which request produced this cookie? where is this id reused? — are answered in one call.
Features
- Provenance tracing —
trace_valuefollows any value across the capture (responses → requests), reporting JSON paths for body fields. Works on tokens, cookies, ids, headers, and payload fields alike, not just cookies. - Search toolkit — full regex search across URLs, headers, and request/response bodies; header finder; URL/endpoint finder; query-parameter extraction.
- Inspection — per-request and per-response retrieval with base64 + gzip/deflate decoding, nested-JSON unwrapping, binary detection, and size caps.
- Lifecycle maps —
cookie_mapandtoken_mapsummarize how cookies and high-entropy secrets flow through a session. - Diffing — compare two captures by
(method, url, ordinal)so repeated calls to the same endpoint align. - Loading — from a local path or an
http(s)URL (with SSRF protection and a size cap). - Safe by construction — every list/search tool paginates with server-clamped limits; secrets are redacted in inspection output; no tool raises to the transport (errors are returned as structured values).
Installation
Requires Python 3.10+.
# from PyPI (once published)
pipx install hartrace
# or zero-install with uv
uvx hartrace
# or from source
git clone https://github.com/rafsanbasunia/hartrace
cd hartrace
pip install -e .
The only runtime dependency is fastmcp.
Quick start with Claude Desktop
Add the server to claude_desktop_config.json:
{
"mcpServers": {
"hartrace": {
"command": "uvx",
"args": ["hartrace"]
}
}
}
Or, running from source:
{
"mcpServers": {
"hartrace": {
"command": "python",
"args": ["/absolute/path/to/hartrace/har_mcp.py"]
}
}
}
Restart Claude Desktop, then talk to it naturally:
"Load
~/captures/login.harand tell me where the CSRF token comes from." "Which requests reuse the session cookie?" "Diffbefore.harandafter.har— what's new?"
Other MCP clients
hartrace is a standard stdio MCP server, so it works in any MCP-capable client — only the config file and wrapper key differ.
-
Cursor (
.cursor/mcp.json) and Windsurf use the same"mcpServers"block shown above. -
VS Code (
.vscode/mcp.json) uses a"servers"key with an explicit type:{ "servers": { "hartrace": { "type": "stdio", "command": "uvx", "args": ["hartrace"] } } }
In every case the command/args are identical to the Claude Desktop example.
Tools
hartrace exposes 19 tools. Refer to a loaded capture by the name returned from load_har.
Loading
| Tool | Purpose |
|---|---|
list_har_files(dir) |
List .har files in a directory to choose from. |
load_har(path) |
Load a capture from a local path. Returns the assigned name. |
load_har_url(url) |
Load a capture from an http(s) URL (SSRF-guarded, size-capped). |
list_hars() |
List currently loaded captures. |
unload_har(name) |
Drop a capture to free memory. |
Inspection
| Tool | Purpose |
|---|---|
list_requests(name, filter, …) |
Overview rows: index, method, URL, status, response size. |
get_request(name, index) |
One request, decoded; secrets redacted. |
get_response(name, index, max_chars) |
One response body, decoded (base64/gzip), JSON unwrapped, capped. |
get_headers(name, index) |
Request and response headers for one entry. |
get_query_params(name, index) |
Parsed query string of one request. |
Search
| Tool | Purpose |
|---|---|
search_regex(name, pattern, scope) |
Regex over url | req_headers | resp_headers | req_body | resp_body | all. |
find_header(name, header_name) |
Every entry carrying a header, with raw values. |
find_urls(name, pattern) |
Requests whose URL matches a pattern. |
list_endpoints(name, group_by) |
Unique endpoints with call counts. |
Provenance
| Tool | Purpose |
|---|---|
trace_value(name, value) |
Where a value was set vs. used — the full timeline. |
trace_header(name, header_name) |
Resolve a header's value(s) and trace their origin. |
cookie_map(name) |
Every cookie's set/used lifecycle and attributes. |
token_map(name, all_tokens) |
High-entropy secrets and how they propagate. |
Comparison
| Tool | Purpose |
|---|---|
diff_hars(a, b) |
Requests unique to each capture; matched by (method, url, ordinal). |
Every tool's full description — including argument semantics and a worked example — is available to the model through the MCP protocol.
How provenance tracing works
On first trace, hartrace builds a correlation index over the capture (cached for subsequent calls). For a queried value it separates hits into two sides:
set_by— responses that produced the value: aSet-Cookieheader, or a response body (with the JSON path when the value sits inside parseable JSON).used_in— later requests that sent the value: in a request header, a cookie, or a request body field (again with JSON path where applicable).
An empty set_by means the value was supplied by the client rather than produced by any captured response — for example a pre-existing OAuth token. origin is the earliest producer; timeline is the ordered list of entry indices touched.
Values shorter than four characters are refused, because short strings match everywhere and the result would be noise rather than signal.
Design and safety
- stdio transport only. The server communicates over stdin/stdout per the MCP spec. All logging is routed to stderr so it cannot corrupt the protocol stream. There is no web UI, port, or background process.
- Bounded output. List and search tools paginate with
limit/offset, and limits are clamped server-side (a request for a million rows returns the cap, not a million rows). Response bodies are capped bymax_chars. These bounds are what make token usage predictable. - Bounded memory. Captures are rejected above 500 MB or 50,000 entries; nested-JSON decoding is depth- and size-limited.
- Redaction. Inspection tools mask sensitive header values and high-entropy secrets as
<REDACTED len=N>, using a configurable header list plus a generic Shannon-entropy heuristic — not a vendor-specific token shape. Provenance tools correlate on the real value but display only a redacted preview. (find_headerintentionally returns raw values, since its purpose is to extract a value to trace.) - SSRF protection.
load_har_urlrefuses non-http(s)schemes and any host resolving to a private, loopback, link-local, reserved, or multicast address (including cloud metadata endpoints), and enforces the size cap on download. - No exceptions across the boundary. Every tool returns a structured
{error: "..."}on failure rather than raising, so the agent always receives an actionable message.
The server contains no vendor-specific logic. Helpers such as nested-JSON unwrapping are generic and apply to any deeply nested response.
Development
pip install -e ".[dev]"
pytest
The suite covers parsing and decoding, redaction and entropy detection, provenance tracing (cookie and non-cookie values, JSON-path resolution), the search toolkit, URL loading and SSRF guards, and the tools driven through the actual FastMCP call path.
Layout:
har_mcp.py MCP server: tool definitions and the stdio entry point
har_parser.py Parsing, decoding, redaction, and the in-memory store
provenance.py Correlation index and the trace / cookie / token tools
search.py Regex, header, URL, and endpoint search
config.json Redaction settings (sensitive headers, entropy thresholds)
tests/ pytest suite
Configuration
config.json adjusts redaction without code changes:
{
"sensitive_headers": ["authorization", "cookie", "set-cookie", "x-csrf-token", "x-api-key"],
"entropy_min_len": 24,
"entropy_bits_min": 3.5
}
sensitive_headers are always redacted by name; any other value is redacted if it exceeds entropy_min_len characters and entropy_bits_min bits of Shannon entropy per character.
License
MIT. See LICENSE.
Metadata
Release files for hartrace 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| hartrace-0.1.0.tar.gz | 32.3 kB | Without provenance | Details for hartrace-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| hartrace-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for hartrace-0.1.0-py3-none-any.whl |
Total release size: 57.9 kB
Release files / hartrace-0.1.0.tar.gz
| Download URL | hartrace-0.1.0.tar.gz |
|---|---|
| Size | 32.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a7ca5e61f9cb7d56f7325a6ff6da7fc9c81e1b4bc9b16641d8c53b83bc0c7f23
|
|
BLAKE2b-256 checksum How to use checksums |
3bd26a93b695bafbf39472697aaa20787fb05c19f2e1750711a215ae8168e79f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / hartrace-0.1.0-py3-none-any.whl
| Download URL | hartrace-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3112f4c5bd68470124cf9be7b5b8939b517a070f4d7ab5ebd499f0c6521401d7
|
|
BLAKE2b-256 checksum How to use checksums |
f7e6d5182002cd3059517f62bc4b3c00708411de58345f446ba6529ee3284388
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Security for hartrace 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.