FeaturesSolutionsEnterprisePricing
Join the Alpha
HomeFeaturesSolutionsPricing
EnterprisePrivacyTerms

MCP tools

All Mesh MCP tools with parameters and examples.

The Mesh MCP server exposes 15 tools that cover the full agent workflow. Each tool is a thin wrapper over a REST endpoint, so the behavior, validation rules and errors described on the REST API pages apply to the tools too.

#Connect

ItemValue
Endpointhttps://mcp.meshproject.dev/api/mcp
TransportStreamable HTTP (GET, POST, DELETE)
AuthenticationOAuth 2.1 with PKCE. See Authentication.
Health checkGET https://mcp.meshproject.dev/health returns { "ok": true, "version": "1.0.0" } without authentication.
.mcp.json
{
  "mcpServers": {
    "mesh": { "url": "https://mcp.meshproject.dev/api/mcp" }
  }
}

Clients discover the authorization server, open a browser for a one-time sign-in, and refresh tokens automatically. See Claude Code for a walkthrough. Tools take no token parameter: the server forwards your OAuth bearer to the REST API and adds the X-Mesh-Platform: oauth header itself. You never set request headers when using MCP.

#Tool overview

ToolWrapsScope or role neededEffect
mesh_statusGET /context?compact=trueNoneRead
mesh_boardGET /board, GET /sprintNoneRead
mesh_ticketsGET /search or GET /boardNoneRead
mesh_ticket_getGET /ticketNoneRead
mesh_brief_getGET /contextNoneRead
mesh_ticket_createPOST /ticketwrite:ticketWrite
mesh_ticket_batchPOST /ticket/batchwrite:ticketWrite (1-25 tickets)
mesh_ticket_beginPOST /beginwrite:ticket, generator roleClaims files, starts ticket
mesh_ticket_updatePATCH /ticketwrite:ticketWrite
mesh_ticket_acknowledgePOST /ticket/{id}/acknowledgewrite:ticketWrite (idempotent)
mesh_sprint_createPOST /sprintwrite:sprintWrite
mesh_sprint_assignPOST /sprint/assignwrite:sprintWrite (idempotent)
mesh_brief_updatePATCH /briefwrite:briefOverwrites the fields you send
mesh_ledger_addPOST /ledgerwrite:ledgerWrite
mesh_handoffPOST /handoffwrite:handoff, generator roleReleases claims, advances ticket

An OAuth token granted with read scope can call only the read tools; the write tools return 403. OAuth tokens granted with write hold all of the scopes above except write:brief. mesh_brief_update still works on a blank brief (new-project setup); once the brief has content it needs write:brief. See Scopes.

#Results and errors

Every tool returns its result as a single JSON text block. Successful results are the REST response's data payload (or the reshaped output described per tool below). Failures set isError: true and return the upstream error unchanged, including any details.recovery hint:

json
{
  "error": {
    "code": "FORBIDDEN",
    "message": "API key lacks required scope: write:sprint",
    "details": {
      "recovery": {
        "action": "REPAIR_OR_REFRESH",
        "endpoint": "POST /api/mesh/pair/connect",
        "hint": "This token lacks 'write:sprint'. Re-pair to receive the current default scope set for your role."
      }
    }
  },
  "status": 403
}
  • On 401 the result also has a reauth string: re-authenticate the Mesh server in your client (in Claude Code, run /mcp and re-authenticate "mesh"), then retry.
  • An HTTP request to the MCP endpoint with no bearer, an expired access token, or a malformed token is answered with 401 and a WWW-Authenticate challenge so clients can start or refresh OAuth.
  • Calls to the REST API time out after 25 seconds. A timeout returns status: 504 with code UPSTREAM_TIMEOUT; the call may or may not have been applied, so check state (for example with mesh_status or mesh_ticket_get) before retrying a write. Other transport failures use UPSTREAM_UNREACHABLE (502) and UPSTREAM_NON_JSON.
  • Rate limits, LEDGER_STALE and the other rules from REST API overview apply unchanged.

#Read tools

#mesh_status

Returns the current session state: the project and agent this connection is bound to, your active ticket, board counts and work surface, compliance score, and conflict warnings, pending reviews and coordinator notes when present. Call it first in a session. It takes no parameters and reads GET /context?compact=true.

json
// Result (abbreviated)
{
  "project": { "id": "3f1c…", "name": "payments-api" },
  "agent": { "id": "9a2e…", "name": "OAuth Agent (user_2ab)", "platform": "oauth" },
  "resume": {
    "activeTicket": { "id": "b7d2a0f4-3c1e-4c55-9f0a-5d1f9a6b2e10", "title": "Add retry to webhook sender", "status": "in_progress" }
  },
  "workSurface": { },
  "complianceScore": 92,
  "skillVersion": "9f2c1a"
}

Keys conflictRisk, collisionWarnings, pendingReviews and coordinatorNotes are included only when they are not empty, and repoMismatch only when set. Tell the user project.name so they can confirm the connection is bound to the right project. A projectSetup object (needed, projectName, briefVersion, message, steps) appears on a brand-new project (no brief content and no tickets): in an existing codebase the agent drafts the brief and first tickets from the repo, in an empty directory it asks the user, and either way it confirms before writing. For the full payload use the context API.

#mesh_board

Returns the board as per-column ticket summaries, true per-column counts, and the sprint list. It reads GET /board and GET /sprint.

NameTypeDescription
sprintIdstringOnly tickets in this sprint (UUID).
statusstringOnly this status column, for example in_progress.
limitintegerTickets per page, 1 to 200. Default: server default (50).
cursorstringOpaque cursor from a previous board.nextCursor.
json
{
  "board": {
    "columns": {
      "in_progress": {
        "count": 2,
        "tickets": [
          { "id": "b7d2a0f4-3c1e-4c55-9f0a-5d1f9a6b2e10", "key": "APP-42", "title": "Add retry to webhook sender", "assignee": "builder" }
        ]
      },
      "sprint_backlog": { "count": 14, "tickets": [], "more": 14 }
    },
    "total": 31,
    "returned": 31,
    "hasMore": false
  },
  "sprints": []
}

Each column shows at most 10 ticket summaries; more is the number of tickets not shown. When board.hasMore is true, pass board.nextCursor as cursor for the next page. Column names come from the statuses present, so custom columns appear too.

#mesh_tickets

Lists tickets. With q it runs a keyword search (GET /search?scope=tickets); without it, it filters the board (GET /board). Returns an array of tickets.

NameTypeDescription
qstringKeyword search, at least 2 characters. When set, sprintId is not used.
sprintIdstringFilter by sprint (board listing only).
statusstringFor example sprint_backlog or in_progress.
typestringFor example feature, bug, chore, docs.
limitnumberMaximum tickets. Default: 20.

#mesh_ticket_get

Returns full ticket detail, including criteria, expected files and verification command. Wraps GET /ticket.

NameTypeDescription
keystringHuman ticket key such as APP-42. Takes precedence over id.
idstringTicket UUID.
includeLedgerbooleanInclude ledger entries for the ticket. Default: true.
includeCommentsbooleanInclude comments. Default: false.

Pass either key or id; with neither, the call fails with 400 VALIDATION_ERROR.

#mesh_brief_get

Reads the project brief and its version. Takes no parameters; reads GET /context.

json
{
  "brief": { "scope": "Rebuild checkout", "goals": ["Ship checkout v2"], "stack": ["Next.js", "Postgres"] },
  "briefVersion": 4,
  "briefUpdatedAt": null
}

Pass briefVersion as expectedVersion to mesh_brief_update. briefUpdatedAt is currently always null. brief is undefined (omitted) if the project has no brief yet.

#Ticket tools

#mesh_ticket_create

Creates a ticket in agent-first format. Scope: write:ticket. Wraps POST /ticket; the result is the created ticket as the REST endpoint returns it. See Writing agent-first tickets and the Tickets API.

NameTypeDescription
titlerequiredstringUp to 100 characters.
typerequiredstringOne of feature, bug, chore, refactor, spike, docs.
descriptionrequiredstringUp to 2,000 characters.
riskClassrequiredstringlocal, shared-state or irreversible.
expectedFilesrequiredstring[]At least one path the work will touch.
acceptanceCriteriarequiredobject[]At least one. Each: { title, description?, evidence }, where evidence is ledger, pr, screenshot, log or none.
doneDefinitionrequiredstringOne line stating what done means. The API requires at least 20 characters.
verificationCommandrequiredstringA command that verifies the work. The API requires at least 10 characters.
sprintIdstringSprint UUID to file the ticket into. Must belong to this project.
tagsstring[]Labels.
json
{
  "title": "Add retry to webhook sender",
  "type": "feature",
  "description": "Webhook deliveries fail permanently on the first 5xx. Add jittered exponential backoff.",
  "riskClass": "local",
  "expectedFiles": ["lib/webhooks/send.ts", "lib/webhooks/send.test.ts"],
  "acceptanceCriteria": [
    { "title": "Failed deliveries retry up to 5 times with jitter", "evidence": "ledger" }
  ],
  "doneDefinition": "Webhook sender retries 5xx responses with jittered backoff and has tests.",
  "verificationCommand": "npx vitest run lib/webhooks"
}

If the project has no brief yet, creation fails with BRIEF_REQUIRED and a recovery hint pointing at PATCH /brief. Missing or invalid agent-first fields return 400 with details.missing and suggested values.

#mesh_ticket_batch

Creates 1 to 25 tickets in one call, each in the same agent-first shape as mesh_ticket_create. Scope: write:ticket. Wraps POST /ticket/batch. Rows are created independently: a response can be 200 with some rows in errors[], so check it. Useful for filing a new project's first tickets.

json
{ "tickets": [ { "title": "…", "type": "feature", "...": "same fields as mesh_ticket_create" } ] }

#mesh_ticket_begin

Atomically claims files and sets the ticket to in progress. Scope: write:ticket; generator role. Wraps POST /begin. Save the returned sessionId: mesh_ledger_add and mesh_handoff need it.

NameTypeDescription
ticketIdrequiredstringTicket UUID.
filesrequiredstring[]1 to 20 files you will edit. A claim is created for them.
acknowledgeCriteriabooleanPass true to acknowledge the ticket's existing acceptance criteria as part of begin. The tool sends it only when true.
json
// Result
{
  "ticket": { "id": "b7d2a0f4-3c1e-4c55-9f0a-5d1f9a6b2e10", "status": "in_progress" },
  "sessionId": "sess_9c2e...",
  "nextAction": "..."
}

The result contains only ticket, sessionId and nextAction. Common failures:

SituationWhat the tool returns
Criteria exist but are not acknowledged (medium and strict review modes)An error with the ticket's acceptanceCriteria and a nextStep: retry with acknowledgeCriteria: true.
The ticket has no acceptance criteria (medium and strict review modes)An error with a nextStep: call mesh_ticket_acknowledge with additionalCriteria, then retry.
A file is claimed by another agent409 CONFLICT with a details.conflicts list. See Claims API.
Your role is not generator403 FORBIDDEN with delegation guidance.

#mesh_ticket_update

Changes status, priority or assignment. Scope: write:ticket. Wraps PATCH /ticket. The server enforces valid transitions and the project's review gates; a rejected transition lists the valid targets, and gate errors carry recovery hints. Moving a ticket to review requires a reviewHandoff bundle.

NameTypeDescription
ticketIdrequiredstringTicket UUID.
statusstringTarget status.
prioritystringcritical, high, normal or low.
assignToSelfbooleanAssign the ticket to yourself. Returns 409 if another agent holds it.
unassignbooleanClear the assignment. Mutually exclusive with assignToSelf.
reviewHandoffobject{ summary, changedFiles, branch, prUrl? }: what was done, files touched, the git branch, and the pull request URL if one exists. Required when the transition goes to in_review.

#mesh_ticket_acknowledge

Acknowledges a ticket's acceptance criteria, optionally adding criteria first. Scope: write:ticket. Use it when mesh_ticket_begin or a review gate fails with ACKNOWLEDGE_CRITERIA or ADD_CRITERIA. Wraps POST /ticket/{id}/acknowledge.

NameTypeDescription
ticketIdrequiredstringTicket UUID.
additionalCriteriaobject[]Up to 20 criteria to append before acknowledging; required when the ticket has none. Each: { title (1 to 500 chars), description? (up to 2000), requiresEvidence (boolean) }. The tool marks them as manual.

#Sprint tools

Sprint planning is an orchestrator or generator activity: sub-agent tokens do not hold write:sprint. See Planning sprints and the Sprints API.

#mesh_sprint_create

Creates a sprint. Scope: write:sprint. All fields are optional; the name defaults to "Sprint N" and the sprint starts in the planning state. The result includes the new sprint id, which you pass to mesh_sprint_assign or to mesh_ticket_create as sprintId.

NameTypeDescription
namestringUp to 200 characters.
goalstringUp to 2,000 characters.
startDatestringISO 8601 start date.
endDatestringISO 8601 end date.
capacityPointsintegerPlanned capacity in story points, 0 to 9,999.

#mesh_sprint_assign

Moves an existing ticket into a sprint, or removes it from its sprint. Scope: write:sprint. Idempotent: assigning to the current sprint changes nothing.

NameTypeDescription
ticketIdrequiredstringTicket UUID or human key such as APP-42.
sprintIdrequiredstring | nullTarget sprint UUID, or null to remove the ticket from its sprint.
idempotencyKeystringUp to 120 characters. Makes retries idempotent for a 60-second window.

#Brief tool

#mesh_brief_update

Writes one or more brief fields as a new version. Scope: write:brief, or write:ticket while the brief is blank. Wraps PATCH /brief, which is limited to 20 requests a minute. Always pass expectedVersion from mesh_brief_get; if the brief changed since, the call fails with 409 VERSION_CONFLICT and returns the current version and content so you can merge and retry.

NameTypeDescription
scopestringWhat the project is.
goalsstringProject goals.
stackstringTechnologies used. Stored as the text you send.
constraintsstringRules every agent must respect.
contextstringBackground that does not fit elsewhere.
expectedVersionintegerThe briefVersion you last read.

At least one field besides expectedVersion is required. Result: { "version": 5, "patchedFields": ["goals"] }.

#Ledger and handoff tools

#mesh_ledger_add

Posts a ledger entry. Scope: write:ledger. Wraps POST /ledger. Result: id, createdAt, nextAction, and warnings when applicable.

NameTypeDescription
typerequiredstringOne of PROGRESS (what changed), DECISION, TESTED (command plus output), BLOCKED (blocker plus how to unblock), ALERT.
contentrequiredstringThe entry text, up to 2,000 characters.
sessionIdrequiredstringFrom mesh_ticket_begin.
ticketIdstringTicket UUID or key.
fileRefstringFile path for PROGRESS or TESTED entries.

#mesh_handoff

Submits your handoff, releases your claims, and moves your ticket to the board's review column (or to done when the project uses light review). Scope: write:handoff; generator role. You must be the ticket's assignee and the ticket must be in progress. Wraps POST /handoff.

NameTypeDescription
moduleNamerequiredstringShort slug for what you built, for example webhook-retry.
summaryrequiredstringBoard-facing summary: what you built and open items. Up to 2,000 characters.
sessionIdrequiredstringFrom mesh_ticket_begin.
ticketIdstringTicket UUID.
testResultsstringShort test summary such as 18/18 passed. Up to 500 characters.
diffStatstringOutput summary of git diff --stat. Up to 500 characters.
toolResultsunknown[]Raw tool results to classify into ledger entries automatically.
artifactsobject[]Up to 10 artifacts to attach. Each: { type: "pull_request" | "branch" | "commit" | "deploy", url, ref?, title? }, where url must be a valid URL.

If a review gate or the ledger check blocks the handoff, the error's recovery hint names the call to make, typically logging a TESTED entry with mesh_ledger_add or attaching review evidence. See Sessions and handoff API.

#A typical session

text
1. mesh_status                     -> active ticket, board counts, pending actions
2. mesh_tickets {status: "sprint_backlog"}  -> pick a ticket
3. mesh_ticket_get {key: "APP-42"}  -> read criteria, expectedFiles, verificationCommand
4. mesh_ticket_begin {ticketId, files, acknowledgeCriteria: true}  -> sessionId
5. mesh_ledger_add {type: "PROGRESS", sessionId, content}          -> repeat as you work
6. mesh_ledger_add {type: "TESTED", sessionId, content}            -> command and result
7. mesh_handoff {moduleName, summary, sessionId, ticketId}         -> releases claims, advances ticket