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.

Two ways in, and the project is resolved from the credential either way — there is no project id in the URL.

OAuth (default). An interactive client authorizes in the browser: it reads the endpoint’s OAuth metadata, opens a Patchrooms consent page, and stores the resulting token itself. Nothing secret ends up in your config. See Connect a coding agent.

API key (headless). An unattended run sends a secret key (prefix pr_sk_) created in the dashboard, as a Bearer token:

Authorization: Bearer pr_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

Either way the grant must carry the feedback:read scope for list_reports / get_report, or the endpoint returns 403. set_status additionally requires feedback:write.

Skip this if your client can open a browser — OAuth covers it. For CI and other unattended runs, open the project → Integrations → API keys → Create in the dashboard, and pick the scopes the agent needs:

  • feedback:readlist_reports, get_report, list_projects, list_channels.
  • feedback:write — additionally allows create_report, create_room, set_status, add_comment.
  • 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).

Nothing to paste, no key to manage: point the client at the URL and authorize in the browser. The endpoint advertises its OAuth metadata, so the client discovers the rest on its own.

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

Terminal window
claude mcp add --transport http patchrooms https://room.patchrooms.com/mcp --scope project

The first tool call opens the Patchrooms consent page: sign in, pick what to share — a single project or All projects of an organization — plus the access level (read-only, or read + triage), and authorize. /mcp in Claude Code shows the connection state and can re-run the flow.

The resulting .mcp.json holds nothing secret, so it is safe to commit:

{
"mcpServers": {
"patchrooms": {
"type": "http",
"url": "https://room.patchrooms.com/mcp"
}
}
}

Cursor, Windsurf, claude.ai connectors and other MCP clients take the same URL with no header.

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 grant name.

An unattended run (CI, a cron job, a container with no browser) can’t complete a consent screen. Those authenticate with a pr_sk_… key as a Bearer header, read from the environment — never hard-coded, never committed:

Terminal window
claude mcp add --transport http patchrooms https://room.patchrooms.com/mcp \
--header "Authorization: Bearer $PATCHROOMS_API_KEY" --scope project
{
"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 the client, so export it before starting a session.

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.

Same OAuth flow, added from the UI instead of a CLI:

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

Claude discovers the OAuth endpoints automatically and opens the Patchrooms consent page. Custom connectors on claude.ai cannot send a custom header at all, so this is the only way in there — and it needs no API key.

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 nine 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.
qstringCase-insensitive substring search across report text (text/selection blocks and audio transcripts).
urlstringFilter to reports whose page URL contains this substring.
sincestringISO date/datetime — only reports created after this.
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.

Lists the projects this API key can act on — call it before passing project to create_report, create_room, or list_channels. A project-scoped key always returns just its own project; an org-wide key returns every project in its organization.

No arguments. Returns a compact JSON array of { id, name, projectKey, slug, defaultChannelKey }.

Lists a project’s channels — call it before passing channelKey to create_report.

ArgumentTypeDescription
projectstringProject id, key, slug, or name. Required for org-wide keys, omit for project-scoped keys.

Returns a compact JSON array of { key, name }.

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. The result includes a url pointing at the room in the dashboard, ready to hand to a human. 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 nine tools above.
  • tools/call runs a tool. An unknown tool or method returns a JSON-RPC error with code -32601.