MCP tools

Every tool the connector gives Claude, with its arguments.

On this page

The Roomi connector gives Claude the platform's operations as MCP tools: list your projects, check a deploy, make and revoke viewer links, read what viewers did and said, add a page, publish a static demo written in the conversation, with the guide and the check that get it right the first time, and list a project on the community. This page is the reference for each tool, its arguments and what it returns. Deploying from Claude is the guide.

The connector

The connector is an MCP server that speaks Streamable HTTP, at one address:

https://mcp.getroomi.com/mcp

Add it in Claude as a custom connector with that address. It holds no credential of its own and runs nothing of yours: every tool is a call to the HTTP API, made as you.

Signing in

The connector is an OAuth 2.1 protected resource, and the platform is its authorization server. When you add it, Claude does the rest:

  1. Claude asks the connector, is told to sign in, and reads where from /.well-known/oauth-protected-resource/mcp.
  2. Claude registers itself with the platform and sends you to the app to sign in.
  3. The app asks you to approve Claude for the workspace you are in. The grant is for that workspace only.
  4. Claude receives a token issued for the connector and nothing else, valid for an hour, and a refresh token to renew it without asking you again.

The connector accepts only a token the platform signed for it. A token from pitch login is refused there, and the connector's own token is refused by the API, so neither can stand in for the other. The connector never passes your token on: it reaches the platform over a private channel, as the person the token names, and the platform checks again that you still belong to the workspace.

What each grant allows

Scope Allows
pitch:read Every tool that changes nothing.
pitch:write The tools that change something: create_link, revoke_link, get_link, add_page, deploy_static, set_community_card, request_listing, withdraw_listing, invite_member, revoke_invitation, set_member_role, remove_member, set_brand, remove_logo, set_room_theme and reset_room_theme. A rehearsal of one of them needs it too. get_link is here because the address it shows opens the room.

Claude asks for both. A connection granted pitch:read alone gets a 403 with insufficient_scope when it calls a tool that changes something: its message is "This connection may only read. Reconnect and allow changes."

From Claude Code

Claude Code can add the connector by its address, as any Claude client does. The roomi plugin for Claude Code instead sends the token pitch login stored, read with pitch auth header; only a connector running on your own machine accepts that token.

Every tool, at a glance

Tool What it does Changes anything
deploy_guide Returns the guide to building a demo the platform takes No
check_bundle Checks a static demo as deploy_static would, sending nothing No
list_projects Lists your projects and their rooms No
deploy_status Shows a project's live build and recent builds No
viewer_activity Shows a project's links and their visits No
read_feedback Shows what viewers answered and commented No
pipeline Shows every link, with its stage No
create_link Makes a link for one viewer Yes
revoke_link Stops a link opening the room Yes, and it cannot be undone
get_link Shows a link's address again, when the viewer has lost it Yes: each showing is recorded
add_page Adds a page to a room Yes
deploy_static Publishes a static demo held in the conversation Yes with commit: true; otherwise a rehearsal
community_card Shows a project's community card and where its listing stands No
set_community_card Writes the community card, with the pre-flight check's warnings Yes with commit: true; otherwise a rehearsal
request_listing Lists a project on the community if its checks pass, or says what stopped it Yes with commit: true; otherwise a rehearsal
withdraw_listing Takes a project off the community, or out of review Yes with commit: true; otherwise a rehearsal
appeal_listing Asks Roomi to review a block, or a listing it took off Yes with commit: true; otherwise a rehearsal
list_notices Shows your notices: a listing taken off, a project taken down, a review decided No
list_workspaces Lists your workspaces: your own and each team, and which one this connection works in No
list_members Lists the people in a workspace, with their roles No
list_invitations Lists a team's invitations still waiting No
invite_member Invites an email into a team, and gives you the link to send Yes with commit: true; otherwise a rehearsal
revoke_invitation Stops an invitation's link working Yes with commit: true; otherwise a rehearsal
set_member_role Makes someone in a team an owner or a member Yes with commit: true; otherwise a rehearsal
remove_member Takes someone out of a team Yes with commit: true; otherwise a rehearsal
public_address_status Says whether a project's public address is turning new visitors away after a rush, and until when No
get_brand Shows the brand and the room theme, and what the room shows of each No
set_brand Sets the brand's name, accent colour and logo, checking the colour reads Yes with commit: true; otherwise a rehearsal
remove_logo Removes the brand's logo Yes with commit: true; otherwise a rehearsal
set_room_theme Sets the room theme, checking every colour reads Yes with commit: true; otherwise a rehearsal
reset_room_theme Removes the room theme Yes with commit: true; otherwise a rehearsal

When Claude connects, the connector also sends it instructions: what it deploys, what the files must be (every app's path a file among them, so an index.html at the root), the limits, that a tour and pages make the pitch, and to call deploy_guide before preparing a deploy and check_bundle before rehearsing; and that on Free, which has no viewer links, it offers to list a live demo on the community. Deploying from Claude says why.

Every tool describes itself to Claude with the words quoted below, and says whether it changes anything. The tools that change nothing are marked read-only; Claude asks you before it calls any of the others.

Tools

deploy_guide

Returns the guide to building a demo Roomi will take: the build contract (every app path needs an index.html among the files), the manifest, how to write the guided tour, pages, the rules, and when to suggest installing the pitch CLI instead. Call it before preparing a deploy or writing a story. Changes nothing.

Read-only. Takes no arguments.

{}

Returns the guide as Markdown. It is drawn from the same sources as the PITCH.md that pitch init writes and as these docs: the rules, the loop (check_bundle, a rehearsal, your yes, then commit: true), what the files must be, the manifest and every field it takes, how to write the tour, pages, and what to do once the demo is live. Where PITCH.md names a pitch command, the guide names the tool. One section names the CLI itself: when it is the better route (a container demo, a build over the connector's limits, work in a repository with Claude Code, links and pages from a terminal), the two commands that install it, and that Claude offers to run the install where it has a terminal and gives the commands where it has none.

check_bundle

Checks a static demo exactly as deploy_static would, and sends nothing anywhere. Changes nothing. It returns every problem at once, each with its fix and the docs entry that explains it: an app or a story step whose page is not among the files (an app at / needs index.html), too many files or bytes, a hidden file or node_modules, a live credential, a manifest field that is wrong or unknown. Call it with exactly what you will give deploy_static, and fix everything it names before rehearsing.

Read-only. It takes deploy_static's arguments, less commit: project, name, device, files (each files[].path, files[].content and files[].encoding), manifest and note, with the same limits.

{
  "project": "corner-teaser",
  "name": "Corner teaser",
  "files": [{ "path": "src/App.tsx", "content": "export default () => <h1>Corner</h1>" }]
}
1 problem, so deploy_static would refuse this. Nothing was sent. Fix every one, then check again:
- files: there is no index.html at the root. Without a manifest the demo is one app at /, and the room opens it at index.html: add index.html, the page the demo starts on
  https://getroomi.com/docs/claude#every-check-and-its-fix

Also worth knowing:
- files: src/App.tsx look like source, not a build. The room serves files as they are and builds nothing: send what the build writes, or plain HTML, CSS and JavaScript
  https://getroomi.com/docs/claude#every-check-and-its-fix
- manifest.story: there is none, so the room offers no guided tour. A viewer meets the demo without a word from you
  https://getroomi.com/docs/story

A demo that needs the CLI is refused with the two commands that install it. More than 200 files or 3 MB ends: To install it on the publisher’s machine: npm install -g @pitch-product/cli, then pitch login; a manifest with kind: container adds then pitch deploy in the demo’s folder.

With no problem, it says so, with the demo's apps, its tour and its pages, and anything worth knowing. Every check, and its fix lists what it checks.

list_projects

Lists the projects in the signed-in workspace, with each one's room URL. Changes nothing.

Read-only. Takes no arguments.

{}

Returns the projects as JSON: each one's id, slug, name, visibility, liveBuildId, roomUrl and createdAt. The id is what every other tool's projectId takes.

deploy_status

Shows a project's live build and its recent builds. Changes nothing.

Read-only.

Argument Type Required Limits
projectId string yes 1 to 100 characters: the id from list_projects
{ "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53" }

Returns project (as list_projects gives it), live (the live build, or null when nothing is live) and recent (the five newest builds). Each build has its id, kind, manifest, sizeBytes, note, live and createdAt. To deploy, Claude uses pitch deploy through the plugin, or deploy_static for a static demo in the conversation.

Creates a new viewer link to a project's room, for one named person. This changes something: it issues a working link that opens the room. Give the URL to the person straight away and write it nowhere else; if it is lost, get_link shows it again.

Changes something. Not idempotent: each call makes another link.

Argument Type Required Limits
projectId string yes 1 to 100 characters
viewerName string yes 1 to 80 characters: who the link is for
viewerEmail string no an email address, kept with the link; nothing is sent to it
expiresInDays integer no 1 to 365. Without it, the link does not expire
{ "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53", "viewerName": "Priya Shah", "expiresInDays": 30 }

Returns the link's id, who it is for, when it expires, and the URL, as text:

Link for Priya Shah (link id a91d4e6f-2c38-4b7a-9e05-d7b3f1c8e240, expiring 2026-10-29T10:00:00.000Z):
https://corner-for-bullring.getroomi.app/l/…

Give it to Priya Shah. If it is lost, get_link with this link id shows it again.

The URL appears in that one result and nowhere else; no list carries it. On the Free plan the platform refuses every private link; see Plans and limits.

Revokes a viewer link. This changes something and cannot be undone: the link stops opening the room at once. What the viewer already did stays on record.

Changes something, destructively. Revoking a link that is already revoked leaves it revoked, with the time of the latest revocation.

Argument Type Required Limits
linkId string yes 1 to 100 characters: the link id from viewer_activity or pipeline
{ "linkId": "a91d4e6f-2c38-4b7a-9e05-d7b3f1c8e240" }

Returns the link as JSON, with revokedAt set: id, viewerName, viewerEmail, expiresAt, revokedAt and stage.

Shows the full URL of an existing viewer link again, for the publisher to copy and resend when the person has lost it. This changes something small: each showing is recorded in the project's history, under the person signed in, and it needs the write permission, because the URL opens the room. A link made before Roomi kept addresses cannot be shown; the reply says to reissue it in the app.

Changes something: the project's history records each showing. Idempotent otherwise: the same link gives the same URL every time.

Argument Type Required Limits
linkId string yes 1 to 100 characters: the link id from viewer_activity or pipeline
{ "linkId": "a91d4e6f-2c38-4b7a-9e05-d7b3f1c8e240" }

Returns the URL as text, as create_link does. A revoked or expired link is refused, and so is one made before 1 October 2026, whose reply says to reissue it in the app: the platform kept only a hash of its key then.

viewer_activity

Shows a project's viewer links and their visits: who opened the room, when, and the seconds spent on each app, page and file. Changes nothing.

Read-only.

Argument Type Required Limits
projectId string yes 1 to 100 characters
{ "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53" }

Returns links (each as revoke_link returns one) and visits. A visit has its id, linkId, viewerName, startedAt, endedAt and time: seconds per thing the viewer looked at, keyed app:<id> or page:<id>, as Room events explains.

read_feedback

Shows what viewers said back on a project: their next-step answers (meeting, yes, later, colleague, question, no) and their comments. Changes nothing; it does not mark anything read or resolved.

Read-only.

Argument Type Required Limits
projectId string yes 1 to 100 characters
{ "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53" }

Returns responses and comments. A response has its id, linkId, viewerName, step (meeting, yes, later, colleague, question or no), detail (what the viewer added, such as when to get back to them, or their question) and createdAt. A comment has its id, linkId, viewerName, appId and screen (where it was pinned), body, resolvedAt and createdAt.

pipeline

Shows every viewer link across every project with its stage (sent, opened, engaged, yes, later, no). Changes nothing.

Read-only. Takes no arguments.

{}

Returns every link in the workspace, each as revoke_link returns one, with its projectId and projectName. Analytics and the pipeline says how a stage is decided.

add_page

Adds a page (Markdown or HTML) to a project's room. This changes something: the page is visible to every viewer of the room at once.

Changes something.

Argument Type Required Limits
projectId string yes 1 to 100 characters
title string yes 1 to 80 characters
kind string yes markdown or html
content string yes the page itself, up to 2,000,000 characters
{
  "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53",
  "title": "Why Corner",
  "kind": "markdown",
  "content": "# Why Corner\n\nCoaches lose an hour a day to…"
}

Returns the page's id, title and kind. A page with the same title as one the room already has replaces it. Pages says how the room shows each kind.

deploy_static

Publishes a static demo (HTML, CSS, JavaScript, images) that is in this conversation to a project's room, creating the project if its slug is new. Without commit it is a rehearsal and changes nothing: it checks and packs the files and says exactly what would go live. With commit: true it changes something: the files become the live build every viewer of the room sees. Call with commit: true only after showing the rehearsal and hearing a clear yes. Limits: 200 files, 3 MB, every app's path a file among the files (index.html for an app at /), no server code. Call deploy_guide first, and check_bundle until it passes: this refuses with the same problems. A demo is half-deployed without its guided tour (the manifest's story) and pages (the room's Read more): add them, and on a paid plan create_link makes a viewer's link next; on Free, which has no viewer links, offer to list the room on the community with request_listing. A repository on disk, or a demo with a server, is deployed with pitch deploy on the publisher's machine instead.

Changes something with commit: true; without it, it only checks and packs.

Argument Type Required Limits
project string yes the project's slug: 3 to 40 lower-case letters, digits and hyphens, starting with a letter. An existing slug from list_projects, or a new one to create
name string yes 1 to 80 characters: the demo's name, shown in the room
device string no the frame the room draws the demo in when there is no manifest: phone, tablet, laptop, screen or none. The default is laptop
files array yes 1 to 200 files, each an object with path, content and encoding
files[].path string yes 1 to 255 bytes, relative to the demo's root, such as index.html
files[].content string yes the file's content
files[].encoding string no utf8 (the default) or base64, for an image or any other binary file
manifest object no pitch.json for the demo: its apps, its tour (story) and its pages, each page a Markdown or HTML file among files. kind is static and may be left out; output is not used, since the files are the build
note string no up to 200 characters, kept with the build
commit boolean no false (the default) rehearses; true publishes
{
  "project": "corner-teaser",
  "name": "Corner teaser",
  "files": [
    { "path": "index.html", "content": "<!doctype html><title>Corner</title><link rel=\"stylesheet\" href=\"style.css\"><h1>Corner</h1>" },
    { "path": "style.css", "content": "h1 { font-family: system-ui; }" },
    { "path": "why.md", "content": "# Why Corner\n\nCoaches lose an hour a day to paperwork." }
  ],
  "manifest": {
    "apps": [{ "id": "teaser", "name": "Corner teaser", "path": "/", "device": "phone" }],
    "story": [
      { "id": "hello", "title": "Corner, at a glance", "say": "One screen that tells a coach what matters today.", "app": "teaser" }
    ],
    "pages": ["why.md"]
  }
}

Before anything is sent, the files and the manifest are checked, exactly as check_bundle checks them, and every problem is returned at once with its fix: Every check, and its fix. Without a manifest, the demo becomes a one-app static build: pitch.json with kind: static, the one app web at /, named name and framed as device. The manifest's pages are not files of the demo: they are added to the room's Read more, each titled from its first heading.

Without commit, it returns the plan and changes nothing:

Rehearsal only: nothing has been sent to the platform.
Project: corner-teaser (new; it will be created)
Files: 2, 121 bytes (205 bytes packed)
  index.html  91 bytes
  style.css  30 bytes
Apps: teaser at / (phone)
Story: 1 step: hello
Pages: why.md as "Why Corner"
Manifest: {"kind":"static","output":".","name":"Corner teaser","apps":[…],"story":[…],"pages":["why.md"]}
Publishing makes this the live build of the room. Call again with commit: true only after the person says yes.

With commit: true, it creates the project if the slug is new, uploads the files, registers the build with its manifest, adds the pages, makes the build live, and returns the same plan headed Live: build <id> of <slug>. It ends with the next steps the plan allows, read as pitch deploy --commit reads them: on a paid plan the room is private, and create_link makes a viewer's link; on Free, which has none, the room is a draft, and the next step is to list it on the community with set_community_card and request_listing. It gives the room's address only once the project is listed, since until then it opens to nobody. A demo published without a tour or pages is told to add them next. The deploy that creates a project ends with one more line, a tip said once and never on a later deploy: for a container demo, a build over 200 files or 3 MB, or work in a repository with Claude Code, the pitch CLI deploys from the person's own machine, installed with npm install -g @pitch-product/cli and then pitch login.

community_card

Shows a project's community card (its title, one line and cover) and where its listing stands: an unlisted draft, listed (with its public address), blocked by a check (with the field and the reason), taken off by Roomi (with its comment), or waiting for review; any review asked for, and whether one can be. Also what the pre-flight check found when listing was last asked for. Changes nothing.

Read-only.

Argument Type Required Limits
projectId string yes 1 to 100 characters: the id from list_projects
{ "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53" }

Returns the card and its state, as text:

Title: A portal for a trade supplier
One line: Orders, invoices and deliveries, in one place.
Cover: PNG, 48213 bytes
Listing: listed since 2026-10-07T09:12:00.000Z. Public on the community at https://trade-portal.getroomi.app: anyone can open it, with no link and no account.
withdraw_listing takes it off the community; set_community_card changes the card, which is checked again and stays listed unless a check fails.

Blocked, it names each thing a check found, by its field and what it is, such as "The build ships a program or an installer (downloads/setup.exe)", and never the list it was checked against. Taken off, it gives Roomi's comment as you see it beside the card in the app. Either way it says what to change, and, when a review can be asked for, that appeal_listing asks for one. With no card yet, it says so, and that set_community_card writes one.

set_community_card

Writes a project's community card: what strangers see on the community, separate from the pitch, so written for someone who does not know the business. Without commit it is a rehearsal and changes nothing: it runs the pre-flight check on the project with these words, which names anything that might identify a real business or client (a domain, a recurring name, an image named like a logo), and says what saving would do. With commit: true it changes something: it saves the card, and the cover if one is given. A listed card is checked again as it now reads: it stays listed, or is blocked if a check fails. A new cover is held back from the community until its own check passes. A cover is either coverFile, an image already in the project's live build (a screenshot the demo ships), copied on the platform; or cover, an image's bytes as base64. Tell the person what the check found and suggest neutral wording; call with commit: true only after they have seen the rehearsal and said yes. It never asks for listing: request_listing does.

Changes something with commit: true; without it, it only reads the card and runs the check.

Argument Type Required Limits
projectId string yes 1 to 100 characters
title string yes 1 to 60 characters, trimmed
line string yes 1 to 140 characters, trimmed
coverFile string no an image in the project's live build to make the cover, by its path from the build's root, such as img/screenshot.png: no leading /, no . or .. segments, up to 255 characters. Not with cover
cover object no a cover image sent as its bytes, with type and data, when it is not in the build. Not with coverFile. Without either, the cover stays as it is
cover.type string yes, with cover image/png, image/jpeg or image/webp
cover.data string yes, with cover the image's bytes as base64 (a data: URL's prefix is allowed), at most 1 MB once decoded
commit boolean no false (the default) rehearses; true saves
{
  "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53",
  "title": "A portal for a trade supplier",
  "line": "Orders, invoices and deliveries, in one place.",
  "coverFile": "img/screenshot.png"
}

A coverFile is read by the platform from the project's live build, found by the build's own record, so the path names only a file inside it: its type is read from its bytes, never its name, and it must be a PNG, JPEG or WebP image of at most 1 MB, as an uploaded cover must. A container build is never unpacked, so it has no file to take. The rehearsal reads it and says what it is; only commit: true copies it, on the platform, into the card's cover, stored and served from the card's row like an uploaded one. Nothing is uploaded.

A cover is checked before anything is sent, as the app checks a file you choose, and by its bytes too: they must be the image type says. A cover that is not base64, is over 1 MB, or is not that image is refused with what is wrong, and the platform hears nothing.

Without commit, it returns what would change and what the pre-flight check finds in the project with these words:

Rehearsal only: nothing has been saved. Show the person this, and call again with commit: true only on their clear yes. A yes does not carry over once anything changes.
Title: A portal for a trade supplier
One line: Orders, invoices and deliveries, in one place.
Cover: a new PNG image, 48213 bytes, copied from the live build's img/screenshot.png
Saving writes it as an unlisted draft: nothing is public until request_listing lists it.
What the check found, with these words:
- A real-looking web address: northwind-traders.co.uk (found in index.html)
These are guesses, and none of them stops a listing. Tell the person what each might reveal about a real business or client, and suggest neutral wording for the card (or a change to the demo) that names nobody real. Change nothing without their yes. Roomi may look at a listing these name.

With commit: true, it saves the words through the same route as Save the card in the app, then the cover: a cover's bytes through the same route as Upload cover, a coverFile through the platform's copy, which stores it through the same data layer, and returns the card as it now is. Words already saved are not saved again, so sending only a cover changes only the cover. A listed card is checked again as it now reads: it stays listed if the checks pass, and is blocked, off the community, if one fails; the rehearsal says so first. A new cover on a listed card is held back, with a placeholder on the community, until its own check passes. A card waiting for review takes the new words, and those are what Roomi reads. A listed card can be changed 10 times a day in a workspace.

request_listing

Lists a project on the community: public at one address, behind its card. Roomi checks the card and the build first; if they pass, it is listed at once. Without commit it is a rehearsal and changes nothing: it runs the checks dry and says "would be listed now", "would be blocked" (and why) or "would wait for review", runs the pre-flight check, and says what listing means: anyone can open the address with no link and no account, 5 people at once, and on Free its analytics are total views only. With commit: true it changes something: the checks run for real, and the project is listed, blocked, or (after Roomi took it off before) sent for review. At most 3 a day for a workspace. Explain what listing means to the person and call with commit: true only on their yes. Needs a saved card (set_community_card) and a live build.

Changes something with commit: true; without it, it only reads and runs the checks dry.

Argument Type Required Limits
projectId string yes 1 to 100 characters
commit boolean no false (the default) rehearses; true asks to list it, and lists it if the checks pass
{ "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53" }

Without commit, it runs the checks without writing or counting anything, and says which of three things committing would do; then the card, what listing means (the same points the app lists under Community listing, and on Free that listing is how anyone outside the workspace sees the demo), and what the pre-flight check finds:

Rehearsal only: nothing has been listed. Show the person this, and call again with commit: true only on their clear yes. A yes does not carry over once anything changes.
Project: trade-portal
Title: A portal for a trade supplier
One line: Orders, invoices and deliveries, in one place.
Cover: PNG, 48213 bytes
Listing: not listed. The project is an unlisted draft: only this workspace can open its room (Preview as viewer, in the app).

Would be listed now: the checks pass, so committing makes it public at https://trade-portal.getroomi.app at once.
Roomi's content check of the card's words runs only on the real request, so it can still block what this rehearsal passes.

What listing means, for the person to read before they agree:
- Once listed, the project is public at https://trade-portal.getroomi.app: anyone can open it, with no link and no account.
- Analytics there count visitors and never say who they are; on Free they are total views only.
- 5 people can be in it at once; anyone after that is told it is full.
- Roomi checks the card and the build when listing is asked for, and lists them at once if they pass; a card that fails a check is not listed, and the reason is said beside it.
- Changing a listed card or deploying a new build checks it again: it stays listed unless a check fails. A new cover shows once its own check has passed.
- Roomi may take a listing off the community, with a comment saying why; asking again then waits for review.
- This workspace is on Free, which has no private viewer links: listing is how anyone outside it sees the demo, and what it shows of them is total views.
- withdraw_listing takes it off the community at any time.

What the check found: nothing that looks like a real business.

"Would be blocked" names what a check found, by its field and what it is, and says to change it first. "Would wait for review" says why: Roomi took the project off the community before, or has taken two or more of the workspace's listings off. The content check of the card's words is not switched on yet, so for now the word list and the build's checks decide, and they decide the same in the rehearsal as in the real request.

With commit: true, it does what List on the community does in the app: the checks run, and it answers "Listed: the checks passed, and the project is public at …", "Not listed: a check blocked it." with what the check found, or "Sent for review: nothing is public until Roomi lists it." What the pre-flight check warns about never blocks. Without a saved card, or with nothing live in the project, it is refused and says which. A listed project has nothing to ask for. A workspace can ask 3 times a day, and one person 5 times.

withdraw_listing

Takes a project off the community, or out of review. Without commit it is a rehearsal and changes nothing: it says what would stop. With commit: true it changes something: a listed project’s public address stops answering at once, for everyone, and listing it again runs the checks again. The card is kept, as an unlisted draft. Call with commit: true only on the person’s yes.

Changes something with commit: true. A project taken off is listed again only by asking again, which runs the checks again.

Argument Type Required Limits
projectId string yes 1 to 100 characters
commit boolean no false (the default) rehearses; true withdraws
{ "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53", "commit": true }

It does what Unlist does in the app. A project that is neither listed nor waiting for review has nothing to withdraw, and it says so without changing anything.

appeal_listing

Asks Roomi to review a block by its checks, or its decision to take a listing off, in the person's own words. Without commit it is a rehearsal and changes nothing: it says whether a review can be asked for now, and what would be sent. With commit: true it changes something: the review is asked for. One at a time; at most 3 in 30 days for a workspace. If Roomi agrees, this exact card and build are listed; any later change is checked again. Write the message with the person, and call with commit: true only on their yes.

Changes something with commit: true; without it, it only reads the card.

Argument Type Required Limits
projectId string yes 1 to 100 characters
message string yes why the person thinks it is wrong, in their words: 10 to 1,000 characters, trimmed
commit boolean no false (the default) rehearses; true asks for the review
{
  "projectId": "3f2b8c1e-5a47-4d9e-8b21-6c0f9e7a4d53",
  "message": "setup.exe is an empty placeholder; the demo never offers it for download.",
  "commit": true
}

It does what Ask for a review does in the app, and returns where the listing now stands:

Asked for. Roomi reads it and answers in a notice (list_notices).
Listing: blocked by Roomi's checks, so not listed. The build ships a program or an installer (downloads/setup.exe). A review was asked for on 2026-10-07T10:04:00.000Z, and Roomi has not decided yet.
Change what the check found with set_community_card, then request_listing asks again.

A review can be asked for while the card is blocked, or while it is off the community after Roomi took it off. With one already waiting, it says to wait for its answer; past 3 in 30 days, or with nothing to review, it says so, and changes nothing. The answer arrives as a notice, and beside the card: upheld, the card and build that were reviewed are listed as they were; declined, the card stays off, with Roomi's note.

list_notices

The person's own notices in this workspace, newest first: a listing taken off by Roomi, a project taken down, a review decided. Changes nothing, and marks nothing read.

Changes nothing. It takes no arguments.

- 2026-10-07T11:30:00.000Z (unread): The review of “A portal for a trade supplier” is decided: it is listed again. The file is empty, as you said, so the card is listed as it was.

Each notice is its title and then what Roomi wrote: for a listing taken off, the comment; for a review, the note on the decision.

The same notices the app shows under Notices, the last fifty. Notices are in the app only: none is sent by email yet.

list_workspaces

Every workspace the person belongs to: their own (never called a team), and each team, with their role in it (owner or member) and its id. Marks the one this connection works in: list_projects, deploy_static, create_link and the other project tools act there. The team tools here take a workspace id and act in that one. Changes nothing.

Changes nothing. It takes no arguments.

The project tools work in the workspace you were in when you connected Claude. To work in another, switch to it in the app and connect again.

list_members

Everyone in a workspace the person belongs to, with each one's role (owner or member), email and id. Their own workspace has only them. Changes nothing.

Changes nothing.

Argument Type Required Limits
workspace string yes 1 to 100 characters: a workspace id from list_workspaces
{ "workspace": "8d1c6e2a-4b7f-4e09-9a31-2f5d7c8b0e64" }

list_invitations

A team's invitations still waiting: each email, who invited them, when it expires, and its id. Only the team's owners see them. Changes nothing.

Changes nothing. A member of the team is told that only its owners can.

Argument Type Required Limits
workspace string yes 1 to 100 characters: a team's id from list_workspaces

invite_member

Invites one email into a team, as a member. Nothing is emailed: the result is a link for the person to send themselves, which works once, only for someone signed in with that email, for 7 days. A waiting invitation holds one of the plan's seats. Without commit it is a rehearsal and changes nothing: it says what would happen, or why it cannot (someone in the team already, or invited already). With commit: true it changes something: the invitation is made. Only the team's owners can.

Changes something with commit: true. A team at its plan's seats, counting the invitations waiting, is refused.

Argument Type Required Limits
workspace string yes 1 to 100 characters: a team's id from list_workspaces
email string yes an email address, at most 254 characters
commit boolean no false (the default) rehearses; true invites
{ "workspace": "8d1c6e2a-4b7f-4e09-9a31-2f5d7c8b0e64", "email": "tesh@daedalus.example", "commit": true }

Returns the link to send. Only someone signed in with that email, verified as theirs, can use it: the link alone is not the key.

revoke_invitation

Revokes an invitation still waiting, so its link stops working at once. Without commit it is a rehearsal and changes nothing. With commit: true it changes something. Only the team's owners can.

Changes something with commit: true.

Argument Type Required Limits
workspace string yes 1 to 100 characters: a team's id
invitation string yes 1 to 100 characters: an invitation id from list_invitations
commit boolean no false (the default) rehearses; true revokes

set_member_role

Makes someone in a team an owner or a member. Owners also manage the team's billing, plan, people, name, brand and deletion; both roles see viewers and feedback. A team always keeps an owner. Without commit it is a rehearsal and changes nothing. With commit: true it changes something. Only owners can.

Changes something with commit: true. The team's only owner is never made a member.

Argument Type Required Limits
workspace string yes 1 to 100 characters: a team's id
person string yes 1 to 100 characters: a person's id from list_members
role string yes owner or member
commit boolean no false (the default) rehearses; true changes the role

remove_member

Takes someone out of a team: from their next request they reach none of its projects, viewers or feedback. Nothing they wrote is deleted, and they can be invited again. Not yourself: leaving is done in the app. Without commit it is a rehearsal and changes nothing. With commit: true it changes something. Only owners can.

Changes something with commit: true.

Argument Type Required Limits
workspace string yes 1 to 100 characters: a team's id
person string yes 1 to 100 characters: a person's id from list_members
commit boolean no false (the default) rehearses; true removes them

public_address_status

Whether a project's public address (the room its Community listing opens) is turning new visitors away right now, and until when. A sudden rush of new visitors, far beyond a busy room, trips it; it opens again by itself a few minutes later. People already in the room keep their seats, and private viewer links and the members’ preview are never affected. Also lists every time it happened, newest first. Changes nothing.

Changes nothing. It reads the project's room history, the same record the app's Activity tab shows.

Argument Type Required Limits
projectId string yes 1 to 100 characters: a project id from list_projects
{ "projectId": "6f2a9c1e-3b8d-4f70-a5e2-9d1c4b7e0a38" }

get_brand

Shows the workspace's brand (its name in the room, its accent colour and whether it has a logo) and its room theme, and what the room shows of each now and why: a plan without its own branding shows neither, and the room theme is a team plan's. Also any saved colour that does not read now, which the room draws as its own instead. Changes nothing.

Changes nothing. It takes no arguments.

set_brand

Sets the workspace's brand for its rooms: the name the room calls the publisher, the accent colour, and the logo. Any left out stays as it is. Without commit it is a rehearsal and changes nothing: it checks the accent with the platform's own contrast guard (an accent no viewer could read is refused, with the nearest shade that would pass) and the logo's bytes, and says what would change. With commit: true it changes something. A logo is a PNG, JPEG or WebP image of at most 256 KB, 16 to 2048 pixels a side and no more than 8 times as wide as it is tall, sent as base64; an SVG is refused: convert it to a PNG first. Changing the brand is an owner's to do in a team.

Changes something with commit: true; otherwise a rehearsal.

Argument Type Required Limits
name string or null no 1 to 80 characters; null uses the workspace's own name
accent string or null no #rrggbb; null uses the room's own
logo object no A new logo, replacing any there is
logo.type string yes, with logo image/png, image/jpeg or image/webp
logo.data string yes, with logo The image's bytes, base64-encoded: at most 256 KB
commit boolean no false (the default) rehearses; true saves
{ "name": "Northwind", "accent": "#1f6b4a", "commit": true }

It does what Save brand and Upload logo do in the app, by the same routes, and an accent is refused by the same check: the rehearsal says each pair that fails in words, and the nearest shade of the colour that would pass. Your brand in the room has the rules.

Removes the brand's logo: rooms show the initial of the name instead. Without commit it is a rehearsal and changes nothing; with commit: true it changes something, and the logo is deleted.

Changes something with commit: true, and the logo cannot be brought back: upload it again.

Argument Type Required Limits
commit boolean no false (the default) rehearses; true removes it

set_room_theme

Sets the workspace's room theme, whole: the tour's colour, the highlight (the ring over the demo), the attention colour, the background, the surface and the text as #rrggbb, the corners (square, soft or round) and the typeface (system, serif or rounded). A token left out is the room's own. Light themes only. Without commit it is a rehearsal and changes nothing: the platform's own contrast guard checks every pair the room would draw, and it says in words what reads and what does not (with the nearest shade that would), and the colours the room would draw. With commit: true it changes something: the theme is saved. It is kept whatever the plan, and shown on a team plan.

Changes something with commit: true; otherwise a rehearsal.

Argument Type Required Limits
tour string or null no #rrggbb; unset or null follows the accent
highlight string or null no #rrggbb; unset or null follows the accent
attention string no #rrggbb
background string no #rrggbb, light
surface string no #rrggbb, light
text string no #rrggbb
radius string no square, soft or round
font string no system, serif or rounded
commit boolean no false (the default) rehearses; true saves
{ "tour": "#6a3fb5", "background": "#fdf8ef", "font": "serif", "commit": false }

The tokens and their checks are in Your brand in the room.

reset_room_theme

Removes the room theme: rooms are drawn in the room's own look again (the brand's accent, name and logo are kept). Without commit it is a rehearsal and changes nothing; with commit: true it changes something, and the saved theme is gone.

Changes something with commit: true.

Argument Type Required Limits
commit boolean no false (the default) rehearses; true removes it

When a tool fails

A tool that fails returns an error result Claude can read, never a broken connection. What it says:

Cause What the tool says
The platform does not accept who you are, or you have left the workspace "The platform refused this connection. Disconnect Roomi in Claude and connect it again." (through the plugin: "The platform refused the token. Run pitch login again.")
A plan's limit "That is past what the plan allows." and the platform's own words, which name the limit and the plan that allows more
The platform answered 403 "That belongs to a workspace this sign-in cannot reach." From a team tool: "Only the team's owners can do that: ask one of them."
An id that is not in this workspace, including another workspace's "Not found in this workspace."
A refusal on the merits (a slug taken or not allowed, an upload refused) "The platform refused it (409)." or "(422)", and the platform's reason
The platform did not answer "The platform API at … did not answer."
Any other status "The platform API answered" and the status
deploy_static's files or manifest every problem, each with its fix, as check_bundle says them
set_community_card's cover what is wrong with it: not base64, over 1 MB, or not the image its type says; for a coverFile, no such file in the live build, not a PNG, JPEG or WebP image, or over 1 MB
request_listing with no card, or nothing live which of the two, and the tool or step that fixes it
A listing limit (429): 3 requests a day for a workspace or 5 for a person, or 10 changes to a listed card "Not now: a limit was reached." and the platform's words, which say which limit and when to try again

Errors lists every refusal the platform makes.