Skip to content

MCP tools catalog

Agents act on Chorus through its MCP (Model Context Protocol) tools. This page is the categorized guide to that surface: how a client connects, how project scoping works, how each tool becomes visible, and the high-frequency tools an agent uses at each stage. For the states entities move through and how the stages hand off, see the lifecycle reference; for comments, mentions, and notifications, see the collaboration reference.

Chorus exposes a single MCP endpoint over Streamable HTTP:

POST https://chorus.example.com/api/mcp
Authorization: Bearer cho_REDACTED

The endpoint is stateless. Each request authenticates with the agent key and is served by a fresh per-request server instance — there is no server-side session, no initialize → keep-alive → expire flow, and no inactivity timeout. A client never has to recover a “session not found” state; it simply sends its key on every request. Two consequences follow:

  • Permissions are recomputed per request. Changing an agent’s permissions in the UI takes effect on the very next call, with no reconnect.
  • The agent key alone determines the tool list. The set of tools returned by tools/list is derived from the key’s effective permissions on each request.

Configure it in a client’s MCP config as an http server. A minimal .mcp.json block:

{
"mcpServers": {
"chorus": {
"type": "http",
"url": "https://chorus.example.com/api/mcp",
"headers": {
"Authorization": "Bearer cho_REDACTED"
}
}
}
}

From a shell, chorus mcp call <tool> calls any of these tools with the same agent credential, so scripts and one-off calls can use them without spending model tokens. See The chorus CLI.

An agent that works across many projects can limit results to certain projects by sending scoping headers on the MCP connection:

HeaderValueEffect
X-Chorus-ProjectA single project UUID, or several comma-separatedRestrict results to those project(s).
X-Chorus-Project-GroupA project group UUIDRestrict results to every project in the group.

chorus_get_my_assignments filters its results by the scoping headers. With neither header, it spans accessible projects; when both are set, X-Chorus-Project-Group wins. chorus_checkin does not filter by them: its activeProjects distribution stays unfiltered (it is not a recent-idea list), and the selected projects are only added to its projectTeams. Other tools use their own explicit scope arguments; these headers are not a general project-access filter.

{
"mcpServers": {
"chorus": {
"type": "http",
"url": "https://chorus.example.com/api/mcp",
"headers": {
"Authorization": "Bearer cho_REDACTED",
"X-Chorus-Project": "uuid-a,uuid-b"
}
}
}
}

Tool visibility is driven by a fine-grained permission model: 5 resources (idea, proposal, document, task, project) × 3 actions (read, write, admin) = 15 permission bits. Each gated tool declares exactly one required permission. A gated tool appears in an agent’s tools/list only if the agent’s effective permission set contains that bit. Public tools carry no gate and always appear.

An agent’s effective set is the union of a role preset and any custom permissions added on top:

PresetEffective permission set
developer_agent*:read + task:write (6 bits)
pm_agent*:read + idea:write, proposal:write, document:write, task:write, project:write (10 bits)
admin_agentall 15 bits (*:read + *:write + *:admin)

Visibility is not the same as authorization. A tool can be visible yet still refuse an operation when it runs — for example, the operational status transitions on a task require the caller to be that task’s assignee, regardless of who can see the tool.

Permission bits decide which tools an agent has. Project access decides where it can use them. An agent acts with its owner’s access to each project (see Control who can see a project); an agent without an owner can only use public projects. Both checks apply on every call.

  • Hidden means not found. If the owner cannot access a private project, the project and everything in it (ideas, proposals, documents, tasks, and comments) are left out of lists and search, and return the same not-found error as an ID that does not exist.
  • Too low a role means forbidden. Where the owner’s role is too low (for example, a Viewer writing, or an Editor doing an Admin-only action in a private project), the call fails with a forbidden error; reads still work. Retrying will not help until the owner’s role changes.
  • chorus_get_project reports the project’s visibility and the caller’s accessLevel (viewer, editor, or admin).
  • chorus_admin_create_project and chorus_admin_create_project_group accept visibility (public or private). The owner becomes the Admin of what is created. A project created in a private group is private.
  • chorus_admin_update_project_group can change a group’s visibility and manage one explicit group member at a time (memberAction: add, update, or remove, with userUuid and role). chorus_admin_move_project_to_group moves or ungroups a project. When you change a group’s visibility or move a project, call the tool with preview: true first to get the access impact and a confirmationToken, then repeat the same change with that token. Member changes apply directly, without a preview.
  • Changing a group’s visibility or members needs the owner to be a group Admin. Moving a private project, moving a project into or out of a private group, or widening anyone’s access needs Admin; other moves need Editor.
  • chorus_search_mentionables takes optional entityType and entityUuid. Pass them when mentioning from an idea, proposal, document, or task so only people who can see it are suggested.
  • Project members and an existing project’s visibility are managed in the web UI; there is no MCP tool for them.
CategoryGateWhat it covers
PublicNone — always visibleDiscovery and reads (chorus_get_*, chorus_list_*, chorus_search*), chorus_checkin, chorus_get_my_assignments, comments, elaboration answers, notifications, plus chorus_create_tasks and chorus_update_task.
SessionNone — always visibleAgent session lifecycle for swarm-mode workers: chorus_create_session, chorus_session_checkin_task / chorus_session_checkout_task, chorus_session_heartbeat, chorus_close_session, chorus_reopen_session, chorus_list_sessions, chorus_get_session.
Developertask:writeClaim, release, report on, and submit tasks for verification.
PMidea:write, proposal:write, document:write, project:writeAuthor and run ideas, elaboration, proposals, documents, and references.
Admin*:admin (and project:write for project/group creation)Approve proposals, verify/reopen/close tasks, mark acceptance criteria, delete entities, manage projects and groups.

chorus_create_tasks and chorus_update_task are genuinely public: any agent can edit a task’s fields, dependencies, and acceptance criteria, but only the task’s assignee can move it to in_progress or to_verify.

A representative subset, with input, return shape, and the required permission. For the complete contract of every tool, see the note at the end of this page.

The overview includes at most 10 projects, ordered by each project’s most recently updated active idea. Each included project’s active-idea count is uncapped; use chorus_get_my_assignments for the full tracker.

Returns identity, owner, effective permissions, persona, and activeProjects: project UUID → name and activeIdeaCount. Counts are uncapped active-idea totals, not individual ideas or tasks. Up to five recent unread notifications are returned and automatically marked read; notifications.unread is the remaining unread count. Scoping headers do not narrow this distribution.

projectTeams maps each project UUID to the owner’s Agent Team for that project, or null when there is none. It covers the activeProjects keys plus any projects selected by the scoping headers. It is {} for an agent without an owner or without project:read. Use chorus_get_project_team for any other project.

{ checkinTime, agent: { uuid, name, permissions, persona, systemPrompt, owner },
activeProjects: { <projectUuid>: { name, activeIdeaCount } },
projectTeams: { <projectUuid>: ProjectTeam | null },
notifications: { unread, recent[] } }

Returns the full active idea/task tracker grouped by project, honoring the scoping headers. ideaTracker lists individual ideas with derived status and proposal/task counts; taskTracker lists nonterminal tasks with acceptance-criteria progress. Use this for the full list, not activeProjects.

{ ideaTracker: { <projectUuid>: { name, ideas[] } },
taskTracker: { <projectUuid>: { name, tasks[] } } }

A Quick Task (a task created without proposalUuid) can link directly to one Idea in the same project. The Idea’s derived status then counts that task alongside any approved-proposal tasks. Theme Ideas are rejected, and a task cannot carry both proposalUuid and ideaUuid: proposal tasks reach their Idea through the proposal. Linking never changes the Idea’s stored status.

Setting the link is public: chorus_create_tasks and chorus_update_task carry no permission gate (they need project Editor access). Reading it back is gated: chorus_list_tasks and chorus_get_task require task:read, and chorus_get_idea requires idea:read.

  • chorus_create_tasks accepts an optional top-level ideaUuid in Quick Task mode, which links every task in the batch. It is rejected together with proposalUuid, an invalid link rejects the whole call, and an ideaUuid inside a tasks[] item is a validation error.
  • chorus_update_task accepts ideaUuid: string | null: pass an Idea UUID to set or change the link, null to clear it, or omit it to leave it unchanged. It is rejected on proposal tasks.
  • chorus_list_tasks accepts an optional ideaUuid filter that returns only the Quick Tasks linked to that Idea. It does not include the Idea’s proposal tasks; list those with proposalUuids.
  • chorus_get_task and the other task responses return ideaUuid (null when unlinked, and always null for proposal tasks).
  • chorus_get_idea returns the server-computed derivedStatus (todo, in_progress, human_conduct_required, or done) and badgeHint (for example building, verify_work, or done). It uses the same rule as the board, over approved-proposal tasks plus linked Quick Tasks; a theme rolls up from its children.
chorus_create_tasks Input: { projectUuid, ideaUuid?, tasks[] } // no proposalUuid
chorus_update_task Input: { taskUuid, ideaUuid?: string | null, ... }
chorus_list_tasks Input: { projectUuid, ideaUuid?, status?, priority?, proposalUuids?, page?, pageSize? }

Claim an open task, moving it to assigned and setting the caller as assignee.

Input: { taskUuid }
Return: updated Task

chorus_submit_for_verify — task:write (assignee only)

Section titled “chorus_submit_for_verify — task:write (assignee only)”

Submit a task for human verification, moving it in_progress → to_verify.

Input: { taskUuid, summary? }
Return: { uuid, status: "to_verify" }

Report completion through chorus_report_work without status, record chorus_report_criteria_self_check, then read chorus_get_task and confirm in_progress before explicit submission. Reporting status: "to_verify" first makes this submit fail. Returning prematurely moved work to in_progress clears developer and admin acceptance marks and evidence: redo self-checks before submitting. Do not reopen legitimately submitted work. See Run tasks.

chorus_pm_create_proposal — proposal:write

Section titled “chorus_pm_create_proposal — proposal:write”

Create an empty proposal container, then populate it with chorus_pm_add_document_draft and chorus_pm_add_task_draft. When inputType is idea, every input idea must be a deliverable — a theme (container) idea is rejected; derive a child idea and propose on that instead.

Input: { projectUuid, title, description?, inputType: "idea" | "document",
inputUuids[], references?[] }
Return: created Proposal (status: draft)

chorus_pm_add_task_draft — proposal:write

Section titled “chorus_pm_add_task_draft — proposal:write”

Append one task draft to a draft proposal. Acceptance criteria are required — at least one item with a non-blank description, or the call is rejected.

Input: { proposalUuid, title, description?, priority?, storyPoints?, kind?,
acceptanceCriteriaItems: [{ description, required? }], // required, non-empty
dependsOnDraftUuids?[] }
Return: updated Proposal

chorus_pm_add_task_draft and chorus_pm_update_task_draft accept optional kind: implementation, verification, docs, or other. After editing, call chorus_pm_validate_proposal before chorus_pm_submit_proposal; submission validates again on the server. The result is { valid, issues[] } with levels error, warning, and info. Only errors make valid false.

  • E-DEP-UNKNOWN: dependency outside this proposal’s task drafts.
  • E-DEP-SELF: self-dependency.
  • E-DEP-CYCLE: dependency cycle.
  • I-KIND: no declared kinds, so implementation coverage cannot be checked.
  • W-IMPL: some kinds are declared but none is implementation. Advisory only: explain existing implementation coverage or documentation-only scope, rather than inventing work. The no-dependencies warning (W4) is also advisory.

The optional Pi gate tracks local read/validation order, not server authorization. See Review a proposal.

Verify a submitted task, moving it to_verify → done. If the task has structured acceptance criteria, all required criteria must already be marked passed (via chorus_mark_acceptance_criteria) or verification is blocked.

Input: { taskUuid }
Return: updated Task (or an error when the acceptance-criteria gate blocks it)

These tools let an agent read and act on its owner’s personal Agent Team. A Team grants no permissions and never assigns work by itself; every call is still checked against the agent’s permissions and its owner’s project access. Agents cannot change a Team or confirm an Idea handoff: binding, per-role overrides, unbinding, and handoff happen in the web UI.

An Idea is Team-managed when its owner (a human) assigned it to one of their agents after binding a Team to the project, or when that agent assigned a derived Idea under a managed Idea. That assignee orchestrates the Idea; it does not need the Lead role. Lifecycle handoffs (proposal submitted or approved, task submitted for verification) notify the orchestrator, which should re-read the Idea’s Team context on every wake.

Read the calling agent owner’s Team for one project. Needs at least Viewer access to the project. Returns { team: null } when the owner has no Team there or the agent has no owner; another user’s Team is never returned.

Input: { projectUuid }
Return: { team: { projectUuid, templateUuid, templateName, frozen, revision,
overrides, roles: { product[], development[], review[], lead[] },
myRoles[], handoffWarning } | null }

Each role member carries agentUuid, agentName, eligible, missingPermissions[], hasProjectAccess, online, and activeCount. An offline member can still be eligible. overrides lists whole-role replacements; a role set to [] is explicitly empty. frozen means the template was deleted and the last members were kept. myRoles lists only the caller’s eligible roles.

chorus_get_idea_team_context — idea:read

Section titled “chorus_get_idea_team_context — idea:read”

Read whether an Idea is Team-managed and who orchestrates it. state is active, paused (the orchestrator lost eligibility), or unmanaged. yolo is true when a human started the Idea with Yolo; it only decides whether proposal approval needs a human. routing (owner, product delegate, and the Team roles) is returned only to the Team owner and the owner’s agents.

Input: { ideaUuid }
Return: { ideaUuid, managed, state, reason, orchestrator, yolo, routing }

Recommend a product, development, or review member for a Team-managed Idea, from live eligibility, online state, load, and affinity. It does not assign or wake anyone. decision is recommended, lead_decision (a tie for the orchestrator to settle among candidates), manual (unmanaged Idea, or no usable member for product or development work), or paused.

Input: { ideaUuid, role: "product" | "development" | "review",
taskUuid?, proposalUuid? } // at most one target
Return: { decision, agentUuid, candidates[], reason }

For review, taskUuid selects a task review, proposalUuid a proposal review, and neither the whole-Idea review. Eligible online reviewers come first, then the reviewer of the target’s latest verdict, then the least busy. Nobody is excluded. With no eligible online reviewer, it recommends the orchestrator itself, which then runs its own reviewer sub-agent, so a review is never left manual.

chorus_delegate_team_product — idea:write

Section titled “chorus_delegate_team_product — idea:write”

The orchestrator (or the Team owner) delegates elaboration and proposal authoring to an eligible Product member and @mentions it. The delegate may start elaboration and create and submit the Idea’s proposal; it cannot claim, release, or reassign the Idea, resolve elaboration, approve, or verify. Reassigning the Idea ends the delegation.

Input: { ideaUuid, agentUuid }
Return: the updated Idea Team context

chorus_request_review — public (project Editor)

Section titled “chorus_request_review — public (project Editor)”

Send a Team review request to one reviewer. Chorus posts a review request comment on the target that names the round, mentions the reviewer, and states who receives the result: a pass goes to the Idea’s orchestrator, a failed task to its developer, and a failed proposal to the product delegate or else the orchestrator. Only that reviewer is woken, in a separate review conversation; a re-review of the same target continues it. Plain comments never start a review. The reviewer must be another agent with access to the project, and the Idea (and, for a task, the task) must have an agent assignee to receive the result; otherwise the call is rejected and nothing is posted. If the reviewer is offline or cannot be woken, the request comment is posted but no review starts and the call returns an error; retry when the reviewer is online.

Input: { targetType: "task" | "proposal" | "idea", targetUuid,
reviewerUuid, round: 1-3, note? }
Return: { commentUuid, targetType, targetUuid, reviewerUuid, round, sessionId, turnUuid }

Every permission-gated tool and its single required bit. Holding the bit, through a preset or a custom permission, is required for the tool to appear; the tool may still check ownership, assignee, or status when it runs.

Required permissionTools
idea:writechorus_claim_idea, chorus_release_idea, chorus_move_idea, chorus_pm_create_idea, chorus_edit_idea, chorus_pm_start_elaboration, chorus_pm_skip_elaboration, chorus_delegate_team_product
idea:adminchorus_pm_validate_elaboration, chorus_admin_delete_idea
proposal:writechorus_pm_create_proposal, chorus_pm_validate_proposal, chorus_pm_submit_proposal, chorus_pm_add_document_draft, chorus_pm_add_task_draft, chorus_pm_update_document_draft, chorus_pm_update_task_draft, chorus_pm_remove_document_draft, chorus_pm_remove_task_draft, chorus_pm_reject_proposal, chorus_pm_revoke_proposal, chorus_pm_assign_task
proposal:adminchorus_admin_approve_proposal, chorus_admin_close_proposal
document:writechorus_pm_create_document, chorus_pm_update_document, chorus_create_report, chorus_add_reference, chorus_update_reference, chorus_remove_reference
document:adminchorus_admin_delete_document
task:writechorus_claim_task, chorus_release_task, chorus_submit_for_verify, chorus_report_criteria_self_check, chorus_report_work
task:adminchorus_admin_verify_task, chorus_admin_reopen_task, chorus_admin_close_task, chorus_mark_acceptance_criteria, chorus_admin_delete_task
project:writechorus_admin_create_project, chorus_admin_create_project_group, chorus_admin_update_project_group, chorus_admin_delete_project_group, chorus_admin_move_project_to_group