Skip to content

StartMCP capture

One MCP call. One local receipt.

Doorstep passes an ordinary stdio MCP server through Bulla byte-for-byte and records completed tool calls locally. The server does not need to change.

Install Bulla 0.49.2

$ python -m pip install "bulla==0.49.2"

Doorstep is the bulla capture command, not a separate service or protocol. It creates no account, daemon, network dependency, or default signing key.

Package version used on this page

The command shown here comes from the package published on PyPI, not from unreleased repository code.

Configure the wrapper once

Keep your existing MCP server command after --. Point --session-root at a private absolute path. Each server lifecycle receives a distinct session directory, so the same client configuration can remain in place across restarts.

json
{
  "mcpServers": {
    "your-server": {
      "command": "bulla",
      "args": [
        "capture",
        "mcp",
        "--session-root",
        "/absolute/path/to/bulla-captures",
        "--",
        "python",
        "-m",
        "your_mcp_server"
      ]
    }
  }
}

The upstream client still performs the MCP handshake. Bulla forwards stdin, stdout, and server stderr without injecting tools, renaming methods, or rewriting JSON-RPC IDs. A complete client-originated tools/call and its matching response produce one ActionReceipt.

Privacy default: commitments only.

Request and response payloads are not retained unless you explicitly add --retain-payloads. That option stores the exact frames locally and can preserve prompts, credentials, tool arguments, and results. Review the session-root location and its access controls before enabling it.

Check the capture locally

$ bulla capture check /absolute/path/to/bulla-captures --show-receipts
$ bulla receipt verify /absolute/path/to/receipt.json

capture check inventories every session, verifies receipts, and recomputes frame commitments when retained sidecars exist. receipt verify checks one ActionReceipt. An unsigned receipt reaches the digest rung; a receipt created with --key FILE can authenticate the local observer's statement.

What the receipt carries

These are the central fields from one commitments-only unsigned receipt. The full record also contains its canonical hashes, receiver-local event identifier, completion time, and producer metadata.

json
{
  "schema_version": "0.4",
  "kind": "action_receipt",
  "action": {
    "type": "mcp.tools.call.observed",
    "subject": {
      "transport": "mcp-stdio-jsonrpc",
      "tool_name": "demo.echo",
      "request_frame_sha256": "sha256:8da4f7118b25956f40db428961733f1f9e3bbc08968e704fea60c959aa605096",
      "response_frame_sha256": "sha256:091265a2d0fefb624c26991ed8758035003c21cfbafb13ef2b31a1ec0a00dbbe",
      "response_kind": "result"
    }
  },
  "evidence_refs": [
    {
      "name": "mcp.request.frame",
      "hash": "sha256:8da4f7118b25956f40db428961733f1f9e3bbc08968e704fea60c959aa605096",
      "grounding": "self_asserted"
    },
    {
      "name": "mcp.response.frame",
      "hash": "sha256:091265a2d0fefb624c26991ed8758035003c21cfbafb13ef2b31a1ec0a00dbbe",
      "grounding": "self_asserted"
    }
  ],
  "retention": {
    "record": "operational",
    "disclosure": "party"
  },
  "signature": null
}

The frame hashes commit the exact newline-terminated bytes that crossed the wrapper. With commitments-only capture, those bytes are not present for an independent recheck.

What this establishes

ClaimStatus
Canonical structure and internal consistencyCheckable
Request/response commitments carriedYes
Underlying bytes match commitmentsOnly with retained sidecars
Call correlationRecorded by local observer
Observer statement authenticatedOnly when signed
MCP server authenticatedNo
Tool execution provenNo
Result correctness establishedNo

A signature authenticates only the local observer's statement. It does not authenticate the MCP server, prove that a tool executed, establish result correctness, or turn a local correlation into an independent observation.

Continue with the ActionReceipt specification or the published CLI reference.