Skip to main content

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) or tmo_… (OAuth access token). Each tool declares a scope class — read, write, or admin — checked before the handler runs; a violation returns a structured FORBIDDEN envelope, never a bare error.
  • The error envelope. Failures return isError: true with { error: { code, message, hint } } where codeFORBIDDEN | NOT_FOUND | INVALID_INPUT | RATE_LIMITED | CONFLICT | INTERNAL. Rate-limited calls still authenticate and include retryAfterSeconds.
  • Idempotency. Every create_* and bulk_* tool takes an optional idempotencyKey: the same key with the same arguments replays the stored response; the same key with different arguments is CONFLICT.
  • Optimistic concurrency. Every update_* tool and move_task take an optional expectedUpdatedAt; a mismatch returns CONFLICT embedding the entity's current state under error.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-validated structuredContent; dates are ISO strings; paginated lists return totalCount plus a notice when 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).

ToolScopeRead-onlyDestructiveIdempotentWhat it does
add_project_linkwriteLink 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_linkwriteLink 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_sessionwriteJentrix 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_boardadminArchive 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_taskwriteArchive a task (soft delete — it disappears from the board but is recoverable).
attach_agent_sessionwriteBind 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_artifactwriteAttach 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_taskswriteCreate 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_taskswriteMove 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_taskswriteUpdate 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_sessionwriteClose 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_sessionwriteCreate 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_boardwriteCreate a board in a workspace with the default columns for its kind (TASKS/CRM/SUPPORT/BUGS/ROADMAP, default TASKS).
create_commentwriteAdd a comment to a task (markdown body, max 20k chars).
create_projectwriteCreate a project (the container that links boards/tasks/repos/decisions, with owner/constraints/milestones/risks). Admin-gated.
create_subtaskwriteAdd a subtask (checklist item) to a task.
create_taskwriteCreate a new task in a column. Returns the new task's ID, per-workspace number, and human-readable key (e.g. STK-42).
create_workspacewriteCreate 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_commentwriteDelete a comment permanently. Only the comment's author can delete it.
delete_subtaskwriteDelete a subtask permanently.
get_agent_sessionreadFetch 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_artifactreadGet 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_snapshotreadTHE 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_projectreadFetch a project with its owner, links, milestones, risks, and counts. Accepts projectId, or workspaceId + slug.
get_taskreadFetch 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_contextreadReport 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_memberadminInvite 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_activityreadList 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_sessionsreadList 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_artifactsreadList 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_attachmentsreadList a task's attachments with short-lived signed download URLs (~5 min). Uploads are UI-only.
list_boardsreadList boards in a workspace.
list_columnsreadList columns of a board, ordered by position. Columns represent statuses on the kanban board.
list_commentsreadList a task's comments oldest-first, with authors.
list_invitationsadminList 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_labelsreadList labels available on a board.
list_membersreadList members of a workspace. Use the userId field when assigning tasks.
list_projectsreadList 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_linksreadList a task's outgoing and incoming links with the linked tasks' keys, titles, and boards.
list_tasksreadList 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_workspacesreadList workspaces the authenticated user belongs to, with their role.
manage_columnswriteCreate, 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_labelswriteCreate, 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_taskwriteMove 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_memberadminRemove 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_linkwriteRemove 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_linkwriteRemove a task link (exact fromTaskId + toTaskId + kind match). No-op if the edge does not exist.
rename_boardwriteRename a board.
resolve_projects_for_reporeadResolve 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_sessionwriteReopen 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_invitationadminRevoke a pending workspace invitation (admin scope + ADMIN role). Discover the invitationId via list_invitations.
search_artifactsreadSearch 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_tasksreadSearch 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_roleadminChange 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_assigneeswriteSet the full list of assignees on a task. REPLACES existing assignees. All user IDs must be members of the task's workspace.
set_task_labelswriteSet 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_subtaskwriteMark a subtask complete or incomplete.
unarchive_boardsadminRestore one to 50 boards in a workspace atomically. Requires workspace admin access; already-active boards are idempotent no-ops.
update_commentwriteEdit a comment's body. Only the comment's author can edit it.
update_projectwriteUpdate 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_taskwriteUpdate fields on an existing task. Only provided fields are changed.
update_workspaceadminRename 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.