Skip to content

MCP tool surface

StateLode keeps the tool surface small on purpose. Every extra tool adds choice, and LLMs get worse when the correct choice is hidden inside a wide menu.

Use this first. It returns lightweight task summaries and defaults to active work.

{
"projectId": "statelode",
"status": ["active", "in_progress"],
"assignee": "codex",
"limit": 10
}

Searching is truly read-only: a projectId that doesn’t exist is never created — the unknown_project error lists the workspace’s real slugs (knownProjects) so you can pick one and retry (see Workspaces, projects & tokens).

Add "sprint" to scope the search to a sprint: a sprint id, "active" (the project’s active sprint), or "none" (un-sprinted backlog).

Use this after task_search identifies a task you need to work on. It returns the full body, acceptance criteria, notes, blocker, dependencies, and updatedAt.

updatedAt is required for later mutations.

Use this for creates, updates, moves, comments, and blocking. Every mutation except create and comment must include the last updatedAt you saw.

{
"action": "move",
"payload": {
"id": "task_id",
"status": "in_progress",
"updatedAt": "2026-05-28T21:15:33.860Z",
"by": "codex"
}
}

If another agent won the race, StateLode returns STALE_WRITE with the fresh task inside the error. Retry with that fresh row. Do not guess.

Task lifecycle: a horizontal task-state chain with a cyan active signal and a dim retry branch for stale-write recovery.

Sprints are managed through task_mutate too — there is no fourth tool. A sprint is a named, goal-bearing group of tasks within one project, with a planned → active → completed lifecycle and exactly one active sprint per project.

ActionPayloadNotes
sprint_createprojectId, name, goal?Creates a planned sprint.
sprint_assignid, sprintId, updatedAtPuts a task in a sprint (sprintId: null removes it). Needs the task’s updatedAtSTALE_WRITE applies.
sprint_activatesprintIdMakes it the project’s active sprint. Fails if another is already active.
sprint_completesprintIdCloses the sprint.
{
"action": "sprint_activate",
"payload": { "sprintId": "sprint_id", "by": "codex" }
}

The board surfaces the active sprint as a lane with a priority-ordered “what’s next” queue, and a returning human sees a “since you were away” digest of what changed.

Every connected agent is a Delegate of one human workspace member. It does not become a member or impersonate that person; task history keeps both the agent credential and accountable human identity.

  • Team lead Delegates coordinate plans, assignments, reviews, and project direction.
  • Contributor Delegates focus on implementation and collaboration across project work.
  • Observer Delegates primarily monitor context and provide analysis or feedback.

These are advisory working postures, not permission roles. They never filter task visibility or reject an action. Workspace membership and credential scopes remain the authorization boundary, and the capabilities list reports what the current credential can actually do.

A Team lead turns a delivery plan into StateLode state without another tool: create a sprint with the plan’s goal, create the concrete tasks using member emails from statelode://workspace, then attach each task with sprint_assign.

Owners and admins assign these responsibilities to human members from Dashboard → Members. All of that member’s static-token and OAuth connections inherit the current role automatically in each workspace.

Workspace discovery (a resource, not a tool)

Section titled “Workspace discovery (a resource, not a tool)”

The server also exposes one MCP resource at statelode://workspace (application/json): each granted workspace, the human Supervisor, inherited role and capabilities, assignable human directory, and valid projects —

{
"workspace": { "id": "", "name": "", "slug": "" },
"delegation": {
"supervisor": { "userId": "", "displayName": "Ada" },
"responsibilityRole": "lead",
"capabilities": ["tasks:read:all", "tasks:create", "tasks:assign"]
},
"members": [
{ "userId": "", "displayName": "Grace", "email": "grace@example.com", "responsibilityRole": "contributor" }
],
"projects": [{ "slug": "statelode", "name": "StateLode" }]
}

Read it before acting: use the role as collaboration guidance, capabilities as the permission boundary, the member email for member-linked assignment, and a listed projectId instead of guessing one. It stays a resource so the tool count stays at three — the same reason sprints ride on task_mutate.