caido-sdk · git:20260709.1f84970 · 2026-07-09 · sha256 9107467a3dba5ec3

caido-sdk git:20260709.1f84970A

Immutable. This exact content is served forever at /api/v1/blob/9107467a3dba5ec3.

---
name: caido-sdk
description: "Direct Caido interaction via the caido-sdk-client Python library, bypassing the Caido MCP server. Prefer this over the caido-proxy MCP skill for efficiency WHEN the SDK is importable in the current runtime. If the import fails, or Caido/the MCP is not loaded, fall back to the caido-proxy skill."
---

# Caido SDK (direct)

Talk to a running Caido instance directly through the `caido-sdk-client` Python
library instead of the Caido MCP server. When the library is importable, this is
more efficient than MCP: one process, no per-call tool round-trips, and full
access to the SDK's typed objects.

This does not replace the `caido-proxy` skill — it is the preferred path only
when the SDK is available. Decide with the availability check below.

## Step 0 — Availability check (do this first)

The SDK is often only installed inside the Caido MCP's isolated env, not the
agent runtime. Probe before committing:

```bash
python3 -c "import caido_sdk_client" 2>/dev/null \
  && echo "USE SDK DIRECTLY" || echo "SDK NOT IN RUNTIME"
```

Fallback order:

1. `import caido_sdk_client` succeeds → use it directly (this skill).
2. Import fails but `uv` is on PATH → run one-off scripts with
   `uv run --with caido-sdk-client script.py` (ephemeral install, matches how
   the MCP provisions itself). Needs network on first run.
3. Neither works, or Caido itself is not reachable → **load the `caido-proxy`
   skill and use the `caido_*` MCP tools instead.**

Do not assume the SDK is present just because "caido" is in the task. If Step 0
prints `SDK NOT IN RUNTIME` and `uv` is unavailable, switch to `caido-proxy`.

## Authentication

Resolution order (same as the MCP server uses):

1. `CAIDO_PAT` env var → `PATAuthOptions(pat=...)`, no `connect()` needed.
2. `~/.caido-mcp/token.json` (`accessToken` / `refreshToken`) →
   `TokenAuthOptions` + `await client.connect()`.
3. No auth → guest mode, only `health()` works.

`CAIDO_URL` overrides the default `http://localhost:8080`.

## Minimal usage

```python
import asyncio, os, json
from pathlib import Path
from caido_sdk_client import Client

async def main():
    url = os.environ.get("CAIDO_URL", "http://localhost:8080")
    pat = os.environ.get("CAIDO_PAT")
    if pat:
        from caido_sdk_client.auth import PATAuthOptions
        client = Client(url, auth=PATAuthOptions(pat=pat))
    else:
        from caido_sdk_client.auth import TokenAuthOptions, TokenPair
        data = json.loads((Path.home() / ".caido-mcp" / "token.json").read_text())
        client = Client(url, auth=TokenAuthOptions(
            token=TokenPair(access_token=data["accessToken"],
                            refresh_token=data.get("refreshToken"))))
        await client.connect()

    # health
    h = await client.health()
    print(h.name, h.version, h.ready)

    # search proxy history (HTTPQL — same filter syntax as the MCP/caido-proxy skill)
    conn = await client.request.list().first(20).filter('req.host.eq:"example.com"').execute()
    for edge in conn.edges:
        r = edge.node.request
        resp = edge.node.response
        print(r.id, r.method, resp.status_code if resp else "-", r.host + r.path)

    # get one request/response
    entry = await client.request.get("<request_id>")
    if entry and entry.response and entry.response.raw:
        print(entry.response.raw.decode(errors="replace")[:2000])

    # replay a modified raw request
    from caido_sdk_client.types.replay_session import ReplaySendOptions
    session = await client.replay.sessions.create()
    result = await client.replay.send(session.id, ReplaySendOptions(
        raw=b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n",
        host="example.com", port=443, tls=True))
    print(result.task_status)

    # document a finding
    from caido_sdk_client.types.finding import CreateFindingOptions
    await client.findings.create("<request_id>", CreateFindingOptions(
        title="IDOR in /api/users/{id}", reporter="dreadnode-agent"))

    await client.aclose()

asyncio.run(main())
```

Run inline with `python3 - <<'PY' ... PY`, or via `uv run --with caido-sdk-client`
when the library is not in the runtime env.

## HTTPQL

Filter syntax is identical to the `caido-proxy` skill (e.g.
`req.host.eq:"example.com" AND req.method.eq:"POST"`, `resp.code.gte:500`). See
that skill's quick reference — do not duplicate it here.

## Notes

- `caido-server-auth` is a separate auth-only helper package (device-flow / PAT
  approval) that `caido-sdk-client` pulls in. You normally interact only with
  `caido_sdk_client`; reach for `caido_server_auth` only when scripting an
  initial device-flow login.
- Do not modify the `caido-sdk-client` package or the capability's MCP wrappers.
  This skill only *uses* the SDK.