# Connect Mocco to your agent

Mocco speaks the Model Context Protocol, so the assistant you already code with can
answer "is the deploy stuck, and on what?" without you leaving the terminal.

The server is **remote and hosted by us** — nothing to install, nothing to keep updated.
You sign in once in the browser and the client holds the token.

```
https://www.mocco.club/api/mcp
```

> The read tools are in, and so are the deciding tools: voting on an approval request,
> resuming or rejecting a paused run, changing where notifications go, working the messenger
> inbox and its settings, setting up feedback boards, writing, moving, commenting on, voting on, merging, converting and linking feedback posts to GitHub and marking them shipped from a release, writing and publishing changelog entries, and writing,
> publishing and translating help center articles, and creating flags and proposing flag changes. The plan is in the
> [design spec](https://github.com/fi-workers/mocco/blob/main/docs/specs/2026-10-02-mcp-and-cli-design.md).

## What it can do

**It reads as you.** You see what your Mocco roles let you see, in whichever workspaces
you belong to — never more, because the server has no privileges of its own.

| Tool | Answers |
|---|---|
| `mocco_runs_search` | Which runs are running, waiting or failed. Filter by `awaiting_gate` for "what is blocked" |
| `mocco_runs_get` | One run: its steps, and the gate holding it (with its `itemIndex`) and what would release it |
| `mocco_approvals_search` | What is waiting on a human right now, each request with a short label of what it is about ("Production", "production channel", "Shopper (iOS)") |
| `mocco_approvals_get` | One request: the change it pins, the requirements, and the votes so far |
| `mocco_flags_search` | Which feature flags a project has, by key or description text, lifecycle, or whether the repository defines them, and where each is on |
| `mocco_flags_get` | One flag: its variants, what it serves in each environment, and whether `.mocco/flags.yml` manages it |
| `mocco_flags_changesets_search` | Which flag changes wait for approval in a protected environment, each with the approval request deciding it |
| `mocco_flags_changesets_get` | One flag change: what it changes, its state, the content an approval would apply, and the votes cast on it |
| `mocco_flags_environments_list` | A project's flag environments, which of them are protected, and each one's current version |
| `mocco_flags_segments_search` | An environment's segments by key or name, and who they include and exclude |
| `mocco_flags_preview` | What an environment's flags would serve a given user or context, now or with changes you have not saved |
| `mocco_flags_ruleset_get` | The ruleset your SDKs read for an environment: its version, ETag and each flag's state (the whole document when detailed) |
| `mocco_flags_deploy_check` | Whether a flag's key is in the code the environment last deployed, before you turn it on |
| `mocco_flags_timeline_search` | An environment's flag changes and its pipeline's runs, newest first: what changed around a deploy |
| `mocco_flags_usage_search` | How often your SDKs evaluated each flag over the last days, and when each was last seen |
| `mocco_flags_stale_search` | Which flags look ready to remove: unused, never evaluated, or serving one variant to everyone |
| `mocco_flags_file_syncs_search` | Your recent `.mocco/flags.yml` syncs, how each ended, and why a file was refused |
| `mocco_ota_channels_search` | What each OTA channel serves now, per platform and runtime version: the release, a rollout in progress and its share, and whether it is paused or rolled back |
| `mocco_ota_releases_search` | Which OTA releases CI uploaded, newest first, by message or commit, runtime version, state or platform |
| `mocco_ota_adoption_get` | How many devices checked in during the last 24 hours, per channel and release, and the app's monthly active devices |
| `mocco_ota_version_policies_search` | The minimum supported, recommended and blocked versions of each iOS and Android app, and whether tightening them needs approval |
| `mocco_desktop_releases_search` | A desktop app's releases, newest first, by state, version prefix or the channel serving them |
| `mocco_desktop_releases_get` | One desktop release by id or version: its state (and why it failed or was withdrawn), its files with sizes, SHA-256 and signature key ids, and the channels serving it |
| `mocco_desktop_releases_channels` | What each of a desktop app's channels serves per platform now |
| `mocco_desktop_releases_stats` | How often each version was downloaded per day, by people and by the updater |
| `mocco_projects_search` | The workspace's projects with their apps, and which product lines the workspace has on |
| `mocco_projects_create` | Creates a project in the workspace |
| `mocco_projects_apps_add` | Adds an app (React Native, iOS, Android, web or server) to a project |
| `mocco_products_enable` | Turns a product line, such as OTA, on for the workspace |
| `mocco_ota_setup_get` | A project's React Native apps and, for each one Mocco hosts, its manifest URL and `expo.updates` block, channels, signing certificates and trusted repositories, and what is still missing before the first update |
| `mocco_ota_apps_host` | Hosts OTA updates on Mocco for a React Native app, and answers its manifest URL |
| `mocco_ota_channels_create` | Adds an open channel, such as `staging`, to a hosted app |
| `mocco_ota_certificates_add` | Registers the code signing certificate the app embeds, so Mocco accepts updates signed by its key |
| `mocco_ota_trust_policies_create` | Trusts a GitHub repository to publish from Actions without a stored key, and names the open channels it may promote to |
| `mocco_status_pages_get` | What a status page says right now: each component and the status it shows, counting open incidents and maintenance in progress |
| `mocco_status_incidents_search` | Which incidents are open (or were), newest first, by status, severity, page or title text, and whether each was opened by hand, by a monitor or by a deploy watch |
| `mocco_status_incidents_get` | One incident: where it came from, the run a deploy watch suspects (with a link to it), every update posted to it, the components it affects and how badly, its postmortem, and the deploys linked to it |
| `mocco_status_maintenances_search` | Which maintenance windows are scheduled or in progress, and the components each covers |
| `mocco_status_monitors_search` | Which HTTP, TCP and heartbeat monitors a project has, what each checks (the host only), its state (for example the ones down) and since when, the components it reports on, and for a heartbeat its period, grace, last ping and last run |
| `mocco_status_monitors_get` | One monitor: its latest state changes and why, its latest rounds, and the incident it opened that is still open |
| `mocco_status_locations_search` | Where monitors run: Mocco's hosted regions, your private locations and the embedded probe, with when each agent was last seen |
| `mocco_status_run_incidents_list` | Which status incidents a run is linked to, across your projects |
| `mocco_status_gate_maintenances_search` | Which pipeline gates announce maintenance on a status page, and what each announces |
| `mocco_help_articles_search` | Which published help center articles match a question (every word, or any word for a customer's message), or every article in order, in a language where translated |
| `mocco_help_articles_get` | One published help article's Markdown, in the asked language where translated, the languages it is published in, and how readers answered "Was this helpful?" in the last 30 days (with their newest comments when detailed) |
| `mocco_help_translations_list` | How far the help center is translated: per language, how many articles are reviewed, machine translated, out of date, failed or not translated, and which articles need attention (or are stale, or failed, or all), narrowed to text that came from git, a person or the machine, with each one's status and origin per language |
| `mocco_help_translation_get` | One article in one language: who reviewed it and when, whether a machine draft is waiting, and exactly which sentences of the original changed since it was translated (with the texts when detailed) |
| `mocco_help_glossary_list` | The help center's glossary every translation follows: names kept as written in every language, and words translated one fixed way per language, found by text, rule or language |
| `mocco_help_site_get` | Your help center as its editors see it: its address, its languages, whether its content is managed in git and from where, and its collections and sections with how many articles each has |
| `mocco_help_drafts_list` | Every help article, published or not, with its draft title and whether the draft has changes not yet published; by status, collection, section or title |
| `mocco_help_draft_get` | One help article as the editor shows it: the draft's Markdown, and which revision is published |
| `mocco_help_revisions_list` | An article's history, newest first, or one earlier revision in full |
| `mocco_messenger_conversations_search` | Which messenger conversations are open (or closed), newest activity first, by assignee (yours, someone's, or no one's) or by contact (id, email or your app's user id), with a preview of the latest message and whether you have read it |
| `mocco_messenger_conversation_get` | One conversation's thread: every message from the user and your team, internal notes marked, and each attachment's name, type and size |
| `mocco_messenger_settings_get` | Whether a project's messenger is set up, the categories users pick from and whether people who aren't signed in may write; never the identity secret |
| `mocco_messenger_inbox_members_list` | Who takes new conversations (round robin), in order, and whether each is available or away |
| `mocco_feedback_boards_list` | Which feedback boards a project has, whether each is public, and their categories in order |
| `mocco_feedback_posts_search` | A board's posts by status (under review, planned, in progress, shipped, closed) or newest first, by status or category, a page at a time |
| `mocco_feedback_post_get` | One feedback post, and every status it took and when |
| `mocco_feedback_ship_suggestions_list` | The releases waiting for you to mark feedback posts shipped: the commit, who approved it, the posts and the draft changelog entry |
| `mocco_feedback_votes_list` | Who voted for a feedback post (your app's id for each end user), and whether each vote counts yet or waits for an email confirmation |
| `mocco_feedback_comments_list` | A feedback post's comments as your team sees them: end users' comments, your official response, and internal notes, marked |
| `mocco_feedback_board_get` | One feedback board: whether it is public, its categories, and which releases ship its posts |
| `mocco_feedback_subscribers_list` | Who follows a feedback post, a page at a time |
| `mocco_feedback_duplicates_list` | A board's possible duplicates still to decide, with both posts |
| `mocco_feedback_intake_preview` | What turning a messenger conversation into a feedback post starts from: a title, the customer's words, and the board's posts it may repeat |
| `mocco_feedback_source_posts_list` | The feedback posts a messenger conversation became |
| `mocco_feedback_post_sources_list` | The messenger conversations a feedback post came from, with the customer's words |
| `mocco_changelog_entries_search` | A feedback board's changelog entries: drafts, scheduled and published, a page at a time |
| `mocco_changelog_entry_get` | One changelog entry: its state, tags, the posts it announces and its text |
| `mocco_feedback_links_list` | The GitHub issues and pull requests a feedback post links: open, closed or merged, the merge commit, and the pull requests that close a linked issue |
| `mocco_feedback_github_search` | Issues or pull requests in the GitHub repos linked to the project, by words or number, to link one to a post |
| `mocco_notifications_channels_search` | Which Discord channels Mocco posts to, and why a disabled one is disabled |
| `mocco_notifications_rules_search` | Which events go to which channel: the event type, the source and the filter of each rule |
| `mocco_notifications_activity_search` | What became of each webhook and Mocco event: per channel, sent or failed (with the error), or why it got nothing |
| `mocco_inbound_sources_search` | Which Sentry, Vercel and GitHub webhook sources the workspace has, whether each accepts deliveries, and what became of the latest |

Reads take a `responseFormat`: `concise` by default, `detailed` when the agent wants the
commit and the gate requirements too. That keeps a search from spending your context on
rows you did not ask about.

**Which workspace?** If you belong to one, say nothing. If you belong to several, the
tool asks which and names them — and a workspace you are not a member of is refused
whether or not it exists.

**Which project?** The flag tools read one project. If the workspace has one, say nothing;
otherwise the tool names the projects to pick from. They answer only where the workspace
has feature flags turned on, as the console does. Name an environment by its key, such as
`production`; an unknown one is refused with the keys the project has. The preview saves
nothing, even with changes in it. Usage counts only what your SDKs reported, so a flag no
SDK evaluated is not listed. To change flags, see **Changing flags** below; a flag that
`.mocco/flags.yml` manages changes only in the repository.

The OTA tools pick their project the same way and answer only where OTA is turned on. The
channel, release and adoption tools read one hosted app: leave `appId` out when the
project hosts one, or the tool names the apps to pick from. They only read; promote, roll
out, pause, roll back and change a version policy in the console or with `mocco ota`.

The status page tools pick their project the same way and answer only where the status
page is turned on. `mocco_status_pages_get` reads one page: leave `pageId` out when the
project has one, or the tool names the pages to pick from. The incident and maintenance
searches read every page of the project unless you name one. A monitor shows only the
host it checks: its full URL, request body and keyword stay on the server, since they can
hold credentials. A heartbeat shows its period, grace, when its job last pinged and how long
its last run took, never its ping token. The location tool reads the whole workspace for any
member and never returns a location's token. An incident says whether it was opened by hand,
by a monitor or by a deploy watch; for a deploy watch's, it names the run it suspects and links
to it in the console. Apart from checking a monitor now (below), they only read; declare an
incident, post an update, schedule maintenance, and add, pause or change a monitor or a
location in the console.

The messenger tools pick their project the same way and answer only where the messenger is
turned on, for any member of the workspace, as the inbox does. They read internal notes too,
since your team sees them in the inbox. An attachment comes back as its name, type and size,
never as a link to the file: open the conversation in the console to see it. A user's email,
your app's user id for them, their traits and the devices they wrote from are in the
`detailed` answer only.

The feedback tools pick their project the same way and answer only where feedback is turned
on, for any member of the workspace. A post's body is cut short
unless you ask for the `detailed` answer, which also names who wrote it and who changed each
status (as user ids).

The notification and webhook source tools read the whole workspace, with no project to
pick, and answer for any member, as the console does. They never return a signing
secret or a token: a source says whether it has a secret, and the detailed answer gives
the ingest URL your vendor is configured with, which is no credential on its own because
every delivery must also be signed. To find out why a notification did not arrive, ask
for the activity trace with the source or channel. They only read; connect channels,
edit rules and add sources in the console or with the changing tools below. On a self-hosted server without
`SECRETS_ENCRYPTION_KEYS`, the source tool says webhook sources are not configured.

**Deciding is separate and off by default.**

| Tool | Does |
|---|---|
| `mocco_approvals_vote` | Approves or rejects a pending request as you, with an optional reason |
| `mocco_gates_resume` | Resumes or rejects the gate a run is paused at, as you, with an optional reason |
| `mocco_notifications_channels_connect` | Connects a Discord channel of your workspace's server as a notification channel; Mocco posts a test message |
| `mocco_notifications_channels_reenable` | Turns a disabled notification channel back on, once the bot can reach it again |
| `mocco_notifications_rules_add` | Sends an event type (from one source or any, optionally filtered by its facts) to a channel |
| `mocco_notifications_rules_remove` | Removes a rule, so its events stop going to its channel |
| `mocco_notifications_presets_apply` | Adds a ready set of rules (`mocco`, `sentry`, `vercel`, `github`) to a channel, skipping any it has |
| `mocco_inbound_sources_create` | Adds a GitHub webhook source; its signing secret is never shown to the agent |
| `mocco_inbound_sources_pause` / `_resume` | Pauses a webhook source (its deliveries are refused) or resumes it |
| `mocco_inbound_sources_delete` | Deletes a webhook source and the deliveries it received |
| `mocco_monitors_check` | Runs an HTTP or TCP monitor's next round now, for example right after a deploy, instead of at its interval |
| `mocco_status_incident_create` | Opens an incident on a status page as you; it is public at once and sent to the page's subscribers |
| `mocco_status_incident_update_post` | Posts an update to an incident as you, moving its status (up to resolved, which closes it) |
| `mocco_status_incident_components_set` | Replaces the components an incident affects and how badly |
| `mocco_status_incident_postmortem_set` | Sets or clears an incident's postmortem |
| `mocco_status_incident_run_link` / `_run_unlink` | Links a deploy to an incident (or as the fix), or removes a link |
| `mocco_status_incident_runs_correlate` | Recomputes the deploys Mocco suggests for an incident; the ones people linked stay |
| `mocco_status_maintenance_schedule` / `_cancel` | Schedules a maintenance window, or cancels one (one in progress ends now) |
| `mocco_status_component_status_set` | Sets the status a component reports by hand |
| `mocco_status_page_create` / `_page_update` | Creates a status page, or changes its title or address |
| `mocco_status_group_create` / `_update` / `_delete` | Adds, renames or moves, and deletes a component group (its components stay, ungrouped) |
| `mocco_status_component_create` / `_update` / `_delete` | Adds, changes and deletes a component |
| `mocco_status_monitor_create` / `_update` | Creates an HTTP or TCP monitor, or changes a monitor's settings without ever reading its URL back |
| `mocco_status_monitor_pause` / `_resume` / `_delete` | Pauses, resumes or deletes a monitor |
| `mocco_status_gate_maintenance_set` / `_delete` | Makes a pipeline gate announce maintenance on a page, or stops it |
| `mocco_messenger_reply` | Sends a text reply to a messenger conversation as you; the user reads it in your app |
| `mocco_messenger_assign` | Gives a messenger conversation to a member of the workspace (you, or someone else) or to no one |
| `mocco_messenger_note_create` | Leaves an internal note in a conversation as you; only your team sees it |
| `mocco_messenger_conversation_set_status` | Closes a conversation, or opens a closed one again, as you |
| `mocco_messenger_contact_set_blocked` | Stops a user writing to your team (they can still read), or lets them write again |
| `mocco_messenger_categories_set` | Replaces the categories users pick from when they start a conversation |
| `mocco_messenger_guest_access_set` | Lets people who aren't signed in write (leaving an email), or takes only signed-in users |
| `mocco_messenger_inbox_members_add` / `_remove` | Puts a workspace member in the round-robin rotation, or takes them out |
| `mocco_messenger_inbox_members_set_availability` | Marks you (or someone in the rotation) available or away |
| `mocco_feedback_post_set_status` | Moves a feedback post to another status as you, recorded in its history |
| `mocco_feedback_ship_suggestions_accept` | Marks the posts a release shipped as shipped, as you; their email voters are mailed |
| `mocco_feedback_ship_suggestions_dismiss` | Sets a release's ship suggestions aside, as you; the posts stay as they are |
| `mocco_feedback_comment_create` | Comments on a feedback post as you: a public comment, the official response, or an internal note only your team sees |
| `mocco_feedback_post_vote` | Records an end user's vote on a feedback post on their behalf, as you; it counts at once |
| `mocco_feedback_post_merge` | Merges a duplicate feedback post into the post it repeats, as you; votes and followers move over |
| `mocco_feedback_board_create` / `_update` | Creates a feedback board, or renames it, moves its address or makes it public or private, as you |
| `mocco_feedback_board_release_policy_set` | Sets which releases ship a board's posts, and whether you are asked first, as you |
| `mocco_feedback_category_create` / `_update` / `_delete` | Adds, changes or deletes a board's category, as you; a deleted category's posts stay, uncategorized |
| `mocco_feedback_post_create` / `_update` | Writes a feedback post as your team, or edits its title, details or category, as you |
| `mocco_feedback_post_unvote` | Removes an end user's vote on a feedback post on their behalf, as you |
| `mocco_feedback_duplicate_dismiss` | Marks a suggested duplicate pair as different requests, as you |
| `mocco_feedback_intake_convert` | Turns a messenger conversation into a new feedback post, or adds it to one, as you |
| `mocco_changelog_entry_create` / `_update` | Starts a draft changelog entry, or edits one, as you |
| `mocco_changelog_entry_publish` / `_schedule` / `_unpublish` | Publishes a changelog entry now or at a time, or takes it back to a draft, as you |
| `mocco_changelog_entry_delete` | Deletes a changelog entry, as you |
| `mocco_feedback_post_link` | Links a GitHub issue or pull request to a feedback post, as you |
| `mocco_feedback_post_unlink` | Removes a feedback post's GitHub link, as you; nothing changes on GitHub |
| `mocco_help_translation_accept` | Accepts the machine draft waiting beside an out-of-date reviewed translation as the reviewed text, as you |
| `mocco_help_translation_retranslate` | Has the machine translate one language of a help article again; a language a person reviewed is replaced only when you confirm exactly that |
| `mocco_help_glossary_set` | Adds, changes or removes a term in the help center glossary every translation follows |
| `mocco_help_site_enable` | Sets up a project's help center: its address and its languages |
| `mocco_help_site_release` | Gives a help center whose content is managed in git back to the console, for an owner or admin: its articles stay, and the next `mocco help push` takes it back |
| `mocco_help_collection_create` / `mocco_help_section_create` | Adds a collection, or a section to a collection |
| `mocco_help_article_create` | Creates a help article as an unpublished draft, with its text when given |
| `mocco_help_draft_save` / `mocco_help_draft_restore` | Replaces an article's draft, or makes an earlier revision its draft again |
| `mocco_help_article_publish` / `_unpublish` / `_delete` | Publishes an article's draft, takes it off the site, or deletes it for good |
| `mocco_flags_create` | Creates a feature flag (boolean, or string, number or JSON with your variants), added disabled to every environment |
| `mocco_flags_environments_create` | Creates a flag environment, unprotected, with every flag disabled in it |
| `mocco_flags_changesets_create` | Changes flags in an environment: applied at once where it is unprotected, an approval request where it is protected |
| `mocco_flags_changesets_withdraw` / `_rebase` | Withdraws a pending flag change you proposed, or proposes it again on the environment's current version |
| `mocco_flags_set_client_visible` | Lets browsers and apps evaluate a flag, or stops them |
| `mocco_flags_environments_link_pipeline` | Links an environment to a repository's pipeline for its timeline and deploy check, or unlinks it |
| `mocco_flags_stale_dismiss` | Hides a stale flag finding until a date, or shows it again |

Deciding is switched on per workspace by an owner or admin (below). Until then your agent
can tell you a change is waiting on a second approval; it cannot be that approval.

When it is on, every decision asks you first. For a vote, your client shows what is about to
happen — approve or reject, the kind of request, what it is about, the exact change it would
let through, and your reason. For a paused run, it shows resume or reject (a reject halts the
run), the repository, the commit with its branch, the gate and what it requires, and your
reason. Nothing is recorded until you answer yes. Declining, or closing the prompt,
votes nothing. That confirmation is the protocol's own step, not a prompt we wrote, and it
is what stops a page of text your agent read somewhere from turning into a production
deploy. A confirmation is good for five minutes and only for the decision it showed: change
the decision or the reason and you are asked again.

A notification change shows exactly what would change: the server and channel to connect,
the channel to turn back on and why it is off, the event type, source, filter and channel
of a rule to add or remove, or every rule of a preset. Only an owner or admin may change
notification settings, as in the console: a plain member is refused before being asked.
To find the channel to connect, `mocco_notifications_discord_channels_search` lists the
text channels the Mocco bot sees in your server and which are connected already; it is a
read, but owners and admins only, because it spends the shared bot's Discord calls.
Installing the bot in a Discord server and removing a channel stay in the console for now.

**Changing flags.** The flag tools change flags the way the console does, and never approve
anything. A change to an unprotected environment applies at once; a change to a protected
one opens the same approval request the console opens, and someone in the roles it requires
decides it, in the console or with `mocco_approvals_vote`. When you vote on a flag change
that way, your client shows its diff (`flag new-checkout enabled: false → true`), and an
approval applies exactly that change or nothing. Before a flag change, your client shows the
environment, whether it is protected and who must approve, every value that would change
and your reason. If the environment changes before you answer, your answer is refused and
you are asked again with the new state. A pending change cannot be edited: withdraw it and
propose a new one, or propose the same one again on the current version (earlier votes do
not carry over). Only the person who proposed a change can withdraw or rebase it. A flag
that `.mocco/flags.yml` manages is refused: change it in the repository. The tools need
their own permission, asked for the first time one is used: **Create feature flags and
propose flag changes as you; protected environments still wait for approval**. Not
available to agents: the kill switch (it bypasses approval, so whether an agent may use it
is still being decided), choosing who may kill a flag, and protecting an environment or
changing who must approve its changes. Use the console for those.

**Checking a monitor now.** `mocco_monitors_check` is what a pipeline step does with
`POST /v1/monitors/{id}/check`: the probes check your service right away, and
`mocco_status_monitors_get` shows the verdict once they report. It moves the monitor's next
round, so it follows the same rules as the other changes: the workspace must allow agents to
make changes, and your client first shows the monitor, what it checks, its state and when its
next round is due. Nothing runs until you answer yes. It needs its own permission, asked for the
first time it is used: **Change your status pages as you** (below). Any member of the
project may check its monitors, as in the console. A heartbeat (its job pings it) and a paused
monitor are refused before you are asked anything.

**Running an incident from your agent.** The same permission and the same workspace switch
let an agent do what the status page's incident and maintenance screens do: open an incident,
post its updates up to resolved, change the components it affects, set its postmortem, link the
deploy that caused or fixed it, schedule and cancel maintenance, and set a component's status.
The permission is asked for the first time one of them is used: **Change your status pages as
you: incidents, maintenance, components and monitors, and run your monitors' checks**. Any member of the project may use them, as in the console, and each is
recorded in the audit trail naming you.

What your agent writes on a published incident is what your customers read, so your client
always shows it first, exactly as it will appear, and says **PUBLIC** when it goes on the page
and to its subscribers. For a new incident that is the page, the title, severity, status,
affected components and the first update. For an update it is the incident's status now and its
latest update, where the update moves it, and your text; an update to a draft incident (one a
monitor opened, which only your team sees) says it stays in the console. Nothing is published
until you answer yes. Each confirmation is for what it showed: if a teammate posts an update,
changes a component or edits the postmortem before you answer, your answer is refused and you
are asked again with what is there now, and answering the same confirmation twice changes
things once. A move the incident can't make (back to investigating, or anything after resolved)
is refused before you are asked, with the moves it can make.

The same permission covers setting a page up: pages, component groups and components, monitors
and the gates that announce maintenance. A monitor's URL can hold credentials or a token, so your
agent never reads it back: confirmations and answers name the host only, and changing a monitor's
settings keeps its check unless a new one is given. 

Some things stay in the console on purpose: deleting a status page (it deletes everything on it,
with no undo), creating a heartbeat and issuing or rotating a location's token or a heartbeat's
ping URL (a credential is shown once, and never to an agent), and disabling a location.

**Replying and assigning in the messenger.** `mocco_messenger_reply` sends what the inbox's
**Send** does: your user reads it in the app, and gets a push notification if they turned them
on. Your client first shows who it goes to and the exact text, and nothing is sent until you
answer yes. A confirmation is for a reply after the conversation's latest message, so answering
it twice sends once, and if the user writes again before you answer, you are asked afresh. It
sends text only; attach files in the console. `mocco_messenger_assign` is the hand-off: your
client shows who has the conversation now and who would take it, and someone outside the
workspace is refused before you are asked. Round robin still assigns new conversations when
they start.

**Notes, closing and blocking.** `mocco_messenger_note_create` leaves a note only your team
sees: your client shows the exact text first, and the user is never notified.
`mocco_messenger_conversation_set_status` closes a conversation or opens it again (a user
writing in a closed one opens it again by itself). `mocco_messenger_contact_set_blocked` stops
a user writing; they can still read what they have. Each confirmation is for the state it
showed: if a teammate closes the conversation, writes in it or blocks the user before you
answer, you are asked afresh. Asking for what is so already answers without asking.

**Messenger settings and the rotation.** `mocco_messenger_categories_set` shows the categories
now and after, and warns when it removes a key an app may still send.
`mocco_messenger_guest_access_set` turns guest access on or off. The rotation tools add or
remove someone, or mark them available or away, as the **Round robin** settings do; someone
outside the workspace is refused before you are asked. Setting the messenger up and rotating
its identity secret stay in the console, because both show the secret, and so does erasing a
user, which can't be undone.

All of these follow the same rules as the other changes, need the workspace to allow agents
to make changes, and need their own permission, asked for the first time one is used:
**Reply to, note, assign, close and block in your messenger conversations, and change its
rotation and settings, as you**. Any member of the workspace may use them, as in the inbox.
Assigning, closing, reopening, blocking, the categories, guest access and joining or leaving
the rotation are recorded in the audit trail naming you; availability is not, as in the
console.

**Moving a feedback post.** `mocco_feedback_post_set_status` does what changing a post's
status on the board does: the post gets the new status (moving it to shipped records when it
shipped, and moving it away clears that), and the change goes into the post's history and the
audit trail, naming you. Your client first shows the post, the status it has now and the one
it would get, and nothing changes until you answer yes. A confirmation is for a move from the
status the post had when you were asked: if anyone moves the post before you answer, the
answer is refused and you are asked afresh, and answering the same confirmation twice moves
it once. Asking for the status a post has already answers without asking you. It follows the
same rules as the other changes, needs the workspace to allow agents to make changes, and
needs its own permission, asked for the first time it is used: **Set up your feedback boards, write, move, comment on, vote on, merge and link your feedback posts to GitHub, decide which ones a release shipped, and write and publish your changelog, as you**. Any member
of the workspace may move posts, as on the board.

**Commenting, voting and merging on feedback.** The same permission and the same workspace
switch cover three more changes, each confirmed in your client first:

- `mocco_feedback_comment_create` shows the post, what kind of comment it is (public, the
  official response, or an internal note) and the exact text. An official response can't also
  be internal.
- `mocco_feedback_post_vote` records a vote for one of your app's users, by the id your app
  knows them by, for when someone asked by email or on a call. It counts at once and they
  follow the post. A vote that counts already answers without asking. If the person votes
  themselves before you answer, the answer is refused and you are asked afresh.
- `mocco_feedback_post_merge` names both posts and their votes. The duplicate's votes and
  followers move to the other post (someone who voted on both counts once), and the duplicate
  is closed, keeping its comments and history. A merge can't be undone. If either post gets a
  vote before you answer, you are asked again with the new counts; if either is merged
  elsewhere, the merge is refused.

**Linking feedback to GitHub.** The same permission and switch cover linking a post to an
issue or pull request, as the post page's **GitHub** section does. `mocco_feedback_github_search`
finds one in the repos linked to the project (every one, or the one you name); it needs your
Mocco server's GitHub App, and says so when the project links no repo.
`mocco_feedback_post_link` shows the post, the repo and the issue or pull request with its
title and state (open, closed or merged). If its state changes on GitHub before you answer, you
are asked again with the new one. A merged post, a repo the project doesn't link, a number the
repo doesn't have and an issue the post links already are refused before you are asked.
`mocco_feedback_post_unlink` shows the link and its state, and removes it from the post only:
nothing changes on GitHub.

**Writing and translating the help center.** Every help center change shares one permission,
asked for the first time any is used: **Set up your help center, write, publish and delete its
articles, review its translations and change its glossary, as you**. Each needs the workspace to allow agents to make changes and is confirmed
in your client first; any member of the project may make them, as in the console.

- `mocco_help_translation_accept` shows the machine draft and whose reviewed text it replaces.
  If a newer draft arrives, or the article is published again, before you answer, the answer
  is refused and you are asked afresh.
- `mocco_help_translation_retranslate` asks the machine again for one language, from the
  original and without reusing earlier translations. On a language a person reviewed, the
  confirmation says so and names them; their text stays in the history. If someone reviews or
  edits the language before you answer, you are asked again about that text. A language being
  translated already answers without asking.
- `mocco_help_glossary_set` shows the term as it is now and as it would be. Translations then
  redo the sentences that contain it (a reviewed language gets a draft beside its text). If the
  term changes before you answer, you are asked again.

- `mocco_help_article_create`, `mocco_help_draft_save` and `mocco_help_draft_restore` change
  only the draft: readers keep seeing the published text until you publish. A save shows the
  title and length before and after and the start of the new text; if the draft is edited
  before you answer, you are asked again.
- `mocco_help_article_publish` shows the draft it would publish, and says whether it replaces
  what readers see. If the draft changes before you answer, you are asked again, so what goes
  public is what you saw. The site's other languages are then translated from it.
- `mocco_help_article_unpublish` takes an article off the site and keeps everything; publishing
  it again brings it back. `mocco_help_article_delete` removes the article with its history and
  translations, and can't be undone.

Writing a translation yourself, uploading images, importing from another tool, letting AI
training crawlers in, and changing a site's address or languages stay in the console.

**Marking feedback shipped from a release.** When a release contains a post's linked work,
the board's inbox suggests marking it shipped. The same permission and switch let your agent
decide, a release at a time per board, as the inbox banner does.
`mocco_feedback_ship_suggestions_list` shows each waiting release: its commit, who approved
it, the posts and the draft changelog entry. `mocco_feedback_ship_suggestions_accept` shows
the release and each post with what happens to it; a post merged or shipped since is left as
it is, the post's email voters are mailed, and the draft stays a draft for you to publish.
`mocco_feedback_ship_suggestions_dismiss` leaves the posts as they are. If anyone moves or
merges one of the posts before you answer, the answer is refused and you are asked afresh;
if someone decides the release first, the answer is refused.

**Setting up boards and writing posts.** The same permission and switch cover setting a board
up and writing posts as your team, each confirmed in your client first with exactly what would
change. `mocco_feedback_board_create` and `_update` create a board, or rename it, move its
address (its public pages move with it) or make it public or private; only what you name
changes. `mocco_feedback_board_release_policy_set` sets which repo's releases ship the board's
posts and whether you are asked first; the confirmation says plainly when posts would be
marked shipped without asking. `mocco_feedback_category_create`, `_update` and `_delete` look
after categories; a deleted category's posts stay on the board with none, and the confirmation
says how many. `mocco_feedback_post_create` writes a post as your team and
`mocco_feedback_post_update` edits its title, details or category. An address another board
or category has already is refused before you are asked. If anyone changes the board,
category or post before you answer, the answer is refused and you are asked afresh.
Deleting a board is left to the console on purpose: it deletes every post, vote, comment and
changelog entry on it, with no undo.

**Duplicates, conversations and votes.** `mocco_feedback_duplicate_dismiss` sets a suggested
pair aside for good; both posts stay as they are (merge one with `mocco_feedback_post_merge`).
`mocco_feedback_intake_convert` turns a messenger conversation into a new post or adds it to
an existing one, as **Convert to feedback** does: the confirmation quotes the customer's words
(never your internal notes) and says whether they vote for it, which they do when they were
signed in to your app. A conversation that became a post already is not made a second one.
`mocco_feedback_post_unvote` removes one end user's vote, for when they ask or it was
recorded by mistake; they keep following the post.

**Writing the changelog.** The same permission and switch cover a board's changelog.
`mocco_changelog_entry_create` starts a draft, which nobody outside your team sees, and
`mocco_changelog_entry_update` edits an entry in any state (a published entry's page changes
at once, and the confirmation says so). `mocco_changelog_entry_publish` puts it on the public
changelog and its RSS feed now, `_schedule` at a time you give, and `_unpublish` takes it back
to a draft. `mocco_changelog_entry_delete` deletes one entry; the confirmation says whether it
is public and that it can't be undone. Each confirmation names the entry and its state, and
if anyone edits, publishes or schedules it before you answer, the answer is refused and you
are asked afresh.

**Setting up a project.** Starting from an empty workspace, `mocco_projects_create` creates
a project, `mocco_projects_apps_add` adds its apps and `mocco_products_enable` turns a product
line on. Each is confirmed in your client first and needs the workspace to allow agents to
make changes and its own permission, asked for the first time one is used: **Create projects,
add apps to them and turn products on, as you**. Any member may do these, as in the console.
Archiving a project, removing an app and turning a product off stay in the console.

**Setting up OTA hosting.** An agent working in your app's repository can connect it the
way the **Hosted by Mocco** tab does: `mocco_ota_setup_get` says what the app has and what is
missing, `mocco_ota_apps_host` hosts it and answers the manifest URL for `app.json`,
`mocco_ota_channels_create` adds a channel, `mocco_ota_certificates_add` registers the
certificate (`certs/certificate.pem`) and `mocco_ota_trust_policies_create` trusts the
repository that publishes. Each is confirmed in your client first, showing exactly what
would change, and needs the workspace to allow agents to make changes and its own
permission, asked for the first time one is used: **Set up OTA hosting as you**. Any member
may host an app and add a channel; registering a certificate and trusting a repository take
an owner or admin, as in the console, because they decide whose code devices run. A private
key is refused outright — it stays in your CI. None of these ships an update: promoting,
rolling out and rolling back stay with CI and the console, and a channel made this way is
open, so protect it in the console when its promotions should wait for approval.

Webhook source changes follow the same rules, and a signing secret never passes through
your agent. `mocco_inbound_sources_create` adds a GitHub source but does not return the
secret Mocco generates for it: to get one to paste into GitHub, open **Notifications →
Sources** in the console and rotate the source's secret. A Sentry or Vercel source needs
the secret those services show you, so the tool refuses and points you to the console,
where you paste it. Rotating a secret and renaming a source also stay in the console.

The decision is then recorded exactly as if you had clicked it in the console. The request's
or gate's own rules still apply: you need one of the roles it asks for, you cannot approve a
change you requested, or resume a run you triggered, when it forbids that, and you get one
vote. A gate that needs several people stays paused until they have all voted; the tool says
where it stands.

## What it will never do

- **Act as anyone but you.** Every action goes through the same check the console does,
  with your identity. An agent cannot approve what you could not approve.
- **Accept an API key for a decision.** A key is a project, not a person, and an approval
  has to name someone who could have been asked. Keys get the read tools.
- **Hide anything from the audit trail.** A vote, a resume or a notification change made
  through an agent appears in the chain exactly like one made in the console, naming you.

## Add it

### Claude Code

```bash
claude mcp add --transport http mocco https://www.mocco.club/api/mcp
```

Then run `/mcp` and pick **mocco** to sign in. Check it took with:

```bash
claude mcp list
```

### Claude Desktop and claude.ai

**Settings → Connectors → Add custom connector**, and paste the URL above. The browser
sign-in happens inline.

### Cursor

`.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` for every project:

```json
{
  "mcpServers": {
    "mocco": {
      "url": "https://www.mocco.club/api/mcp"
    }
  }
}
```

Cursor opens the browser for sign-in by itself. Leave out any headers — this server uses
OAuth, not a token you paste.

### VS Code

`.vscode/mcp.json`:

```json
{
  "servers": {
    "mocco": {
      "type": "http",
      "url": "https://www.mocco.club/api/mcp"
    }
  }
}
```

VS Code runs the OAuth flow itself, so there is nothing to put in `headers` or `inputs`.

### Anything else

Any client on the **2026-07-28** MCP revision works: point it at the URL and let it
discover the rest. An unauthenticated call is answered with a `401` that points to the
protected-resource metadata at `/.well-known/oauth-protected-resource/api/mcp`, which names
the authorization server; its own metadata is at
`/.well-known/oauth-authorization-server/api/auth`. A conforming client follows both
without being told.

It serves that revision only, over `POST`. A client still on the older HTTP+SSE transport
will not connect — upgrade it, or use the `mocco` CLI in the meantime.

## Approving the connection

The first time a client connects, your browser opens Mocco. Sign in if you aren't already,
and Mocco asks whether to let that app read as you:

![The consent screen: the app's name, the account it would act as, what it will be able to do, and Allow or Deny](https://fi-workers-mocco-storage.s3.ap-northeast-2.amazonaws.com/pub/w/93e11fe8-0494-4e3d-b1cb-fe4dffd3ee7e/p/d64785b8-9a23-4fa1-a81d-550af30e203a/helpcenter/b63ce45d-c80d-4cfe-9ae3-d5d2c9674e14/mcp-consent.png)

**Allow** sends you back to the client, which finishes connecting by itself. **Deny** tells
the client you said no, and it gets nothing. Once you allow an app, Mocco remembers, so
reconnecting it later doesn't ask again.

Only allow an app you just started connecting. If this screen appears and you didn't start
anything, choose Deny.

### Allowing an app to vote

Connecting does not let an app vote or resume. The first time your agent tries to, Mocco answers that
the connection needs one more permission, and your client opens the same screen again with
one new line: **Approve or reject changes as you, in workspaces that allow agents to
decide**. Allow it and the client carries on with the decision, which still asks you to
confirm it. Deny it and the app keeps reading, as before. The same permission covers voting
and resuming: what you may decide is still set by your roles.

You are asked once per app. The permission does nothing in a workspace that has not allowed
agents to decide, and nothing beyond what your roles allow anywhere.

## Turning the deciding tools on

An owner or admin enables them per workspace: **Settings → Agents → Allow agents to
decide**. Switching it on records who did, and every tool it unlocks is still bound by the
roles of whoever calls it.

Leave it off for workspaces where an agent only needs to report. That is most of them.

## If it will not connect

| What you see | What it means |
|---|---|
| The client asks for a token or header | It is treating this as a key-authenticated server. Remove the header; this one is OAuth |
| `405 Method Not Allowed` on connect | The client is trying `GET` or `DELETE`. It is on the old transport — upgrade it |
| "Agents may not vote in this workspace" | Deciding is off for that workspace. An owner or admin can turn it on in **Settings → Agents** |
| "This connection may not vote" | The app was never allowed to vote. Reconnect it and allow the voting permission when asked |
| "This connection may not run checks" | The app was never allowed to run checks. Reconnect it and allow the checks permission when asked |
| "Agents may not run checks in this workspace" | Changes are off for that workspace. An owner or admin can turn them on in **Settings → Agents** |
| "… is a heartbeat; its job pings it" | A heartbeat has no rounds to run. Its last ping is in `mocco_status_monitors_search` |
| "… is paused; resume it in the console to check it" | Resume the monitor in the console first |
| "This connection may not open incidents" (or post incident updates, schedule maintenance, …) | The app was never allowed to change status pages. Reconnect it and allow the status permission when asked |
| "Agents may not open incidents in this workspace" (or post incident updates, …) | Changes are off for that workspace. An owner or admin can turn them on in **Settings → Agents** |
| "That confirmation was for a different change" after a status page change | Someone changed the incident, window or component before you answered. Call again to be asked with what is there now |
| "An incident can't go from … to …" | The incident lifecycle doesn't allow that move. The message names the moves it allows |
| "Status incident … was not found" (or page, component, maintenance) | It is in another project or workspace, or the id is wrong. `mocco_status_incidents_search` and `mocco_status_pages_get` give the ids |
| "This connection may not reply in the messenger" or "… may not assign conversations" | The app was never allowed to reply or assign. Reconnect it and allow the messenger permission when asked |
| "Agents may not reply in the messenger in this workspace" | Changes are off for that workspace. An owner or admin can turn them on in **Settings → Agents** |
| "… isn't a member of this workspace" | A conversation can only go to a member of the workspace. `mocco_messenger_conversations_search` names the people who have conversations now |
| "Conversation … was not found" | It is in another project or workspace, or the id is wrong. Search the inbox first |
| "The messenger isn't set up for this project" | Set it up from the project's **Inbox** in the console; it shows the identity secret once |
| "… is not in this inbox's rotation" | Add them with `mocco_messenger_inbox_members_add` first |
| "This connection may not change feedback statuses" (or comment, record votes, merge feedback posts) | The app was never allowed to change feedback. Reconnect it and allow the feedback permission when asked |
| "Agents may not change feedback statuses in this workspace" (or comment, record votes, merge) | Changes are off for that workspace. An owner or admin can turn them on in **Settings → Agents** |
| "That confirmation was for a different change" after moving a post | Someone moved the post before you answered. Call again to be asked about the move from its status now |
| "That confirmation was for a different change" after a vote or a merge | The end user voted, or one of the posts got a vote, before you answered. Call again to be asked with the counts as they are now |
| "… was merged into … already" | A merged post can't be merged again, merged into, or voted on. Use the post it was merged into |
| "Posts can only be merged on the same board" | Move the posts to one board first, or merge within each board |
| "Feedback board … was not found" or "Feedback post … was not found" | It is in another project or workspace, or the id is wrong. `mocco_feedback_boards_list` and `mocco_feedback_posts_search` give the ids |
| "not in a role authorized to approve" | Your roles do not cover this request. Someone in one of the roles `mocco_approvals_get` lists has to vote |
| "Agents may not resume or reject runs in this workspace" | Deciding is off for that workspace. An owner or admin can turn it on in **Settings → Agents** |
| "No pending gate at index …" | The run is not paused at that gate any more — it moved on, was decided, or is in another workspace. `mocco_runs_get` shows what it waits on now |
| "cannot resume a gate on a run you triggered" | The gate forbids the person who started the run from releasing it. Someone else in its roles has to |
| "not in a role authorized to resume" | Your roles do not cover this gate. Someone in one of the roles `mocco_runs_get` lists has to |
| "Agents may not change notification settings in this workspace" | Changes are off for that workspace. An owner or admin can turn them on in **Settings → Agents** |
| "Agents may not change webhook sources in this workspace" | The same switch, for webhook sources |
| "a secret must never pass through an agent" | Sentry and Vercel sources are added in the console, where you paste their secret |
| "Only an owner or admin of workspace … can do this" | Notification settings are for owners and admins, in the console and here alike |
| The browser reports an invalid scope when you allow voting | The app was connected before voting existed, and Mocco has not yet refreshed what it may ask for. It does within the hour; try again then |
| The browser opens Mocco's sign-in and then lands on your workspaces instead of the client | The page was opened without the client's request in its address. Start the connection again from the client |
| Tools from the wrong workspace | You belong to several. Ask the agent to switch workspace, or pin one in the client config |
