MCP tool reference — product surface
This is the product MCP catalog: every tool the Jentrix MVP deployment
serves at https://stacks-mvp.vercel.app/api/mcp, and the same-named subset
every full deployment serves identically. The catalog's authority is
src/lib/mcp/tools-product.ts; the table below is generated from its live
registration (pnpm gen:tool-registry), so this page cannot drift from the
surface.
Connecting a client — PATs, OAuth sign-in, and per-client setup for Claude Code, claude.ai, Codex, and Cursor — is covered in Agent setup variants. The full platform catalog (harness, delivery, evals, and the other agent-operations planes) is documented in Agent platform (MCP) and served only by full deployments.
The shared contract
Every tool in the catalog follows the same rules:
- Bearer auth + scopes.
Authorization: Bearer tm_…(PAT) ortmo_…(OAuth access token). Each tool declares a scope class —read,write, oradmin— checked before the handler runs; a violation returns a structuredFORBIDDENenvelope, never a bare error. - The error envelope. Failures return
isError: truewith{ error: { code, message, hint } }wherecode∈FORBIDDEN | NOT_FOUND | INVALID_INPUT | RATE_LIMITED | CONFLICT | INTERNAL. Rate-limited calls still authenticate and includeretryAfterSeconds. - Idempotency. Every
create_*andbulk_*tool takes an optionalidempotencyKey: the same key with the same arguments replays the stored response; the same key with different arguments isCONFLICT. - Optimistic concurrency. Every
update_*tool andmove_tasktake an optionalexpectedUpdatedAt; a mismatch returnsCONFLICTembedding the entity's current state undererror.current, so a client merges without an extra read. - Results. Every result is an object (lists are wrapped, e.g.
{ boards: [...] }) with compact-JSON text plus schema-validatedstructuredContent; dates are ISO strings; paginated lists returntotalCountplus anoticewhen truncated.
Reconnect caveat. MCP clients cache the tool list at connect time: a tool added to — or changed on — the server is invisible to an already-connected client. After a deployment that changes the surface, reconnect before relying on new tools (claude.ai: disconnect and reconnect the connector; Claude Code: restart the session or reconnect the server; Codex: restart the session).
Catalog
62 tools — the product catalog registered by src/lib/mcp/tools-product.ts, generated from its live registration and pinned by tests/mcp/tool-registry-docs.test.ts. Every tool is definition-identical to its platform twin (tests/mcp/product-surface.test.ts).
| Tool | Scope | Read-only | Destructive | Idempotent | What it does |
|---|---|---|---|---|---|
add_project_link | write | – | – | ✓ | Link a project to a board, task, repo, doc, decision, metric, or agent. For connected sessions, a REPO link uses the normalized lowercase "owner/name" as targetId (a GitHub URL is accepted and normalized) — the link that satisfies the session repo gate. Adding an edge that already exists is a no-op. Needs the workspace ADMIN role. |
add_task_link | write | – | – | ✓ | Link two tasks of ANY board kind in the same workspace (cross-board allowed), e.g. a bug that BLOCKS a deal. Kinds: BLOCKS, DEPENDS_ON, RELATES_TO, DUPLICATES. Rejects BLOCKS/DEPENDS_ON edges that would create a cycle — the error names the cycle path by task key. Adding an edge that already exists is a no-op. |
align_agent_session | write | – | – | ✓ | Jentrix MVP: anchor an OPEN session to a work item + accountable owner after the operator confirmed the wizard's choices. The server builds the alignment snapshot (ids + display names), stores it on the session, and returns it — echo it VERBATIM to the operator. Re-aligning replaces the anchor and writes a visible activity row, never silently. The session's project/workspace are immutable — a different project means a new session. Requires expectedUpdatedAt (CAS). taskId null = "no task — session-level work". |
archive_board | admin | – | ✓ | – | Archive a board (admin scope + board ADMIN) — the inverse of unarchive_boards. Soft delete: the board and its tasks are retained and unarchive_boards reverses it. |
archive_task | write | – | ✓ | – | Archive a task (soft delete — it disappears from the board but is recoverable). |
attach_agent_session | write | – | – | – | Bind a TRUSTED current provider session/thread id (from provider lifecycle hooks or app-server context — never model-authored text) to a Jentrix session. With sessionId: late-binds a CLI-started session's provider thread (CAS). Without: attach-creates an ACTIVE session for the current provider thread; repeating with the same tuple converges on the existing session. A competing active binding fails SESSION_ALREADY_BOUND. Requires idempotencyKey. |
attach_artifact | write | – | – | – | Attach a first-class artifact (PR/diff/log/screenshot/eval report/run summary/…) linked to a task/project/run/decision/Work Order. EXTERNAL_URL storage takes a url; R2_OBJECT storage requires an uploadGrantId from POST /api/artifacts/upload-grant (REST, same bearer) after PUTting the bytes to its presigned uploadUrl — jentrix artifact upload <file> runs that whole flow. Returns the stored artifact record. |
bulk_create_tasks | write | – | – | – | Create up to 50 tasks in one column in a single transaction (all-or-nothing). Returns each new task's id, number, and key in input order. |
bulk_move_tasks | write | – | – | – | Move up to 50 tasks to new columns at once (each appended to the end of its destination, in input order). Access is checked per task; valid moves apply in one transaction with per-item results. |
bulk_update_tasks | write | – | – | ✓ | Update up to 50 tasks at once. Access is checked per task; valid updates apply in one transaction and the per-item result array reports any failures so you can retry just those. |
complete_agent_session | write | – | – | ✓ | Close a session with an honest lifecycle outcome (COMPLETED normal end / INTERRUPTED crash / CANCELLED pre-first-turn abort). The server verifies the trace-part manifest against durable artifacts, stores the deterministic RUN_SUMMARY, and sets captureComplete ONLY when every expected part and the summary are acknowledged — lifecycle and capture integrity stay orthogonal. Requires expectedUpdatedAt (CAS). |
create_agent_session | write | – | – | – | Create a STARTING connected session BEFORE provider launch: validates operator membership, project visibility, and that the project links the checkout repository (refused otherwise — no model is invoked). The project determines and locks the workspace. Requires idempotencyKey (the CLI launch nonce). |
create_board | write | – | – | – | Create a board in a workspace with the default columns for its kind (TASKS/CRM/SUPPORT/BUGS/ROADMAP, default TASKS). |
create_comment | write | – | – | – | Add a comment to a task (markdown body, max 20k chars). |
create_project | write | – | – | – | Create a project (the container that links boards/tasks/repos/decisions, with owner/constraints/milestones/risks). Admin-gated. |
create_subtask | write | – | – | – | Add a subtask (checklist item) to a task. |
create_task | write | – | – | – | Create a new task in a column. Returns the new task's ID, per-workspace number, and human-readable key (e.g. STK-42). |
create_workspace | write | – | – | – | Create a new workspace and become its OWNER (write scope). REFUSED for a workspace-pinned token — a token scoped to one workspace cannot mint another (checked before any write). The name derives a unique slug and a task-key prefix, both write-once. Workspace DELETE stays UI-only. |
delete_comment | write | – | ✓ | – | Delete a comment permanently. Only the comment's author can delete it. |
delete_subtask | write | – | ✓ | – | Delete a subtask permanently. |
get_agent_session | read | ✓ | – | – | Fetch one connected session: lifecycle status, capture integrity (orthogonal to status), repository start/end state, linked summary/transcript artifacts, the stable usage object (provider-reported tokens or null — never estimated), and the append-only task-alignment interval history (alignments[], ordinal-ascending; the session's taskId mirrors the open interval). |
get_artifact | read | ✓ | – | – | Get one artifact record plus a short-lived signed downloadUrl (internal R2 objects; provenance-gated) or the external URL — the tool-surface twin of the stacks://artifact/{id} resource, for clients that only call tools. Redacted artifacts resolve to a tombstone with no URL. |
get_board_snapshot | read | ✓ | – | – | THE orientation tool: board info + columns + concise task rows in one call. Use this first instead of list_boards → list_columns → list_tasks. Capped at 500 tasks (notice explains how to page the rest). |
get_project | read | ✓ | – | – | Fetch a project with its owner, links, milestones, risks, and counts. Accepts projectId, or workspaceId + slug. |
get_task | read | ✓ | – | – | Fetch full details of a task including description, labels, assignees, subtasks, links, and recent activity. Accepts taskId, or workspaceId + number (the numeric part of a task key like STK-42). Pass response_format: 'concise' for scalars + counts only. |
get_token_context | read | ✓ | – | – | Report THIS token's context (read scope) so an agent fails fast on scope instead of probing with FORBIDDEN calls: effective + raw stored scopes (empty stored = grandfathered full access until rotated), workspace pinning, displayName/emoji identity, expiry, and the per-minute rate-limit window (limit / used / remaining / reset). NO bearer material is ever returned. |
invite_member | admin | – | – | – | Invite a member to a workspace by email (admin scope; ADMIN role, but an OWNER-role invite requires the OWNER role). The default membership-governance pack parks this behind REQUIRE_APPROVAL, so an agent-alone call surfaces as a human-approvable request; an approved binding lets it through. Acceptance stays with the invitee. |
list_activity | read | ✓ | – | – | List the activity log for a task or a whole board, newest first. Filter by since (ISO timestamp), source ('ui' = humans, 'mcp' = agents), or activity type — e.g. diff what humans did since your last run. |
list_agent_sessions | read | ✓ | – | – | List connected sessions in a workspace, filterable by project, operator, provider, lifecycle status, and captureComplete (the two dimensions are independent). Paginated; provider thread ids are omitted from list output. |
list_artifacts | read | ✓ | – | – | List first-class artifacts (PR/diff/log/screenshot/eval report/run summary/…) in a workspace, filterable by project/task/run/workOrder/session/type/creator. Internal (R2) artifacts expose hasObject; get_artifact returns the signed download URL. Redacted artifacts remain as tombstones. |
list_attachments | read | ✓ | – | – | List a task's attachments with short-lived signed download URLs (~5 min). Uploads are UI-only. |
list_boards | read | ✓ | – | – | List boards in a workspace. |
list_columns | read | ✓ | – | – | List columns of a board, ordered by position. Columns represent statuses on the kanban board. |
list_comments | read | ✓ | – | – | List a task's comments oldest-first, with authors. |
list_invitations | admin | ✓ | – | – | List a workspace's pending (unaccepted) invitations (admin scope + ADMIN role): id, email, role, inviter, created/expiry. The invite token is never returned. Use the id with revoke_invitation. |
list_labels | read | ✓ | – | – | List labels available on a board. |
list_members | read | ✓ | – | – | List members of a workspace. Use the userId field when assigning tasks. |
list_projects | read | ✓ | – | – | List projects in a workspace with owner, status, and child/link/milestone/risk/decision counts. Filter by status, owner, or parent project. Paginated; pass nextCursor from the previous response to continue. |
list_task_links | read | ✓ | – | – | List a task's outgoing and incoming links with the linked tasks' keys, titles, and boards. |
list_tasks | read | ✓ | – | – | List tasks in a board or column with board/column names, total count, and pagination. Concise by default — pass response_format: 'detailed' for sidecars/labels/assignees. At least one of boardId or columnId is required. |
list_workspaces | read | ✓ | – | – | List workspaces the authenticated user belongs to, with their role. |
manage_columns | write | – | ✓ | – | Create, rename, move, or archive a board column (action: 'create' | 'rename' | 'move' | 'archive'). create needs boardId+name; rename needs columnId+name; move needs columnId + beforeColumnId/afterColumnId; archive needs columnId (tasks in it disappear from the board with it). |
manage_labels | write | – | ✓ | – | Create, update, or delete a board label (action: 'create' | 'update' | 'delete'). create needs boardId+name+color; update needs labelId and name and/or color; delete needs labelId. Creating an existing name returns the existing label. Use set_task_labels to apply labels to tasks. |
move_task | write | – | – | – | Move a task to a different column (= change status on the kanban board) and/or reorder it. Use beforeTaskId/afterTaskId for placement; omit both to append to the end. |
remove_member | admin | – | ✓ | – | Remove a member from a workspace (admin scope + ADMIN role). You cannot remove YOURSELF, and the last OWNER cannot be removed. Governed by the membership pack (REQUIRE_APPROVAL by default). Concurrency is VALUE-CAS: pass expectedRole; expectedUpdatedAt is refused (M19.2). A value-CAS mismatch returns CONFLICT embedding the current role. |
remove_project_link | write | – | – | ✓ | Remove a project link (exact projectId + targetType + targetId match). Removing a link that does not exist is a no-op. Needs the workspace ADMIN role. |
remove_task_link | write | – | – | ✓ | Remove a task link (exact fromTaskId + toTaskId + kind match). No-op if the edge does not exist. |
rename_board | write | – | – | ✓ | Rename a board. |
resolve_projects_for_repo | read | ✓ | – | – | Resolve non-archived projects across every workspace the caller belongs to whose linked repository matches a normalized "owner/name". Used by connected-session setup to narrow project choices from the checkout; requires an unpinned human credential (workspace-pinned tokens are refused). |
resume_agent_session | write | – | – | ✓ | Reopen an eligible INTERRUPTED session (original operator or workspace admin; same project and repository — continuity failures are SESSION_RESUME_CONFLICT). Requires expectedUpdatedAt (CAS). A deliberate new work period should instead create a new session with continuesSessionId. |
revoke_invitation | admin | – | ✓ | – | Revoke a pending workspace invitation (admin scope + ADMIN role). Discover the invitationId via list_invitations. |
search_artifacts | read | ✓ | – | – | Search the BODIES of typed artifacts (plan/decision/findings/report/diff/deliverable/learning/prompt/goal/prd) workspace-wide — full-text, websearch syntax (words, quoted phrases, -negation). This is how a LEARNING or a FINDINGS write-up is found again by what it says rather than by a title someone remembers. The index is built from the REDACTED stored text, so a secret redacted at ingest was never indexed. Archived and redacted artifacts are excluded; raw TRACE transcript parts are not searchable. Fetch a hit's content with get_artifact. |
search_tasks | read | ✓ | – | – | Search tasks workspace-wide across all boards: exact task key (for example STK-42), full-text (websearch syntax — words, quoted phrases, -negation) over title/description/comments, plus case-insensitive substring on title/description. Exact key hits rank first. Returns concise rows with board/column names. Archived tasks excluded. |
set_member_role | admin | – | – | ✓ | Change a member's role (admin scope; the op requires the OWNER role, and the last owner cannot be demoted). Governed by the membership pack (REQUIRE_APPROVAL by default). Concurrency is VALUE-CAS: pass expectedRole (the role you last read); expectedUpdatedAt is refused (M19.2). A value-CAS mismatch returns CONFLICT embedding the current role. |
set_task_assignees | write | – | – | ✓ | Set the full list of assignees on a task. REPLACES existing assignees. All user IDs must be members of the task's workspace. |
set_task_labels | write | – | – | ✓ | Set the full list of labels on a task. REPLACES existing labels; pass current+new to add, pass current-removed to delete. All label IDs must belong to the task's board. |
toggle_subtask | write | – | – | ✓ | Mark a subtask complete or incomplete. |
unarchive_boards | admin | – | – | ✓ | Restore one to 50 boards in a workspace atomically. Requires workspace admin access; already-active boards are idempotent no-ops. |
update_comment | write | – | – | ✓ | Edit a comment's body. Only the comment's author can edit it. |
update_project | write | – | – | ✓ | Update fields on an existing project (name, status, owner, parent, goal statement, constraints, budget, success metrics). Only provided fields are changed; pass null to clear a nullable field. Needs the workspace ADMIN role. Pass expectedUpdatedAt (from your last read) for optimistic concurrency — a mismatch returns CONFLICT embedding the current state. |
update_task | write | – | – | ✓ | Update fields on an existing task. Only provided fields are changed. |
update_workspace | admin | – | – | ✓ | Rename a workspace and/or set its connected-session default repository (admin scope + ADMIN role). defaultRepo takes a normalized "owner/name" (lowercased at the write boundary; null clears it) — sessions fall back to it only when no project in the workspace carries an explicit REPO link. slug and taskPrefix are WRITE-ONCE — passing either is refused with INVALID_INPUT. Rename concurrency is VALUE-CAS, not timestamp CAS: pass expectedName (the name you last read); expectedUpdatedAt is refused (workspaces carry no updatedAt — M19.2). A value-CAS mismatch returns CONFLICT embedding the current state under error.current. |