Skip to content

MCP

Patchrooms exposes a Model Context Protocol endpoint so an AI agent (Claude, Cursor, and others) can list, read, file, and triage the feedback reports for a project. It is the same data you see in the dashboard, served as JSON-RPC over a single HTTP endpoint.

POST https://room.patchrooms.com/mcp

The endpoint speaks JSON-RPC 2.0. Send method, params, and an id in the request body; the response echoes the id.

Authenticate with a secret API key (prefix pr_sk_) created in the dashboard, sent as a Bearer token:

Authorization: Bearer pr_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

The project is resolved from the key — there is no project id in the URL. The key must carry the feedback:read scope for list_reports / get_report, or the endpoint returns 403. set_status additionally requires feedback:write.

In the dashboard, open the project → Integrations → API keys → Create, and pick the scopes the agent needs:

  • feedback:readlist_reports and get_report.
  • feedback:write — additionally allows set_status (triage).
  • channel:read / channel:write — read or manage channels (REST API).
  • project:read / project:write — read or configure the project (REST API).
  • apikey:write — mint and revoke keys (REST API).
  • * — wildcard, satisfies any scope. Reserved for short-lived setup tokens minted in the dashboard; it cannot be minted via the API itself.

The pr_sk_… value is shown only once at creation. Store it in an environment variable (e.g. PATCHROOMS_API_KEY) or your agent’s credential store. Keys may carry an optional TTL — used for setup tokens, which expire and are revoked after provisioning (see Agent self-setup).

Point your agent’s MCP client at the endpoint with the key as a Bearer header, read from the environment — never hard-code or commit it.

Claude Code — register the server (project scope writes .mcp.json):

Terminal window
claude mcp add --transport http patchrooms https://room.patchrooms.com/mcp \
--header "Authorization: Bearer $PATCHROOMS_API_KEY" --scope project

…or write .mcp.json yourself, keeping the key in an env var:

{
"mcpServers": {
"patchrooms": {
"type": "http",
"url": "https://room.patchrooms.com/mcp",
"headers": { "Authorization": "Bearer ${PATCHROOMS_API_KEY}" }
}
}
}

${PATCHROOMS_API_KEY} is expanded from the shell that launched Claude Code, so export it before starting a session. Cursor, Windsurf, and other MCP clients take the same URL + Bearer header in their own config.

On first use, call introduce with your agent’s name (and owner, if known) — it’s a one-line call and every report you file or view afterward carries that name instead of the raw key name.

No MCP client? The JSON-RPC tools/call POST shown below works from curl or any script — read the key from the environment and hit the endpoint directly.

Custom connectors on claude.ai cannot send a custom header — they authenticate via OAuth instead. No API key needed; add a connector with just the URL:

Settings → Connectors → Add custom connectorhttps://room.patchrooms.com/mcp

Claude discovers the OAuth endpoints automatically and opens a Patchrooms consent page. Sign in with your Patchrooms account (if you aren’t already), pick what to share — a single project, or All projects of an organization — plus the access level (read-only, or read + triage), and click Authorize. That’s it.

With an org-wide grant, list_reports spans every project in the organization (each item carries a project name), and get_report / set_status accept reports from any of them. Org-wide keys work on the MCP endpoint; the REST API still requires a per-project key.

Behind the scenes a dedicated API key named OAuth: <client> is minted for the connector, scoped to exactly what you picked. It shows up under Integrations → API keys like any other key — revoke it there at any time to disconnect the client. Reconnecting the connector just walks the same flow and mints a fresh key.

Any other OAuth-capable MCP client (MCP Inspector and others) connects the same way: point it at the endpoint URL and it will walk the same flow.

The server advertises seven tools via tools/list.

Introduces the calling agent — call this once, before the other tools. It labels the API key so reports the agent files or reads get attributed to it by name, instead of the raw key name.

ArgumentTypeDescription
agentNamestringRequired. How to label this agent, e.g. "Claude (health-os)".
ownerstringWho this agent belongs to, e.g. a user or team name.

Optional — nothing blocks the other tools if you skip it, but reports and views fall back to the API key’s own name instead of an agent-chosen label.

Lists feedback reports for the project, newest first, in a compact form. Every report returned is marked viewed by the calling agent (fire-and-forget, never blocks the response) — see Read tracking.

ArgumentTypeDescription
statusstringFilter by report status.
channelKeystringFilter by channel key.
artifactIdstringFilter by artifact id.
limitnumberMax results. Defaults to 50, capped at 200.

All arguments are optional.

Returns a single report rendered as Markdown, with its screenshots inlined as image content the agent can look at directly — up to 6 images, capped at 8 MB in total, no separate download step. Marks the report viewed by the calling agent, same as list_reports.

ArgumentTypeDescription
idstringReport id. Required.

Files a new feedback report — for agents that spot issues themselves (a failed check, a broken widget, an API defect). The report is marked as submitted via MCP (context.extra.via = 'mcp'). Requires the feedback:write scope.

ArgumentTypeDescription
messagestringReport body, plain text or Markdown. Required.
channelKeystringChannel key. Defaults to the project’s default channel.
urlstringPage or resource the report is about.
authorstringFreeform note on who’s filing this, stored in context.extra. Doesn’t affect the report’s structured author — that’s always agent:<key>, labelled from introduce.
projectstringProject id, key, slug, or name. Required for org-wide keys.

Starts (or resumes) a room for an artifact/task you’re working on — idempotent upsert by artifact_id, safe to call every time you begin work, before any report exists. Requires the feedback:write scope.

ArgumentTypeDescription
artifact_idstringRequired. Stable id for the artifact/task — reports and future create_room calls group under this.
titlestringHuman-readable room title.
goalstringWhat you’re trying to accomplish in this room.
projectstringProject id, key, slug, or name. Required for org-wide keys.

Triages a report by setting its status. Requires the feedback:write scope.

ArgumentTypeDescription
idstringReport id. Required.
statusstringOne of new, triaged, in-progress, fixed, verified, canceled. Required.

Set fixed once the change is made; verified means a human confirmed it works, so leave that one to them unless you’re asked otherwise.

Replies in a report’s comment thread — progress updates, questions, or an explanation of a fix on a report the agent is already working. Requires the feedback:write scope.

Comments land as drafts by default. A draft is visible only in the dashboard, where a human reads it and either publishes it as the agent, edits the text first, or publishes it under their own name. Nothing reaches the thread until they do. Pass draft: false to post straight to the thread — appropriate in an unattended loop with no human review step, or when the person asked for it explicitly.

ArgumentTypeDescription
report_idstringReport id. Required.
textstringComment body, plain text or Markdown. Required.
draftbooleanDefaults to true (hold for human approval). false publishes immediately.
kindstringOptional label for triage: fix, question, options, deferral, techdebt.

kind is what makes a batch of replies skimmable — a human can filter to every question blocking the agent instead of reading each comment. Use fix for a change already made, question when an answer is needed to proceed, options when presenting alternatives with tradeoffs, deferral when proposing to postpone with a reason, techdebt when explaining why something is expensive because of existing debt.

List the most recent reports:

Terminal window
curl -s https://room.patchrooms.com/mcp \
-H "Authorization: Bearer pr_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_reports",
"arguments": { "limit": 2 }
}
}'

The result is a tool-call envelope whose text content is a JSON array of reports:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "[\n {\n \"id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n \"shortId\": \"9c0d\",\n \"title\": \"Checkout button misaligned on mobile\",\n \"status\": \"open\",\n \"channelKey\": \"bug\",\n \"url\": \"https://app.example.com/checkout\",\n \"artifactId\": null,\n \"createdAt\": \"2026-06-03T09:14:22.000Z\"\n }\n]"
}
]
}
}

Fetch one report as Markdown:

Terminal window
curl -s https://room.patchrooms.com/mcp \
-H "Authorization: Bearer pr_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_report",
"arguments": { "id": "665f1a2b3c4d5e6f7a8b9c0d" }
}
}'

The result content is the report rendered as a Markdown string. A report id that is malformed, or that does not belong to your project, returns a tool result with isError: true.

  • initialize returns protocol version 2024-11-05 and advertises tool support.
  • tools/list returns the seven tools above.
  • tools/call runs a tool. An unknown tool or method returns a JSON-RPC error with code -32601.