@statelyai/mcp 0.1.0 → 0.1.2

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/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ Copyright (c) 2025 Stately Software, Inc.
2
+
3
+ All rights reserved.
4
+
5
+ This repository and the Stately Viz software are proprietary to Stately
6
+ Software, Inc. No rights are granted to use, copy, modify, distribute, host, or
7
+ sublicense this software except under a separate written agreement with Stately
8
+ Software, Inc.
9
+
10
+ For licensing inquiries, contact team@stately.ai.
package/README.md CHANGED
@@ -1,58 +1,428 @@
1
- # @statelyai/mcp
1
+ # Stately MCP
2
2
 
3
- Reusable Stately MCP server for XState machine tooling.
3
+ Use Stately's machine tools from an MCP-compatible agent.
4
4
 
5
- ## Hosted HTTP usage
5
+ ## Connect
6
6
 
7
- <!-- hosted server factory and options from src/server.ts -->
7
+ <!-- public Stately MCP URL -->
8
8
 
9
- ```ts
10
- import { createStatelyMcpServer } from '@statelyai/mcp';
9
+ Choose your client and add Stately MCP using one of these methods.
11
10
 
12
- const server = createStatelyMcpServer({
13
- includeWorkspaceTools: false,
14
- apiBaseUrl: 'https://editor.stately.ai/api',
15
- credentialProvider: async () => ({
16
- type: 'oauth',
17
- accessToken,
18
- }),
19
- anonymousGraphPathLimit: 5,
11
+ ### Codex
12
+
13
+ ```bash
14
+ codex mcp add stately --url https://stately.ai/mcp
15
+ codex mcp login stately
16
+ ```
17
+
18
+ ### Claude Code
19
+
20
+ ```bash
21
+ claude mcp add --transport http stately https://stately.ai/mcp
22
+ ```
23
+
24
+ Then open Claude Code, run `/mcp`, and complete Stately sign-in.
25
+
26
+ ### Cursor
27
+
28
+ Open **Cursor Settings → MCP → Add new global MCP server**, then add:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "stately": {
34
+ "url": "https://stately.ai/mcp"
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ Save the configuration and complete Stately sign-in when Cursor connects. To
41
+ share the server with a project, put the same configuration in
42
+ `.cursor/mcp.json` at the project root.
43
+
44
+ ### VS Code with GitHub Copilot
45
+
46
+ Create `.vscode/mcp.json` in your project:
47
+
48
+ ```json
49
+ {
50
+ "servers": {
51
+ "stately": {
52
+ "type": "http",
53
+ "url": "https://stately.ai/mcp"
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ Open the Command Palette and run **MCP: List Servers**, start `stately`, then
60
+ complete Stately sign-in. For a personal configuration available in every
61
+ workspace, run **MCP: Open User Configuration** instead.
62
+
63
+ ### Other MCP clients
64
+
65
+ Add a remote server using the Streamable HTTP transport and this URL:
66
+
67
+ ```text
68
+ https://stately.ai/mcp
69
+ ```
70
+
71
+ Complete Stately sign-in when the client connects.
72
+
73
+ ## Machine input
74
+
75
+ <!-- shared machine input schemas from src/server.ts -->
76
+
77
+ Most tools accept a machine config object or a source document. Conversion
78
+ supports XState, SCXML, XGraph, and D2. Validation also supports JSON, YAML, and
79
+ Mermaid.
80
+
81
+ ## `validate_machine`
82
+
83
+ <!-- validate_machine registration from src/server.ts and validate response contract -->
84
+
85
+ Checks whether a machine can be parsed and reports structural issues such as
86
+ unreachable states. A successful response contains `ok` and an `issues` array.
87
+
88
+ <details>
89
+ <summary>Summary: validate a machine</summary>
90
+
91
+ ```text
92
+ Use Stately to validate this machine:
93
+
94
+ createMachine({
95
+ id: 'player',
96
+ initial: 'paused',
97
+ states: {
98
+ paused: { on: { PLAY: 'playing' } },
99
+ playing: { on: { PAUSE: 'paused', STOP: 'stopped' } },
100
+ stopped: { type: 'final' }
101
+ }
20
102
  });
21
103
  ```
22
104
 
23
- The host owns the transport, auth, CORS, rate limiting, and deployment. This
24
- package owns MCP tool schemas, handlers, annotations, and calls to the Stately
25
- HTTP API. Use `authMode: 'none'` only when the API is protected elsewhere.
105
+ </details>
26
106
 
27
- ## Local stdio usage
107
+ ## `convert_machine`
28
108
 
29
- <!-- stdio CLI bin from package.json and workspace tools from src/index.ts -->
109
+ <!-- convert_machine registration from src/server.ts and convert response contract -->
30
110
 
31
- ```bash
32
- stately-mcp --workspace /path/to/project
111
+ Converts a machine between XState, SCXML, XGraph, and D2. The response contains
112
+ the target `format`, converted `content`, and any `warnings`.
113
+
114
+ <details>
115
+ <summary>Summary: convert XState to SCXML</summary>
116
+
117
+ ```text
118
+ Use Stately to convert this machine to SCXML:
119
+
120
+ createMachine({
121
+ id: 'player',
122
+ initial: 'paused',
123
+ states: {
124
+ paused: { on: { PLAY: 'playing' } },
125
+ playing: { on: { STOP: 'stopped' } },
126
+ stopped: { type: 'final' }
127
+ }
128
+ });
129
+ ```
130
+
131
+ </details>
132
+
133
+ <details>
134
+ <summary>Summary: convert SCXML to XState</summary>
135
+
136
+ ```text
137
+ Use Stately to convert this SCXML machine to XState:
138
+
139
+ <scxml xmlns="http://www.w3.org/2005/07/scxml" name="player" initial="paused">
140
+ <state id="paused">
141
+ <transition event="PLAY" target="playing" />
142
+ </state>
143
+ <state id="playing">
144
+ <transition event="STOP" target="stopped" />
145
+ </state>
146
+ <final id="stopped" />
147
+ </scxml>
148
+ ```
149
+
150
+ </details>
151
+
152
+ <details>
153
+ <summary>Summary: convert XState to D2</summary>
154
+
155
+ ```text
156
+ Use Stately to convert this machine to D2:
157
+
158
+ createMachine({
159
+ id: 'player',
160
+ initial: 'paused',
161
+ states: {
162
+ paused: { on: { PLAY: 'playing' } },
163
+ playing: { on: { STOP: 'stopped' } },
164
+ stopped: { type: 'final' }
165
+ }
166
+ });
167
+ ```
168
+
169
+ </details>
170
+
171
+ <details>
172
+ <summary>Summary: convert XState to XGraph</summary>
173
+
174
+ ```text
175
+ Use Stately to convert this machine to XGraph:
176
+
177
+ createMachine({
178
+ id: 'player',
179
+ initial: 'paused',
180
+ states: {
181
+ paused: { on: { PLAY: 'playing' } },
182
+ playing: { on: { STOP: 'stopped' } },
183
+ stopped: { type: 'final' }
184
+ }
185
+ });
186
+ ```
187
+
188
+ </details>
189
+
190
+ ## `diff_machines`
191
+
192
+ <!-- diff_machines registration from src/server.ts and diff response contract -->
193
+
194
+ Compares two machine documents structurally instead of comparing their source
195
+ text. It returns a summary and semantic diff; set `includePatches` to request
196
+ applicable patches.
197
+
198
+ <details>
199
+ <summary>Summary: compare two machine versions</summary>
200
+
201
+ ```text
202
+ Use Stately to compare these two versions of a machine and suggest patches:
203
+
204
+ Before:
205
+ createMachine({
206
+ id: 'player',
207
+ initial: 'paused',
208
+ states: {
209
+ paused: { on: { PLAY: 'playing' } },
210
+ playing: {}
211
+ }
212
+ });
213
+
214
+ After:
215
+ createMachine({
216
+ id: 'player',
217
+ initial: 'paused',
218
+ states: {
219
+ paused: { on: { PLAY: 'playing' } },
220
+ playing: { on: { STOP: 'stopped' } },
221
+ stopped: { type: 'final' }
222
+ }
223
+ });
224
+ ```
225
+
226
+ </details>
227
+
228
+ ## `apply_machine_patches`
229
+
230
+ <!-- apply_machine_patches registration from src/server.ts and apply-patches response contract -->
231
+
232
+ Applies semantic patches to a machine and returns the updated document. Use
233
+ `to` to choose the returned format.
234
+
235
+ <details>
236
+ <summary>Summary: update a machine</summary>
237
+
238
+ ```text
239
+ Use Stately to rename the playing state to active and return the updated XState machine:
240
+
241
+ createMachine({
242
+ id: 'player',
243
+ initial: 'paused',
244
+ states: {
245
+ paused: { on: { PLAY: 'playing' } },
246
+ playing: {}
247
+ }
248
+ });
249
+ ```
250
+
251
+ </details>
252
+
253
+ ## `generate_graph_paths`
254
+
255
+ <!-- generate_graph_paths registration from src/server.ts and graph-paths response contract -->
256
+
257
+ Generates shortest or simple paths through a machine. The response includes
258
+ the event steps for each path plus state and transition coverage. Stately MCP
259
+ returns at most five paths per call.
260
+
261
+ <details>
262
+ <summary>Summary: generate shortest paths</summary>
263
+
264
+ ```text
265
+ Use Stately to find up to five shortest paths through this machine:
266
+
267
+ createMachine({
268
+ id: 'player',
269
+ initial: 'paused',
270
+ states: {
271
+ paused: { on: { PLAY: 'playing' } },
272
+ playing: { on: { PAUSE: 'paused', STOP: 'stopped' } },
273
+ stopped: { type: 'final' }
274
+ }
275
+ });
276
+ ```
277
+
278
+ </details>
279
+
280
+ ## `simulate_machine`
281
+
282
+ <!-- simulate_machine registration from src/server.ts and simulate response contract -->
283
+
284
+ Runs up to 100 events through a machine and returns a step-by-step trace of
285
+ states, context, and executed action names. Guards are stubbed during this
286
+ deterministic simulation.
287
+
288
+ <details>
289
+ <summary>Summary: simulate events</summary>
290
+
291
+ ```text
292
+ Use Stately to simulate PLAY followed by STOP on this machine:
293
+
294
+ createMachine({
295
+ id: 'player',
296
+ initial: 'paused',
297
+ states: {
298
+ paused: { on: { PLAY: 'playing' } },
299
+ playing: { on: { STOP: 'stopped' } },
300
+ stopped: { type: 'final' }
301
+ }
302
+ });
303
+ ```
304
+
305
+ </details>
306
+
307
+ ## `visualize_machine`
308
+
309
+ <!-- visualize_machine registration from src/server.ts and visualize response contract -->
310
+
311
+ Renders a machine as an SVG diagram. The response contains the SVG string,
312
+ its width and height, and any warnings.
313
+
314
+ <details>
315
+ <summary>Summary: visualize a machine</summary>
316
+
317
+ ```text
318
+ Use Stately to visualize this machine from left to right:
319
+
320
+ createMachine({
321
+ id: 'player',
322
+ initial: 'paused',
323
+ states: {
324
+ paused: { on: { PLAY: 'playing' } },
325
+ playing: { on: { STOP: 'stopped' } },
326
+ stopped: { type: 'final' }
327
+ }
328
+ });
329
+ ```
330
+
331
+ </details>
332
+
333
+ ## `analyze_machine`
334
+
335
+ <!-- analyze_machine registration from src/server.ts and analyze response contract -->
336
+
337
+ Combines deterministic checks with AI review. Provide optional intent to assess
338
+ the machine against its expected behavior. The response contains issues and may
339
+ include suggested fixes. Use `validate_machine` when only deterministic checks
340
+ are needed.
341
+
342
+ <details>
343
+ <summary>Summary: analyze intended behavior</summary>
344
+
345
+ ```text
346
+ Use Stately to check that STOP reaches a final state and playback cannot restart:
347
+
348
+ createMachine({
349
+ id: 'player',
350
+ initial: 'paused',
351
+ states: {
352
+ paused: { on: { PLAY: 'playing' } },
353
+ playing: { on: { STOP: 'stopped' } },
354
+ stopped: { type: 'final' }
355
+ }
356
+ });
357
+ ```
358
+
359
+ </details>
360
+
361
+ ## `generate_test_code`
362
+
363
+ <!-- generate_test_code registration and generateTestCode implementation from src/server.ts -->
364
+
365
+ Generates a runnable Vitest file with one test per generated path. Each test
366
+ sends the path's events and asserts its final state. Guards and actions are
367
+ stubbed.
368
+
369
+ <details>
370
+ <summary>Summary: generate Vitest tests</summary>
371
+
372
+ ```text
373
+ Use Stately to generate Vitest tests for the shortest paths through this machine:
374
+
375
+ createMachine({
376
+ id: 'player',
377
+ initial: 'paused',
378
+ states: {
379
+ paused: { on: { PLAY: 'playing' } },
380
+ playing: { on: { STOP: 'stopped' } },
381
+ stopped: { type: 'final' }
382
+ }
383
+ });
33
384
  ```
34
385
 
35
- Local stdio mode includes workspace tools:
386
+ </details>
387
+
388
+ ## `extract_machines_from_code`
389
+
390
+ <!-- extract_machines_from_code registration from src/server.ts -->
391
+
392
+ Parses XState source code and returns the extracted machine as an XGraph
393
+ document.
394
+
395
+ <details>
396
+ <summary>Summary: extract a machine from TypeScript</summary>
397
+
398
+ ```text
399
+ Use Stately to extract the machine from this TypeScript:
400
+
401
+ import { createMachine } from 'xstate';
402
+
403
+ export const player = createMachine({
404
+ id: 'player',
405
+ initial: 'paused',
406
+ states: {
407
+ paused: { on: { PLAY: 'playing' } },
408
+ playing: { on: { STOP: 'stopped' } },
409
+ stopped: { type: 'final' }
410
+ }
411
+ });
412
+ ```
36
413
 
37
- - `list_machines`
38
- - `get_machine`
414
+ </details>
39
415
 
40
- API-backed tools read `STATELY_ACCESS_TOKEN`, stored CLI credentials, or
41
- `STATELY_API_KEY`. Use `STATELY_AUTH_MODE=none` for no-auth self-hosted APIs.
416
+ All Stately MCP tools are registered as read-only, non-destructive, idempotent,
417
+ and closed-world.
42
418
 
43
- ## Tools
419
+ ## Self-hosting
44
420
 
45
- <!-- hosted MCP tool registrations from src/server.ts -->
421
+ <!-- self-host MCP endpoint from ../editor/src/app/api/[transport]/route.ts and ../editor/src/lib/auth/oauthProtectedResource.ts -->
46
422
 
47
- - `validate_machine`
48
- - `convert_machine`
49
- - `diff_machines`
50
- - `apply_machine_patches`
51
- - `generate_graph_paths`
52
- - `simulate_machine`
53
- - `visualize_machine`
54
- - `analyze_machine`
55
- - `generate_test_code`
56
- - `extract_machines_from_code`
423
+ Self-host Stately Studio, then replace the hosted URL above with your
424
+ deployment's `/api/mcp` endpoint, for example
425
+ `https://studio.example.com/api/mcp`.
57
426
 
58
- All tools are annotated read-only, non-destructive, idempotent, and closed-world.
427
+ For enterprise self-hosting options, [see pricing and contact
428
+ us](https://stately.ai/pricing).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statelyai/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "files": [
@@ -19,11 +19,6 @@
19
19
  "require": "./dist/index.cjs"
20
20
  }
21
21
  },
22
- "scripts": {
23
- "build": "tsdown",
24
- "test": "vitest run",
25
- "test:watch": "vitest"
26
- },
27
22
  "dependencies": {
28
23
  "@modelcontextprotocol/sdk": "1.26.0",
29
24
  "zod": "^4.4.1"
@@ -32,5 +27,10 @@
32
27
  "@types/node": "25.2.1",
33
28
  "tsdown": "0.21.0-beta.2",
34
29
  "vitest": "^3.2.4"
30
+ },
31
+ "scripts": {
32
+ "build": "tsdown",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest"
35
35
  }
36
- }
36
+ }