Skip to main content
Glama

har-mcp

English | 简体中文

An MCP server for analyzing large HAR files with schema-less protobuf / gRPC decoding, built for reverse-engineering and traffic research workflows.

It turns huge, opaque HAR captures (full of binary protobuf bodies) into targeted, structured queries — so your AI agent no longer has to "drop out to Python" to decode a single field.

Why

Capture tools (Reqable, Charles, mitmproxy, …) export HAR. For apps that speak protobuf/gRPC (Google Play, gRPC services, …) those HAR files are large and their bodies are opaque binary. Existing options either truncate big bodies or force you into manual side-scripts.

har-mcp is different:

  • No silent truncation. Bodies are stored in full. Large bodies return a sized preview by default and the whole payload on demand (full:true) or via structured decoding.

  • Schema-less protobuf decoding. Bodies are decoded without any .proto — field numbers, wire types, nested messages, strings, bytes — so you can inspect obfuscated/proprietary protocols immediately.

  • Any path, no lock-in. Every tool accepts an arbitrary .har path (or a registered name). No fixed working directory to configure.

  • Sidecar Database (.har.db). Each data.har gets an isolated companion SQLite file data.har.db in the same directory, making it straightforward for developers to inspect, query, or delete per-file databases.

  • Scales to 100 MB+ HAR. Streaming index build + companion SQLite schema (slim metadata table vs. isolated body blobs) keep listing/filtering instant and memory flat.

  • ID-addressed, Reqable-friendly. Entries are addressed by Reqable's own _id / _uid, mirroring the official Reqable MCP's filter → id → operate-by-id pattern.

Getting started

1. Install Bun

har-mcp runs on Bun (it uses the built-in bun:sqlite, so there are no native dependencies to compile).

# macOS / Linux
curl -fsSL https://bun.sh/install | bash
# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"

Verify with bun --version (requires ≥ 1.1).

2. Get har-mcp

Pick one:

  • From source (recommended):

    git clone https://github.com/yynag/har-mcp.git
    cd har-mcp
    bun install
  • Compiled JS from Releases: download index.js from the latest release — built by CI with all dependencies bundled, so you only need Bun to run it (bun /path/to/index.js).

3. Configure your MCP client

No directory to configure — you point at HAR files by path through the tools (see step 4).

opencode (opencode.jsonc):

"har": {
  "type": "local",
  "command": ["bun", "run", "/absolute/path/to/har-mcp/src/index.ts"],
  "enabled": true
}

Using the compiled release JS instead of source:

"har": {
  "type": "local",
  "command": ["bun", "/absolute/path/to/index.js"],
  "enabled": true
}

Claude Desktop / Cursor / any stdio client (claude_desktop_config.json / mcp.json):

{
  "mcpServers": {
    "har": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/har-mcp/src/index.ts"]
    }
  }
}

4. Load HARs and go

Load a single file or a whole directory, then query by ID:

har_index { "target": "/path/to/captures" }     # starts background creation
har_files { "dir": "/path/to/captures" }        # poll until status is "ready"
har_filter { "keyword": "acquire" }              # -> IDs, after ready
har_decode_body { "id": 254, "target": "request" }

Most tools' file parameter also accepts an arbitrary .har path directly — it starts indexing on demand; while indexing, the tool returns status: "creating".

Loading & cleanup

  • Sidecar Database: Opening or indexing path/to/data.har automatically creates and maintains path/to/data.har.db right next to the HAR file.

  • Background creation: har_index starts creation and returns immediately. Use har_files to observe the status; query tools return status: "creating" until the database is ready.

  • Auto-check & reuse: Companion .har.db files check size and mtime to reuse indexes without re-parsing when the file hasn't changed.

  • Manual cleanup: har_forget { file } deletes the companion data.har.db file (or delete it directly). The HAR file itself is never touched.

Configuration

Variable / flag

Description

Default

HAR_PREVIEW_BYTES

Body preview size before truncation notice

8192

HAR_DECODE_MAX_DEPTH

Protobuf recursion depth

12

HAR_FILTER_LIMIT

Default result limit

100

Tools

Tool

Description

har_files

List *.har files and their companion .har.db index status in a directory.

har_index

Start background creation of companion .har.db indexes for a file or a directory.

har_forget

Delete the companion .har.db database for a HAR file.

har_filter

Filter entries in a HAR file → return compact rows with IDs (no bodies).

har_get_by_id

Fetch full entry (headers + body) by Reqable ID from a HAR file.

har_generate_curl

Generate a cURL command for an entry by ID.

har_decode_body

Decode a body as schema-less protobuf (auto base64/gzip/gRPC). Optional path to focus a sub-field (e.g. 1.11).

har_diff

Field-level diff of two decoded bodies (great for "working request vs. my request").

har_search

Keyword search over url/host/headers (FTS) and optionally text bodies.

Typical workflow

  1. har_index { target: "/path/to/captures" } → start loading.

  2. har_files { dir: "/path/to/captures" } → poll until every file is ready.

  3. har_filter { keyword: "acquire" } → get IDs of interest.

  4. har_decode_body { id: 254, target: "request" } → inspect the protobuf.

  5. har_diff { idA: 3, idB: 947, target: "request" } → see exactly which fields differ.

  6. har_generate_curl { id: 3 } → reproduce a request.

How it works

Storage. Each HAR has its own companion SQLite database. The HAR is streamed (stream-json) into that database during background creation:

  • meta — the status and source-file metadata for this HAR.

  • entries — slim, indexed metadata (method/host/path/status/kind/sizes). Filters scan only this table.

  • bodies — headers + full body BLOBs, fetched only by ID. Never scanned during listing.

  • entries_fts — FTS5 over url/host/path/headers for har_search (falls back to LIKE if unavailable).

Body classification. content.encoding == "base64" marks binary bodies. Because mimeType is often missing or wrong, bodies are re-classified by magic bytes: gzip (1f 8b), gRPC frame (00 + matching BE length), protobuf (low tag byte), image, text, binary.

Protobuf decoding. A schema-less wire-format decoder walks varint / fixed32 / fixed64 / length-delimited fields. A length-delimited value is rendered as a string when it is valid UTF-8 with no hard control characters; otherwise it is recursively tested as a nested message (strict full-buffer parse); otherwise as hex bytes. This cleanly separates text from sub-messages without a schema. gRPC bodies have their 5-byte frame header stripped (multi-frame supported); gzip is decompressed defensively. Depth, field-count and string-length limits keep output bounded.

IDs. id is Reqable's _id (human-friendly); uid is _uid (globally unique). If an id appears in multiple files (e.g. a capture exported twice), pass file (a path or name) to disambiguate; results carry a _note.

Development

bun install
bun run typecheck          # tsc --noEmit
bun run test:ci            # synthetic-fixture test: path indexing, prune, forget, decode (CI-safe)
bun run smoke              # store + decoder smoke test (set HAR_DIR to real HARs)
bun run smoke:mcp          # end-to-end MCP protocol test
bun run build:js           # bundle to dist/index.js
bun run build              # standalone binary

CI (.github/workflows/build.yml) runs typecheck + test:ci, bundles dist/index.js, uploads it as an artifact, and attaches it to a release on v* tags.

License

MIT — see LICENSE.