Skip to main content
Glama
README.md
# caido-screenshot-mcp

An MCP server that captures formatted screenshots of [Caido](https://caido.io) Replay
request/response pairs, by driving the **Screenshot Mode** plugin.

Caido has no screenshot API — Screenshot Mode is a frontend-only plugin that renders the
DOM to a PNG in the browser. This server reaches it over the Chrome DevTools Protocol,
clicks the plugin's own export, and intercepts the resulting image before Electron can
open a save dialog. The output is the plugin's real output, written straight to disk.

## Requirements

- **Node >= 22** (uses the built-in `WebSocket`; there are no npm dependencies)
- **Caido** desktop
- The **Screenshot Mode** plugin installed in Caido
- Caido launched with `--remote-debugging-port` (see below)

## Install

```sh
git clone <this-repo> caido-screenshot-mcp
cd caido-screenshot-mcp
npm link            # optional: puts `caido-screenshot` on your PATH
```

No `npm install` step — there are no dependencies.

## Start Caido with the debug port

The plugin renders inside Caido's window, so the server needs to talk to that window.
Launching Caido normally leaves the port closed and every call will fail.

```sh
caido-screenshot launch          # quits nothing; starts Caido with the port open
```

Or manually:

```sh
# macOS
open -a Caido --args --remote-debugging-port=9222
# Linux
caido --remote-debugging-port=9222
# Windows
"%LOCALAPPDATA%\Programs\Caido\Caido.exe" --remote-debugging-port=9222
```

Check everything at once:

```sh
caido-screenshot doctor
```

## Use with Claude Code

```sh
claude mcp add caido-screenshot --scope user -- node /absolute/path/to/caido-screenshot-mcp/src/server.mjs
```

Restart Claude Code. Then just ask: *"screenshot the current Caido replay session"*.

## Use with any MCP client

```json
{
  "mcpServers": {
    "caido-screenshot": {
      "command": "node",
      "args": ["/absolute/path/to/caido-screenshot-mcp/src/server.mjs"]
    }
  }
}
```

## Tool: `caido_screenshot`

| Parameter  | Type    | Description |
|------------|---------|-------------|
| `out_path` | string  | Where to save the PNG. Default `~/Downloads/caido-screenshot-<timestamp>.png` |
| `collection` | string | Replay collection containing the session. It is expanded automatically. |
| `session`  | string  | Replay session to select first, by sidebar name (e.g. `GET /login`) |
| `session_id` | string | Exact Replay session ID. Preferred because it is unambiguous. |
| `require_response` | boolean | Reject request-only sessions and stale previews. Default `true`. |
| `inline`   | boolean | Also return the image in the result (large). Default `false` |

## Examples

Once the server is registered you never name the tool. Describe what you want in plain
English and the agent picks it up.

### Just capture what's on screen

> **screenshot the current Caido replay request**

The agent calls `caido_screenshot` and replies with the saved path:

```
Saved /Users/you/Downloads/caido-screenshot-2026-08-22T13-40-11-002Z.png (438 KB)
```

### Send a request, then capture it

This is the common one. Pair it with the official
[Caido MCP server](https://github.com/c0tton-fluff/caido-mcp-server), which can send
requests — this server captures the result.

> **send a GET to https://httpbin.org/get in Caido replay and screenshot it**

The agent sends the request, maps its returned Replay entry to the populated session, and
captures that exact session ID:

| Step | Tool | Server |
|------|------|--------|
| 1 | `caido_send_request` | caido |
| 2 | `caido_list_replay_sessions` | caido |
| 3 | `caido_screenshot(session_id: ...)` | caido-screenshot |

Match `caido_send_request.entryId` to `caido_list_replay_sessions[].activeEntryId`.
Do not create a new session from `requestSourceId` for response evidence: Caido seeds the
request template but does not copy the completed response.

### Send a raw request you wrote

Paste the raw HTTP and say what you want:

> **send this in Caido replay and screenshot it:**
> ```
> POST /post HTTP/1.1
> Host: httpbin.org
> Content-Type: application/json
>
> {"user":"demo","token":"abc123"}
> ```

### Pick a specific session

Sessions are named after the request line in Caido's sidebar, so `GET /`, `POST /login`
and so on:

> **screenshot the "POST /login" replay session**

That becomes `caido_screenshot(session: "POST /login")`. Every capture uses Side by Side.

For reliable automation, use the session ID:

`caido_screenshot(session_id: "67", require_response: true)`

If the session is inside a different or collapsed collection, name both:

> **screenshot "01 admin create private conversation" from the "OBS AI Assistant IDOR - Fresh Evidence" collection**

That becomes `caido_screenshot(collection: "OBS AI Assistant IDOR - Fresh Evidence", session: "01 admin create private conversation")`. The tool expands the collection before selecting the session and captures it Side by Side.

> **Heads up:** `caido_send_request` auto-names sessions from the request line, so several
> targets can all end up called `GET /`. Rename a session in Caido before capturing if you
> need to refer to it unambiguously.

### Save somewhere specific

> **screenshot it and save to ~/reports/login-flow.png**

### Using it from Codex

Start an interactive session and ask the same way:

```sh
codex
> screenshot the current Caido replay session
```

Codex asks for approval the first time. To skip the prompt for this tool, add to
`~/.codex/config.toml`:

```toml
[mcp_servers.caido-screenshot.tools.caido_screenshot]
approval_mode = "auto"   # auto | prompt | writes | approve
```

**`codex exec` (non-interactive) will not work** — it forces `approval: never` and refuses
all MCP tool calls, regardless of per-tool settings. Use an interactive session.

## CLI

```sh
caido-screenshot                                   # current session -> ~/Downloads
caido-screenshot shot.png                          # explicit path
caido-screenshot shot.png --session "GET /login"
caido-screenshot shot.png --session-id 67
caido-screenshot shot.png --collection "Fresh Evidence" --session "01 admin request"
caido-screenshot doctor
caido-screenshot launch
```

## Environment

| Variable            | Default | Description |
|---------------------|---------|-------------|
| `CAIDO_CDP_PORT`    | `9222`  | Caido's remote debugging port |
| `CAIDO_CDP_TIMEOUT_MS` | `45000` | Per-call CDP timeout |

## Known limitations

These are properties of the plugin, not of this server:

- **Long content is cut off.** Caido's editors are CodeMirror, which only renders the
  visible lines. Anything taller than the Caido window is not in the DOM and cannot be
  captured. Very long responses can come out blank; the server errors instead of writing
  a near-empty file.
- **Headers can be dropped.** The DOM-to-image render sometimes omits lines, with visible
  gaps in the line numbers. Treat these images as illustrative, not as byte-exact evidence
  — use Caido's own request export when precision matters.
- **The layout is fixed to Side by Side.** The server deliberately exposes no layout or
  arrangement option so every evidence screenshot has the same report-ready format.
- **Screenshots are not redacted.** Whatever is on screen — `Authorization`, `Cookie`,
  `Set-Cookie` — is captured in full. Review before sharing.
- **Request-only Replay sessions are rejected by default.** Screenshot Mode can retain its
  previous preview when the selected session has no response. Pass `--allow-no-response`
  only when a request-only screenshot is intentional.

## Troubleshooting

| Message | Cause |
|---|---|
| `Cannot reach Caido's debug port` | Caido not launched with `--remote-debugging-port`. Quit it and run `caido-screenshot launch`. |
| `Caido is showing the instance picker` | Click **Connect** on your local instance in the Caido window. |
| `No Screenshot button in the Replay toolbar` | No Replay session open, or the Screenshot Mode plugin isn't installed/enabled. |
| `No Replay collection matching "..."` | Use the exact collection name shown in the Replay sidebar. |
| `No Replay session matching "..."` | The tool expands `collection` when supplied, then lists the visible session names if no exact match appears. |
| `has no rendered response` | The selected session was seeded from a request or has not completed. Capture the session whose `activeEntryId` equals the send result's `entryId`. |
| `preview is stale` | Screenshot Mode showed a different host/path (or a conflicting visible query). Nothing was saved; retry using the populated `session_id`. Scheme, encoding, query order, omitted query labels, and Screenshot Mode 0.8.1's missing `?` delimiter are normalized automatically. |
| `returned an empty image` | Content too long to render. Capture a shorter request/response. |

## License

MIT

TDQS

A4.4/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of confusion between tools. The tool has a single, clearly defined purpose (capturing a screenshot of a Caido Replay session), so an agent cannot misselect it.

Naming Consistency5/5

The single tool follows a consistent snake_case naming convention (caido_screenshot), which is clear and predictable. There is no mix of styles or verbs to create inconsistency.

Tool Count3/5

The server provides only one tool, which feels thin for a typical MCP server. However, the tool targets a very specific, narrow use case (Caido Replay screenshot capture), so the count may be appropriate for that focused purpose, but it is borderline.

Completeness4/5

The tool covers the core workflow of capturing a formatted screenshot from a Replay session, including verification and metadata return. There are minor gaps (e.g., no options for custom layout or output format), but for its stated purpose, it is essentially complete.

Maintenance

ActivityMaintained
ResponsivenessNo issues