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.
Endpoint
Section titled “Endpoint”POST https://room.patchrooms.com/mcpThe endpoint speaks JSON-RPC 2.0. Send method, params, and an id in the
request body; the response echoes the id.
Authentication
Section titled “Authentication”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_xxxxxxxxxxxxxxxxxxxxxxxxxxxxEither 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.
Create a key (headless only)
Section titled “Create a key (headless only)”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:read—list_reports,get_report,list_projects,list_channels.feedback:write— additionally allowscreate_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).
Connect a coding agent
Section titled “Connect a coding agent”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):
claude mcp add --transport http patchrooms https://room.patchrooms.com/mcp --scope projectThe 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.
Headless: connect with an API key
Section titled “Headless: connect with an API key”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:
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.
Connect claude.ai / Cowork
Section titled “Connect claude.ai / Cowork”Same OAuth flow, added from the UI instead of a CLI:
Settings → Connectors → Add custom connector → https://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.
introduce
Section titled “introduce”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.
| Argument | Type | Description |
|---|---|---|
agentName | string | Required. How to label this agent, e.g. "Claude (health-os)". |
owner | string | Who 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.
list_reports
Section titled “list_reports”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.
| Argument | Type | Description |
|---|---|---|
status | string | Filter by report status. |
channelKey | string | Filter by channel key. |
artifactId | string | Filter by artifact id. |
q | string | Case-insensitive substring search across report text (text/selection blocks and audio transcripts). |
url | string | Filter to reports whose page URL contains this substring. |
since | string | ISO date/datetime — only reports created after this. |
limit | number | Max results. Defaults to 50, capped at 200. |
All arguments are optional.
get_report
Section titled “get_report”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.
| Argument | Type | Description |
|---|---|---|
id | string | Report id. Required. |
list_projects
Section titled “list_projects”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 }.
list_channels
Section titled “list_channels”Lists a project’s channels — call it before passing channelKey to
create_report.
| Argument | Type | Description |
|---|---|---|
project | string | Project id, key, slug, or name. Required for org-wide keys, omit for project-scoped keys. |
Returns a compact JSON array of { key, name }.
create_report
Section titled “create_report”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.
| Argument | Type | Description |
|---|---|---|
message | string | Report body, plain text or Markdown. Required. |
channelKey | string | Channel key. Defaults to the project’s default channel. |
url | string | Page or resource the report is about. |
author | string | Freeform 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. |
project | string | Project id, key, slug, or name. Required for org-wide keys. |
create_room
Section titled “create_room”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.
| Argument | Type | Description |
|---|---|---|
artifact_id | string | Required. Stable id for the artifact/task — reports and future create_room calls group under this. |
title | string | Human-readable room title. |
goal | string | What you’re trying to accomplish in this room. |
project | string | Project id, key, slug, or name. Required for org-wide keys. |
set_status
Section titled “set_status”Triages a report by setting its status. Requires the feedback:write scope.
| Argument | Type | Description |
|---|---|---|
id | string | Report id. Required. |
status | string | One 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.
add_comment
Section titled “add_comment”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.
| Argument | Type | Description |
|---|---|---|
report_id | string | Report id. Required. |
text | string | Comment body, plain text or Markdown. Required. |
draft | boolean | Defaults to true (hold for human approval). false publishes immediately. |
kind | string | Optional 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.
Example
Section titled “Example”List the most recent reports:
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:
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.
Protocol notes
Section titled “Protocol notes”initializereturns protocol version2024-11-05and advertises tool support.tools/listreturns the nine tools above.tools/callruns a tool. An unknown tool or method returns a JSON-RPC error with code-32601.