---
title: "A door's MCP endpoint (JSON-RPC 2.0, one message per request)"
method: POST
path: "/agent/{doorId}/mcp"
tags: ["mcp"]
---

# A door's MCP endpoint (JSON-RPC 2.0, one message per request)

`POST /agent/{doorId}/mcp`

## Request

- Base URL: `https://api.bubblio.dev`
- URL: `https://api.bubblio.dev/agent/{doorId}/mcp`
- Auth: none declared

Tools served: `about` and `ask` always; `list_actions`, `quote`, `confirm` only
while the owner has ≥1 visible action. Tool-call RESULTS are MCP content — one
`{ type: 'text', text }` block whose text is a JSON document; the important shapes
are catalogued under components (QuoteAnswer, ConfirmAnswer, Receipt).

The action lifecycle, in one paragraph: `quote { tool, args, agent_key? }` pins
exactly what would run (10-minute TTL; for priced actions the pin IS the price
guarantee) and answers a `quote_id`. `confirm { quote_id, agent_key? }` executes it
EXACTLY once — the quote is consumed by a winner-only conditional update, and a
duplicate confirm replays the original receipt (marked `replayed: true`) instead of
re-executing. A keyed quote is BOUND to the credential that quoted: confirm must
re-present the same key, or the quote reads as nonexistent — a quote_id alone is
never a bearer token. Quotes needing human approval answer `status: needs_approval`
with a `relay_script` for the human and an approval link; `confirm` doubles as the
NON-consuming poll (`wait_seconds` ≤ 25) answering `awaiting_human` /
`awaiting_payment` until the decision or settlement lands.

## Path parameters

- `doorId` string, required

## Request body

- JsonRpcRequest
  - `jsonrpc` '2.0', required
  - `id` union: Omit entirely for a notification (answered 202, no body).
    - string
    - number
  - `method` 'initialize' | 'ping' | 'tools/list' | 'tools/call', required
  - `params` object: For tools/call: { name, arguments }.

## Response `200`

JSON-RPC result or protocol error.

- JsonRpcResponse
  - `jsonrpc` '2.0', required
  - `id` union, required
    - string
    - number
  - `result` object: For tools/call: MCP content — `{ content: [{ type: 'text', text }], isError? }` where `text` is a JSON document (see QuoteAnswer / ConfirmAnswer / Receipt for the action tools). Tool FAILURES arrive here with `isError: true`, phrased for the calling model; JSON-RPC `error` is reserved for protocol problems.
  - `error` object
    - `code` integer
    - `message` string

## Other responses

- `202`: Notification (no `id`): acknowledged, no body.
- `404`: UNIFORM: unknown, malformed, disabled, unapproved, and migration-lagged doors all read the same.
- `413`: Body over 64KB.
- `429`: A published ceiling tripped (see the hub endpoint's note).

---

[API](https://skmtc.dev/bubblio/apis/bubblio-agent-door-api.md) · [All operations](https://skmtc.dev/bubblio/apis/bubblio-agent-door-api/llms.txt) · [OpenAPI document](https://skmtc.dev/bubblio/apis/bubblio-agent-door-api/revisions/d858aff9c01d?raw)
