@sanity/workflow-mcp 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +435 -0
- package/README.md +114 -45
- package/bin/run.js +0 -5
- package/dist/_chunks-es/index.js +862 -0
- package/dist/index.cjs +815 -483
- package/dist/index.d.cts +199 -99
- package/dist/index.d.ts +199 -99
- package/dist/index.js +2 -519
- package/dist/stdio.d.ts +14 -10
- package/dist/stdio.js +119 -68
- package/package.json +9 -6
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/stdio.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,43 +1,41 @@
|
|
|
1
|
+
import type { ActionParam } from "@sanity/workflow-engine";
|
|
1
2
|
import type { Diagnosis } from "@sanity/workflow-engine";
|
|
2
|
-
import { Engine } from "@sanity/workflow-engine";
|
|
3
|
+
import type { Engine } from "@sanity/workflow-engine";
|
|
4
|
+
import type { ExecutorClassification } from "@sanity/workflow-engine";
|
|
5
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
7
|
+
import type { ServerNotification } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import type { ServerRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
3
9
|
import type { StuckCause } from "@sanity/workflow-engine";
|
|
4
10
|
import type { SuggestedRemediation } from "@sanity/workflow-engine";
|
|
5
|
-
import {
|
|
11
|
+
import type { TelemetryLogger } from "@sanity/telemetry";
|
|
12
|
+
import type { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
|
|
6
13
|
import type { WorkflowDefinition } from "@sanity/workflow-engine";
|
|
14
|
+
import { WorkflowResource } from "@sanity/workflow-engine";
|
|
15
|
+
import { ZodRawShape } from "zod";
|
|
7
16
|
|
|
8
17
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
18
|
+
* The host seam: produce the {@link WorkflowToolContext} for one tool
|
|
19
|
+
* call. `extra` carries the request (a hosted server derives auth from
|
|
20
|
+
* it); `input` carries the parsed tool arguments — for the
|
|
21
|
+
* instance-operating tools that includes the per-call workflow
|
|
22
|
+
* environment address, which `workflowAddressFromInput` extracts so the
|
|
23
|
+
* host can build (or reuse) the engine for that environment. The
|
|
24
|
+
* authoring tools never invoke their context thunk, so this is never
|
|
25
|
+
* called without an address to read.
|
|
16
26
|
*/
|
|
17
|
-
export declare
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
27
|
+
export declare type GetWorkflowToolContext = (
|
|
28
|
+
extra: WorkflowToolExtra,
|
|
29
|
+
input: unknown,
|
|
30
|
+
) => WorkflowToolContext | Promise<WorkflowToolContext>;
|
|
21
31
|
|
|
22
32
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* In tests, pass `ALL_ACCESS` (from `@sanity/workflow-engine-test`)
|
|
29
|
-
* because the TestClient has no token and would otherwise throw on
|
|
30
|
-
* the resolution path.
|
|
33
|
+
* One invocable (fireAction-fired) action. Two whole classes of action never
|
|
34
|
+
* appear here: an action whose `filter` scoped it out for this actor is
|
|
35
|
+
* ABSENT (filter is existence — it might as well not exist, never "disabled"),
|
|
36
|
+
* and a cascade-fired (`when`) action is projected as a
|
|
37
|
+
* {@link ProjectedAutomation} instead — the engine fires it, no caller can.
|
|
31
38
|
*/
|
|
32
|
-
export declare interface BuildToolsOptions {
|
|
33
|
-
access?: WorkflowAccessOverride;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export declare interface BuiltTools {
|
|
37
|
-
descriptors: ToolDescriptor[];
|
|
38
|
-
impls: Record<string, ToolImpl>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
39
|
export declare interface ProjectedActionVerdict {
|
|
42
40
|
/** Action name — what to pass to `fire_action` as `action`. */
|
|
43
41
|
action: string;
|
|
@@ -47,6 +45,10 @@ export declare interface ProjectedActionVerdict {
|
|
|
47
45
|
allowed: boolean;
|
|
48
46
|
/** When `allowed` is false, a short reason describing why. */
|
|
49
47
|
disabledReason?: string;
|
|
48
|
+
/** The action's declared params — what `fire_action`'s `params` object must
|
|
49
|
+
* satisfy (each entry names the param and whether it is required). Absent
|
|
50
|
+
* when the action declares none. */
|
|
51
|
+
params?: ActionParam[];
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
export declare interface ProjectedActivity {
|
|
@@ -56,10 +58,57 @@ export declare interface ProjectedActivity {
|
|
|
56
58
|
title?: string;
|
|
57
59
|
/** Longer prose description, if provided. */
|
|
58
60
|
description?: string;
|
|
59
|
-
/** Current activity status.
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
/** Current activity status. Activities are active from stage entry; an
|
|
62
|
+
* activity whose `filter` scoped it out of this visit is absent from the
|
|
63
|
+
* projection, so `skipped` here always means an action resolved it so. */
|
|
64
|
+
status: "active" | "done" | "skipped" | "failed";
|
|
65
|
+
/**
|
|
66
|
+
* Who, if anyone, the activity waits on — `interactive` (only invocable
|
|
67
|
+
* actions), `autonomous` (only cascade-fired automation), `off-system`
|
|
68
|
+
* (work performed outside the system), or `hybrid` (both kinds).
|
|
69
|
+
*/
|
|
70
|
+
classification: ExecutorClassification;
|
|
71
|
+
/** Invocable actions on this activity, each with its allowed/disabled
|
|
72
|
+
* verdict. See {@link ProjectedActionVerdict} for what never appears. */
|
|
62
73
|
actions: ProjectedActionVerdict[];
|
|
74
|
+
/** Cascade-fired actions, narrated as automation ("fires when …").
|
|
75
|
+
* Present only when the activity declares any. */
|
|
76
|
+
automations?: ProjectedAutomation[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* One cascade-fired (`when`) action, narrated as automation: the engine fires
|
|
81
|
+
* it on its own the moment the trigger holds — it is never invocable via
|
|
82
|
+
* `fire_action`, so it must not read as a button.
|
|
83
|
+
*/
|
|
84
|
+
export declare interface ProjectedAutomation {
|
|
85
|
+
/** The cascade-fired action's name. Not accepted by `fire_action`. */
|
|
86
|
+
action: string;
|
|
87
|
+
/** Human label, if provided. */
|
|
88
|
+
title?: string;
|
|
89
|
+
/** The trigger — the GROQ condition whose truth makes the engine fire it. */
|
|
90
|
+
firesWhen: string;
|
|
91
|
+
/** What still stands between the current state and the trigger, as one
|
|
92
|
+
* English line ("Needs: …"). Absent when the trigger is already satisfied
|
|
93
|
+
* or already fired this stage visit. */
|
|
94
|
+
pending?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Result of `get_workflow_definition` — one deployed version's content.
|
|
99
|
+
* `definition` is the stored (desugared) form with the document envelope
|
|
100
|
+
* stripped — valid input for the validate/deploy tools as-is (their parse
|
|
101
|
+
* accepts stored form; parts of it, e.g. resolved guard `idRefs`, are NOT
|
|
102
|
+
* valid authoring shape): modify it and redeploy via
|
|
103
|
+
* `deploy_workflow_definition` to mint the next version.
|
|
104
|
+
*/
|
|
105
|
+
export declare interface ProjectedDefinition {
|
|
106
|
+
/** Definition `name`. */
|
|
107
|
+
name: string;
|
|
108
|
+
/** The deployed version this content came from. */
|
|
109
|
+
version: number;
|
|
110
|
+
/** The envelope-stripped definition content. */
|
|
111
|
+
definition: WorkflowDefinition;
|
|
63
112
|
}
|
|
64
113
|
|
|
65
114
|
/**
|
|
@@ -80,6 +129,10 @@ export declare interface ProjectedDiagnosis {
|
|
|
80
129
|
summary: string;
|
|
81
130
|
/** When `state` is "stuck", the structured cause kind. */
|
|
82
131
|
cause?: StuckCause["kind"];
|
|
132
|
+
/** Per unsatisfied exit transition, its insight summary ("the "Publish"
|
|
133
|
+
* transition: Needs: «Legal approved» must be true") — present when any
|
|
134
|
+
* exit is currently held. */
|
|
135
|
+
explanations?: string[];
|
|
83
136
|
/**
|
|
84
137
|
* What would unstick the instance — empty unless stuck. Each names a
|
|
85
138
|
* surface-neutral verb, whether it's runnable as an engine operation today
|
|
@@ -92,7 +145,8 @@ export declare interface ProjectedDiagnosis {
|
|
|
92
145
|
export declare interface ProjectedHistoryEntry {
|
|
93
146
|
/** ISO timestamp. */
|
|
94
147
|
at: string;
|
|
95
|
-
/**
|
|
148
|
+
/** Human-readable entry title from the engine's display metadata
|
|
149
|
+
* (e.g. "Stage entered"). */
|
|
96
150
|
type: string;
|
|
97
151
|
/** Free-form one-line summary suitable for an LLM to read. */
|
|
98
152
|
summary: string;
|
|
@@ -162,78 +216,41 @@ export declare interface ProjectedSubject {
|
|
|
162
216
|
}
|
|
163
217
|
|
|
164
218
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* Two jobs: operate running instances, and author new definitions.
|
|
170
|
-
*
|
|
171
|
-
* Operate an instance:
|
|
172
|
-
*
|
|
173
|
-
* - `list_workflow_instances` is the only way to *discover* what's
|
|
174
|
-
* running without already knowing an id. Filterable, capped.
|
|
175
|
-
* - `get_workflow_state` is the "tell me everything actionable about
|
|
176
|
-
* one instance" call. It composes the engine's `evaluate` projection
|
|
177
|
-
* into a flat shape an LLM can reason over without piecing together
|
|
178
|
-
* raw `WorkflowInstance` documents.
|
|
179
|
-
* - `diagnose_workflow` answers "*why* isn't this moving?" — it
|
|
180
|
-
* classifies an instance as healthy (waiting/progressing) or genuinely
|
|
181
|
-
* stuck (a failed effect/activity, a dead-end transition) and names the
|
|
182
|
-
* remediations that would unstick it. A pure read; the remediations are
|
|
183
|
-
* advisory (none execute through this server).
|
|
184
|
-
* - `fire_action` is the only write. Mirrors the engine's universal
|
|
185
|
-
* "something happened" entry point — everything other than admin
|
|
186
|
-
* override flows through it.
|
|
187
|
-
*
|
|
188
|
-
* Author a definition (both pure, engine-independent, neither deploys):
|
|
189
|
-
*
|
|
190
|
-
* - `get_workflow_authoring_guide` returns the DSL guide an agent reads
|
|
191
|
-
* before writing a definition — shape, GROQ built-ins, sugars, examples.
|
|
192
|
-
* - `validate_workflow_definition` runs the deploy-time checks (structure +
|
|
193
|
-
* invariants + GROQ) and returns the desugared definition or a
|
|
194
|
-
* path-prefixed error list. A human deploys it via the CLI.
|
|
195
|
-
*
|
|
196
|
-
* Surface choices that matter for an LLM consumer:
|
|
197
|
-
*
|
|
198
|
-
* - Descriptions are written for an agent, not a human reader.
|
|
199
|
-
* Each one says (a) what the tool does, (b) when to use it,
|
|
200
|
-
* (c) what *not* to use it for.
|
|
201
|
-
* - Parameter names use snake_case, matching MCP convention.
|
|
202
|
-
* - The write tool's description spells out that this is the way
|
|
203
|
-
* to advance workflow state — not a side door. Without that line,
|
|
204
|
-
* an LLM tends to look for a `complete_activity` or `set_stage` tool.
|
|
205
|
-
* - Read tools cap their output. A 50-page `recent_history` would
|
|
206
|
-
* burn context and is rarely informative; 8 is enough to spot
|
|
207
|
-
* loops or stuck-in-stage patterns.
|
|
219
|
+
* Register every workflow tool onto `server`, wired through `getContext`.
|
|
220
|
+
* A host that owns a telemetry shell passes its logger to log one
|
|
221
|
+
* adoption event per tool call; without it, calls log nothing.
|
|
208
222
|
*/
|
|
223
|
+
export declare function registerWorkflowTools(
|
|
224
|
+
server: McpServer,
|
|
225
|
+
getContext: GetWorkflowToolContext,
|
|
226
|
+
options?: {
|
|
227
|
+
telemetry?: TelemetryLogger<unknown>;
|
|
228
|
+
},
|
|
229
|
+
): void;
|
|
230
|
+
|
|
209
231
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
232
|
+
* JSON-schema descriptor for consumers that don't speak zod — e.g. the
|
|
233
|
+
* Anthropic Messages API `input_schema` field. `properties`/`required`
|
|
234
|
+
* are declared (not left to the index signature) so the shape is
|
|
235
|
+
* directly assignable to the Anthropic SDK's `Tool.InputSchema`.
|
|
213
236
|
*/
|
|
214
|
-
export declare interface
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
type: "object";
|
|
220
|
-
properties: Record<string, unknown>;
|
|
221
|
-
required?: string[];
|
|
222
|
-
additionalProperties?: boolean;
|
|
223
|
-
};
|
|
237
|
+
export declare interface ToolInputJsonSchema {
|
|
238
|
+
type: "object";
|
|
239
|
+
properties?: Record<string, unknown>;
|
|
240
|
+
required?: string[];
|
|
241
|
+
[key: string]: unknown;
|
|
224
242
|
}
|
|
225
243
|
|
|
226
|
-
/**
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
*/
|
|
231
|
-
export declare type ToolImpl = (input: unknown) => Promise<unknown>;
|
|
244
|
+
/** Derive the JSON-schema descriptor from a def's zod shape. */
|
|
245
|
+
export declare function toolInputJsonSchema(
|
|
246
|
+
def: WorkflowToolDef,
|
|
247
|
+
): ToolInputJsonSchema;
|
|
232
248
|
|
|
233
249
|
/**
|
|
234
|
-
*
|
|
235
|
-
* desugared form that would deploy
|
|
236
|
-
* `valid: false`, `error` is the
|
|
250
|
+
* Per-definition result inside {@link ValidateDefinitionsResult}. On
|
|
251
|
+
* `valid: true`, `definition` is the desugared form that would deploy
|
|
252
|
+
* (defaults filled, sugar expanded); on `valid: false`, `error` is the
|
|
253
|
+
* aggregated, path-prefixed list of problems.
|
|
237
254
|
*/
|
|
238
255
|
export declare type ValidateDefinitionResult =
|
|
239
256
|
| {
|
|
@@ -245,4 +262,87 @@ export declare type ValidateDefinitionResult =
|
|
|
245
262
|
error: string;
|
|
246
263
|
};
|
|
247
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Result of `validate_workflow_definition`. `results` pairs positionally with
|
|
267
|
+
* the input `definitions`; `valid` is true only when every definition passed.
|
|
268
|
+
*/
|
|
269
|
+
export declare interface ValidateDefinitionsResult {
|
|
270
|
+
valid: boolean;
|
|
271
|
+
results: ValidateDefinitionResult[];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export declare const WORKFLOW_TOOLS: readonly WorkflowToolDef[];
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Parse the {@link WorkflowEnvironmentAddress} out of a tool call's input —
|
|
278
|
+
* the host side of the address contract: a host's `getContext` reads the
|
|
279
|
+
* address from the input this parses and builds (or reuses) the engine for
|
|
280
|
+
* it. Extra input keys (the tool's other parameters) are ignored.
|
|
281
|
+
*/
|
|
282
|
+
export declare function workflowAddressFromInput(
|
|
283
|
+
input: unknown,
|
|
284
|
+
): WorkflowEnvironmentAddress;
|
|
285
|
+
|
|
286
|
+
/** Where one tool call reads/writes workflow data: resource + tag. */
|
|
287
|
+
export declare interface WorkflowEnvironmentAddress {
|
|
288
|
+
workflowResource: WorkflowResource;
|
|
289
|
+
tag: string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Everything a tool call needs from its host: the engine to operate on.
|
|
294
|
+
* Identity is the token behind the engine's client (`/users/me`) — a host
|
|
295
|
+
* that should act as someone else supplies an engine over their token, and
|
|
296
|
+
* declares itself via the engine's `executionContext`.
|
|
297
|
+
*/
|
|
298
|
+
export declare interface WorkflowToolContext {
|
|
299
|
+
engine: Engine;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Lazy context supplier. A thunk rather than the context itself so a
|
|
304
|
+
* host never pays for engine construction on tools that don't call it —
|
|
305
|
+
* the guide and validate tools teach and check the DSL without touching
|
|
306
|
+
* the lake, and a per-request host would otherwise build a client for
|
|
307
|
+
* nothing.
|
|
308
|
+
*/
|
|
309
|
+
export declare type WorkflowToolContextThunk =
|
|
310
|
+
() => Promise<WorkflowToolContext>;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* One workflow tool, host-neutral. Hosts iterate {@link WORKFLOW_TOOLS}
|
|
314
|
+
* and register each def with their own glue (error wrapping, telemetry,
|
|
315
|
+
* result envelopes); `registerWorkflowTools` is the bundled convenience
|
|
316
|
+
* for hosts without opinions of their own.
|
|
317
|
+
*/
|
|
318
|
+
export declare interface WorkflowToolDef {
|
|
319
|
+
readonly name: string;
|
|
320
|
+
readonly description: string;
|
|
321
|
+
/**
|
|
322
|
+
* Raw zod shape — the single schema source of truth: MCP servers
|
|
323
|
+
* register it directly, {@link parseToolInput} wraps it for runtime
|
|
324
|
+
* parsing, and {@link toolInputJsonSchema} derives the JSON-schema
|
|
325
|
+
* descriptor for non-MCP consumers.
|
|
326
|
+
*/
|
|
327
|
+
readonly inputSchema: ZodRawShape;
|
|
328
|
+
readonly annotations: ToolAnnotations;
|
|
329
|
+
/**
|
|
330
|
+
* Returns plain projected data (the `Projected*` shapes) — hosts own
|
|
331
|
+
* the serialisation into their transport's result envelope. Takes
|
|
332
|
+
* `unknown` and parses internally: a heterogeneous list of defs with
|
|
333
|
+
* typed handler inputs is unassignable under `strictFunctionTypes`,
|
|
334
|
+
* so the narrowing lives inside each handler instead.
|
|
335
|
+
*/
|
|
336
|
+
readonly handler: (
|
|
337
|
+
context: WorkflowToolContextThunk,
|
|
338
|
+
input: unknown,
|
|
339
|
+
) => Promise<unknown>;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** The per-request extra the MCP SDK hands every registered tool callback. */
|
|
343
|
+
export declare type WorkflowToolExtra = RequestHandlerExtra<
|
|
344
|
+
ServerRequest,
|
|
345
|
+
ServerNotification
|
|
346
|
+
>;
|
|
347
|
+
|
|
248
348
|
export {};
|