How it works, for the technically minded
MCP is the primary API, not a wrapper around a REST app.
Connect an assistant, then the tools, prompts, and errors it will see.
Connect
Create a space, paste the endpoint into the assistant, approve the grant, then ask what's on your plate.
- Create a space. Name it after the work, invite the people who do it, pick the statuses you use.
- Paste
https://mcp.cashew.tools/mcpinto the assistant's connector settings. Approve scopes, spaces, and expiry. - Ask “What's on my plate?”
Anything that speaks MCP over Streamable HTTP with OAuth connects the same way. Grants, expiry, and revoke are on Security.
Endpoint
- Specification
2026-07-28- Transport
- Stateless Streamable HTTP, POST only
- URL
https://mcp.cashew.tools/mcp- Discovery
server/discoveranswers before a token exists- Auth
- OAuth 2.1 with grants, not API keys. Passkeys first for people. How grants work.
A turn
whoamiget_workspace_maplist_inboxorsearch_tasksget_taskcreate_task,update_task,move_task, orcomment_on_task. Usebulk_create_tasksorbulk_update_taskswhen more than one.
Tools
Called via tools/call. Every mutating tool accepts an optional idempotencyKey.
Identity (identity:read)
| Tool | Input | Returns | Scope |
|---|---|---|---|
whoami | None. | Principal, impersonated user, org, client, scopes, spaces, grant expiry, and a cannot list. | identity:read |
list_members | None. | Members by name and role. | identity:read |
Read tasks (tasks:read)
| Tool | Input | Returns | Scope |
|---|---|---|---|
get_workspace_map | None. | Spaces, lists, and status names the grant can see. | tasks:read |
search_tasks | Optional query, spaceId, listId, status, assigneeId, cursor, and limit. | A page of tasks and a next cursor. | tasks:read |
get_task | taskId (ta_…). | The task with its subtasks, comments, and attachments. | tasks:read |
get_attachment | attachmentId (at_…). Optional format: auto, text, or url. | A small text file inline; anything else as a download URL, signed and short-lived where the bucket can sign one. | tasks:read |
view_task_detail | taskId (ta_…). | Backs the task view rather than the model: the task, plus the status names its list allows, the member roster, and whether the grant may write. Call get_task instead. | tasks:read |
list_inbox | Optional cursor and limit. | Open assigned tasks, excluding snoozed items, and a next cursor. | tasks:read |
Write tasks (tasks:write)
| Tool | Input | Returns | Scope |
|---|---|---|---|
create_task | listId and title. Optional description, status, assigneeId, priority (1 Urgent to 4 Low), and dueAt. | The task. | tasks:write |
update_task | taskId, plus any of title, description, status, assigneeId, priority (1 Urgent to 4 Low), dueAt, and snoozedUntil. | The task. | tasks:write |
move_task | taskId. Optional listId, status, position, beforeTaskId, and afterTaskId. | The task. | tasks:write |
create_subtasks | taskId and titles (one to fifty). | The subtasks. | tasks:write |
toggle_subtask | subtaskId. Optional done, to set rather than flip. | The subtask. | tasks:write |
comment_on_task | taskId and body. | The comment. | tasks:write |
delete_task | taskId. | The task id. Recoverable for 30 days. | tasks:write |
restore_task | taskId. | The task. | tasks:write |
delete_comment | commentId (cm_…). | The comment id. Recoverable for 30 days. | tasks:write |
restore_comment | commentId. | The comment. | tasks:write |
delete_attachment | attachmentId (at_…). | The attachment id. Recoverable for 30 days. | tasks:write |
restore_attachment | attachmentId. | The attachment. | tasks:write |
start_attachment_upload | taskId, filename, mimeType, and the exact size in bytes. | A signed POST valid for 15 minutes, a ready curl command, and a board link for a human to upload instead. | tasks:write |
finish_attachment_upload | taskId and the uploadId (up_…) from start_attachment_upload. | The attachment, named and sized from what arrived. | tasks:write |
attach_file | taskId, filename, mimeType, and either text or base64 (up to 256 KB). | The attachment. | tasks:write |
Bulk (tasks:bulk)
| Tool | Input | Returns | Scope |
|---|---|---|---|
bulk_create_tasks | items: one to fifty create payloads. | The tasks. | tasks:bulk |
bulk_update_tasks | items: one to fifty update payloads. | The tasks. | tasks:bulk |
Shape the workspace (spaces:write)
| Tool | Input | Returns | Scope |
|---|---|---|---|
create_space | name. Optional color and visibility (workspace or private). | The space, with its seeded list. | spaces:write |
update_space | spaceId, plus any of name, color, and visibility. | The space. | spaces:write |
archive_space | spaceId. | The space id. | spaces:write |
create_list | spaceId and name. | The list, with its Open and Done statuses. | spaces:write |
update_list | listId and name. | The list. | spaces:write |
archive_list | listId. | The list id. | spaces:write |
create_status | listId, name, and type (open or closed). Optional color. Open/custom land before closed. | The status. | spaces:write |
update_status | statusId, plus any of name, color, and type. | The status. | spaces:write |
reorder_statuses | listId and statusIds (every live status on the list, closed last). | The list id and statuses in the new order. | spaces:write |
delete_status | statusId. | The status id. Recoverable for 30 days. | spaces:write |
restore_status | statusId. | The status. | spaces:write |
Space access (members:write)
| Tool | Input | Returns | Scope |
|---|---|---|---|
add_space_member | spaceId and userId (us_…). | Everyone on the space. | members:write |
remove_space_member | spaceId and userId. | Everyone left on the space. | members:write |
take_over_space | spaceId. | Everyone on the space, now including you. | members:write |
Run the workspace (admin:write)
| Tool | Input | Returns | Scope |
|---|---|---|---|
list_invitations | None. | Pending invitations with their role and expiry. | admin:write |
invite_member | email and role (admin, member, or guest). | The invitation, and whether a live one was refreshed instead. The invitee is emailed either way. | admin:write |
cancel_invitation | invitationId. | The invitation id. | admin:write |
update_member_role | memberId (mb_…) and role. | The member. | admin:write |
list_webhooks | None. | Endpoints by id and URL. Never the secret. | admin:write |
add_webhook | url (https) and secret (16 to 256 characters). Optional events. | The endpoint, without its secret. | admin:write |
remove_webhook | webhookId. | The webhook id. | admin:write |
Audit (audit:read)
| Tool | Input | Returns | Scope |
|---|---|---|---|
get_audit_log | Optional entityType, entityId, cursor, and limit. | Audit rows the grant can see, and a next cursor. | audit:read |
Prompts
These are prompts/get templates, not executable work. The host fills them in and the model then calls tools.
| Prompt | Args | What it tells the model to do |
|---|---|---|
prioritize_inbox | None. | Call list_inbox, then get_task on anything blocked or due soon, and propose an order of attack. |
standup_summary | None. | Call list_inbox, group by status name, and summarise what is in flight, blocked, and due soon. |
Resources
Read-only documents, not tool calls. They return the same data as the matching tools.
| URI | Same as |
|---|---|
workspace://map | The same document get_workspace_map returns. |
task://{id} | The same document get_task returns. The id is the prefixed task id (ta_…). |
user://me | The same document whoami returns. |
ui://task/detail.html | The task panel get_task renders in a host that supports MCP Apps. HTML, not data. |
Errors
Tool errors include a code in the body. A dead grant is a 401 and never reaches a tool.
| Error | What to do |
|---|---|
403 insufficient_scope | Ask the human to approve the missing scopes. The challenge lists the complete set. Do not retry the same token. |
401 | The grant expired or was revoked. Ask the human to renew from Settings, under Agents. Nothing already created goes away. |
unknown_status | Use a status name from get_workspace_map, not an id. |
bulk_item_cap | Split the work. Fifty items per call. |