> For AI agents: the complete Sanity documentation index is available at [https://www.sanity.io/docs/llms.txt](https://www.sanity.io/docs/llms.txt).

# Workflows MCP tools reference

Every tool the Workflows MCP server exposes, with inputs, results, and errors, generated from @sanity/workflow-mcp 0.37, plus the embedding API.

This page lists every tool `@sanity/workflow-mcp` 0.37 exposes to an agent, with its inputs, result, and errors, plus the API for embedding the tools in another MCP server. It is generated from the package's tool definitions. To install the server and connect a client, follow [Connect an agent over MCP](https://www.sanity.io/docs/workflows/mcp).

## Workflow environment address

The server has no default environment. Every tool that reads or writes workflow data takes the address of one deployment, the `workflowResource` and `partition` of a deployment in your [sanity.workflow.ts](https://www.sanity.io/docs/workflows/workflow-config-reference). A deployment that omits `partition` uses `default`. `workflows_list_partitions` takes only `workflow_resource`, and the authoring guide and validation tools take no address.

#### Properties

**workflow_resource** (string, required)

The resource holding the workflow documents, as a resource GDR <type>:<id>: dataset:<projectId>.<dataset>, canvas:<id>, media-library:<id>, or dashboard:<id>. A malformed value fails with Invalid resource GDR "<value>": expected "<type>:<id>" with no document part.

**partition** (string, required)

The deployment partition within that resource. Lowercase letters, digits, and dashes. Call workflows_list_partitions to discover the partitions with deployed definitions, and confirm the intended one before calling another tool. A missing value fails with Use "partition" to address the workflow partition; "tag" is not supported. A tag key fails with [contract-violation] "tag" is not supported. Replace tag: "dev" with partition: "dev".

**Address for the quick start deployment**

```json
{
  "workflow_resource": "dataset:PROJECT_ID.DATASET_NAME",
  "partition": "dev"
}
```

## Results and errors

A successful call returns one text content item holding the result as indented JSON. A failed call returns `isError: true` with one text item rendered by `workflowErrorText`: an engine error leads with its stable `[kind]` (for example `[instance-not-found]`, `[contract-violation]`, `[reader-model-acknowledgement]`), and an input that fails the schema lists every problem as `✖ <message>` followed by `→ at <path>`, prefixed with the tool name. Results that carry titles, descriptions, conditions, or subject titles mark them as untrusted authored data in the tool description.

## Discovery and operations

**workflows_list_partitions(workflow_resource): read**

Lists the partitions that have deployed definitions in workflow_resource, sorted ascending. A partition with nothing deployed does not appear, and an empty list means the resource holds no deployed workflows.

Takes only workflow_resource. Read-only. Result: {partitions: string[]}. The stdio server registers it; it is not in WORKFLOW_TOOLS.

Parameters:
- **workflow_resource** (string): The resource to list partitions for.

**workflows_list_definitions(workflow_resource, partition): read**

The catalog of deployed workflow types, latest version per name. Each entry reports startable (false for child workflows that only run under a parent) and startKind: interactive (a person starts runs from a picker) or autonomous (a system starts runs in reaction to a document). startKind is a classification, not a restriction.

Requires the address. Read-only. Result: {definitions: {name, title, description?, version, startable, startKind}[]}.

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.

**workflows_get_definition(workflow_resource, partition, definition, version): read**

One deployed definition's full content, by name, defaulting to the latest version. The returned definition is the stored form with the document envelope stripped, and is valid input for workflows_validate_definition and workflows_deploy_definition as-is: to edit a workflow, read it, modify it, validate, and deploy the next version.

Requires the address. Read-only. Result: {name, version, definition}.

Error, unknown definition: no deployed definition "nope" in this workflow environment — workflows_list_definitions shows what is deployed

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.
- **definition** (string (non-empty)): The definition's name (as listed by workflows_list_definitions).
- **version** (integer (minimum 1)): A specific deployed version to read. Defaults to the latest.

**workflows_list_instances(workflow_resource, partition, definition, document, include_completed, assignment_user_id, assignment_roles, assignment_states, limit, cursor): read**

Lists instances in the addressed partition, most recently changed first, with optional definition, document, and include_completed filters. Assignment inputs filter to one person and add per-instance counts of active activities in the current stage: held (assigned directly to the person), routed (offered through one of their roles with no person assigned), and unrouted (no person or role selected). Counts do not promise that an action is available. Defensive document verification can leave a page underfilled. When has_more is true, call again with the same filters and next_cursor as cursor.

Requires the address. Read-only. Result: {instances: {instanceId, definition, workflowTitle?, currentStage, currentStageTitle?, lastChangedAt, done, subject?: {ref, title?}, assignment?: {unrouted, routed, held}}[], has_more, next_cursor?}.

Error, assignment filters without a user: workflows_list_instances: assignment_roles and assignment_states require assignment_user_id

Error, malformed cursor: workflows_list_instances: invalid cursor

Error, limit out of range: workflows_list_instances: ✖ Number must be less than or equal to 100

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.
- **definition** (string): Restrict to instances of this workflow definition, by its name (for example 'article-review').
- **document** (string): Only instances that reference this document, the workflow's subject or any other doc its fields point at, as a resource-qualified GDR URI (for example "dataset:proj:ds:article-1"). Use this to answer "which workflows are about this document?".
- **include_completed** (boolean (default false)): true includes completed/aborted instances. Defaults to false; in-flight instances only.
- **assignment_user_id** (string (non-empty)): Account-global user id for viewer-scoped assignment filtering and per-instance unrouted/routed/held counts.
- **assignment_roles** (string[] (non-empty items)): Literal project roles held by assignment_user_id. Role aliases do not change inbox ownership.
- **assignment_states** (('unrouted' | 'routed' | 'held')[] (at least 1 item)): Assignment states to include: unrouted work, routed work offered through assignment_roles, or work held directly by assignment_user_id.
- **limit** (integer (1 to 100, default 25)): Results per page, from 1 to 100. Defaults to 25.
- **cursor** (string): Opaque next_cursor from the previous response. Reuse the same filters and workflow environment when continuing.

**workflows_get_state(workflow_resource, partition, instance_id): read**

Everything actionable about one instance: current stage, subject, a workflow-level autonomy narrative, recent history, and each in-scope activity on the current stage. Per activity: classification (interactive, autonomous, off-system, or hybrid), a causal completesWithoutCaller verdict (yes, no, or conditional) with narrated waitsOn lines when it is not yes, invocable actions with an allowed or disabled verdict and their declared params, and automations the engine fires on its own. Activities and actions scoped out for this visit or caller are absent.

Requires the address. Read-only. Result: {instanceId, definition, workflowTitle?, currentStage, currentStageTitle?, done, subject?, activities, autonomy, recentHistory}.

Error, unknown instance: [instance-not-found] Workflow instance dev.wf-instance.missing not found

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.
- **instance_id** (string (non-empty)): The workflow instance id.

**workflows_diagnose(workflow_resource, partition, instance_id): read**

Explains why an instance is or is not progressing. state is progressing, waiting, blocked, completed, aborted, or stuck. Waiting distinguishes an action available to the caller, a manual action that caller cannot fire, and automation. A stuck instance adds a cause and remediations; remediations are advisory and none can run through this server.

Requires the address. Read-only. Result: {instanceId, state, summary, cause?, explanations?, remediations}.

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.
- **instance_id** (string (non-empty)): The workflow instance id.

**workflows_start(workflow_resource, partition, definition, version, initial_fields, instance_id): write**

Starts a deployed definition. Only definitions with startable: true start here; child workflows are spawn-only. Supply input-sourced field values in initial_fields. Every ordered start requirement must pass. The engine's cascade has already run when the result returns, so the instance can be past its initial stage. Pass the same instance_id to retry a failed start without creating a duplicate; a start whose first auto-advance failed still returns the instance, with a startNotSettled note.

Requires the address. Writes; not idempotent. Result: Same shape as workflows_get_state, plus startNotSettled?.

Error, unknown definition: no deployed definition "nope" in this workflow environment — workflows_list_definitions shows what is deployed

Error, missing definition: workflows_start: ✖ Required

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.
- **definition** (string (non-empty)): The workflow definition name to start (as listed by workflows_list_definitions).
- **version** (integer (minimum 1)): The deployed definition version to start from. Defaults to the highest.
- **initial_fields** (object): Values for the workflow's input-sourced field entries, keyed by field name (for example {"subject": {"id": "dataset:proj:ds:article-1", "type": "article"}}). doc.ref values take an object with a GDR id and doc type. workflows_get_definition shows a workflow's declared fields; only input-sourced entries accept a value here.
- **instance_id** (string (non-empty)): Start under this instance id; for retries. The id is the start's idempotency key: pass the SAME id when retrying a start that errored and the engine resumes that start instead of creating a duplicate instance (an already-settled start replays as a no-op). A failed start names the id to retry with in its error message. Omit to mint a fresh id.

**workflows_fire_action(workflow_resource, partition, instance_id, activity, action, params): write**

The instance write: fires an invocable action on a current-stage activity, exactly as an editor would, with values for the action's declared params. Pick the activity and action from workflows_get_state. Cascade-fired triggers are listed as automations and this tool rejects them. Auto-transitions that become eligible cascade in the same call. Not idempotent: a second call can land elsewhere.

Requires the address. Writes; not idempotent. Result: Same shape as workflows_get_state.

Error, activity not on the current stage: [contract-violation] Activity "write" not found in current stage "review" of article-review

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.
- **instance_id** (string (non-empty)): The workflow instance id.
- **activity** (string (non-empty)): The id of the activity on the current stage. Must be one of the activities returned by workflows_get_state.
- **action** (string (non-empty)): The id of the action on that activity. Must be one of the actions listed as allowed=true on the activity.
- **params** (object): Values for the action's declared params, keyed by param name (for example {"note": "Unsupported claim in paragraph 3."}). Required when the action declares a required param; workflows_get_state lists each action's params and whether they are required. The shape is per-action, so this is a free-form object; the engine validates the supplied values against the action's declared params and rejects the call if a required one is missing.

## Authoring

**workflows_get_authoring_guide(): read**

The DSL guide an agent reads before writing a definition: the definition shape, GROQ condition built-ins, sugars, the rules the validator enforces, and two worked JSON examples.

Takes no address and never reads the Content Lake. Read-only. Result: The guide, as one Markdown string.

**workflows_validate_definition(definitions): read**

Runs structure, cross-field, and GROQ syntax checks on a definitions array without reading the Content Lake. A single workflow is a one-element array; validate a parent and its children together. Each result is the desugared definition that would deploy, or a path-prefixed list of every problem. Deploy also checks duplicate names, spawn dependencies, resource bindings, project roles, and the reader-model acknowledgement, so a valid result does not guarantee a deploy succeeds. sanity-workflows definitions validate <file...> --json prints the same report.

Takes no address and never reads the Content Lake. Read-only. Result: {valid, results: ({valid: true, definition} | {valid: false, error})[]}.

Error, empty array: workflows_validate_definition: ✖ Array must contain at least 1 element(s)

Parameters:
- **definitions** (object[] (at least 1 item)): The workflow definitions to validate, as JSON objects in authoring shape. See workflows_get_authoring_guide for the shape and examples.

**workflows_deploy_definition(workflow_resource, partition, definitions, expectedMinReaderModel): write**

Publishes definitions into the addressed partition. Pass a parent and the children it spawns in one call; children deploy first. Deploys are create-only and content-addressed: content identical to the latest version returns unchanged, any change returns created with the next version, a new name starts at version 1, and running instances keep the version they started under. Runs the same checks as workflows_validate_definition but throws instead of returning the problem list.

Requires the address. Writes; idempotent. Result: {results: {name, version, status}[], deployId}.

Error, invalid definition: definitions[0] ("x"): defineWorkflow("x") failed validation (3 issues):

Error, acknowledgement below the floor: [reader-model-acknowledgement] Deployment acknowledges reader model 4; the submitted definitions require at least 10, and this writer supports acknowledgements through 11.

Parameters:
- **workflow_resource** (string): The workflow resource GDR, for example dataset:PROJECT_ID.DATASET_NAME. See the address.
- **partition** (string): The deployment partition, for example dev. See the address.
- **definitions** (object[] (at least 1 item)): The workflow definitions to deploy, as JSON objects in authoring shape; the same values workflows_validate_definition takes. A single workflow is a one-element array; a parent and its child workflows belong in one call. See workflows_get_authoring_guide for the shape and examples.
- **expectedMinReaderModel** (integer (minimum 0)): Highest reader model already verified across every runtime sharing this workflow resource. Omit to retain the model-4 baseline. Definitions with role-constrained assignment fields require model 8; singular assignment fields require model 9. Pass the highest applicable floor only after upgrading all shared Studio, CLI, MCP, Function, and other runtimes. Definitions with required subject, doc.ref, or doc.refs fields need 10, and an abort block needs 11; see Reader-model acknowledgement and follow Upgrade Workflows packages.

## Embedding API

Exports for hosts that add the Workflows tools to their own MCP server. `registerWorkflowTools` is the bundled path; a host with its own registration, error handling, or result envelopes iterates `WORKFLOW_TOOLS` instead. The library entry (`.`) contains no MCP runtime code; the `./stdio` entry exports `runStdioServer()`, the server the `workflow-mcp` binary runs, and also loads from CommonJS through its `require` condition.

**registerWorkflowTools(server, getContext, options?)(): void**

Registers every WORKFLOW_TOOLS entry on an McpServer. Tools with requiresAddress get workflow_resource and partition merged into their schema, and a tag argument is rejected. getContext(extra, input) returns {engine} (or a promise of it) for the requested environment; it runs only for tools that need an engine, never for the authoring guide or validation. Thrown errors become isError results through workflowErrorText. options.telemetry records one adoption event per call. Partition discovery is not registered; to offer it, register your own tool with LIST_WORKFLOW_PARTITIONS_TOOL_NAME and LIST_WORKFLOW_PARTITIONS_DESCRIPTION.

**workflowAddressFromInput(input)(): WorkflowEnvironmentAddress**

Reads {workflowResource, partition} from a tool call's input, ignoring other keys. Throws Invalid workflow environment address: with every problem listed, or ContractViolationError for a tag key.

**workflowClientConfig({resource, token?, base})(): Base & WorkflowClientPolicy & WorkflowResourceAddressing**

Layers the engine's client policy over the host's own config (base; pass {} if none): keeps its requester, headers, and apiHost, then pins the engine API version, useCdn: false, request-tag prefix sanity.workflows-mcp, and the published perspective, and sets either projectId/dataset or resource for the target while removing the other addressing style.

**createWorkflowEngine({address, client, executionContext?, telemetry?})(): Engine**

Creates an engine bound to one resource and partition, without caching; a long-lived host can cache engines itself. The client's token identifies the actor, so keep its authentication unchanged for the engine's lifetime. executionContext adds an advisory host label to history entries. Runtime field values may reference only the addressed workflow resource; to accept references to other resources, build the engine with createEngine from @sanity/workflow-engine and a resourceClients resolver, and return it from getContext.

**createMcpSessionTelemetry({clientFor, denied, nodeEnv?, sessionId?})(): McpSessionTelemetry**

Opt-in telemetry for an embedding host; embedding the tools does not enable it. clientFor(resource) returns an authenticated client; denied: true sends nothing. Create one per MCP session, pass its logger to the engine factory and to registerWorkflowTools, and call bind(resource) from each tool call's address before logging. The first dataset binding owns the session; later calls do not retarget it. Logs before binding are dropped and traces before binding throw. Await flush() before end() when the session closes.

**WORKFLOW_TOOLS(): readonly WorkflowToolDef[]**

Every tool definition in the order an agent should read them. Each has name, description, inputSchema (a raw zod/v3 shape), requiresAddress, annotations, and handler(context, input), which parses input itself and returns plain data. When requiresAddress is true, merge your host's environment parameters into the registered schema.

**toolInputJsonSchema(def)(): ToolInputJsonSchema**

The JSON Schema for a definition's own inputs, for consumers that do not use Zod (for example an Anthropic Messages API input_schema). It excludes the address fields; add your own.

**workflowErrorText(error)(): string**

The text a failed tool call should show: [<kind>] <message> for a WorkflowError, otherwise the message.

**WORKFLOW_PARTITION_DESCRIPTION(): string**

The model-facing description to use verbatim for your partition parameter.

**LIST_WORKFLOW_PARTITIONS_TOOL_NAME(): 'workflows_list_partitions'**

The name to register a partition-discovery tool under. WORKFLOW_PARTITION_DESCRIPTION tells the model to call it.

**LIST_WORKFLOW_PARTITIONS_DESCRIPTION(): string**

The model-facing description to register verbatim for that tool.

Each wire tool also has a camel-case `*Tool` export: `listWorkflowDefinitionsTool`, `getWorkflowDefinitionTool`, `listWorkflowInstancesTool`, `getWorkflowStateTool`, `diagnoseWorkflowTool`, `startWorkflowTool`, `fireActionTool`, `getWorkflowAuthoringGuideTool`, `validateWorkflowDefinitionTool`, and `deployWorkflowDefinitionTool`. Result types are exported as `ProjectedDefinitionSummary`, `ProjectedDefinition`, `ProjectedInstanceSummary`, `ProjectedInstanceState`, `ProjectedActivity`, `ProjectedActionVerdict`, `ProjectedAutomation`, `ProjectedHistoryEntry`, `ProjectedSubject`, `ProjectedDiagnosis`, `ValidateDefinitionResult`, and `ValidateDefinitionsResult`. See [TypeDoc](https://reference.sanity.io/_sanity/workflow-mcp/) for their fields.

Tool schemas are built with `zod/v3`, which both Zod 3 and Zod 4 ship. When you merge parameters into them, build those with `zod/v3` too; a Zod 4 schema in the same object fails type checking. `zod` (`^3.25.28 || ^4`) and `@modelcontextprotocol/sdk` (`^1.29.0`) are peer dependencies the host provides.

