@xenolithengine/graph-mcp-server 0.7.0-beta.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.
@@ -0,0 +1,14 @@
1
+ export interface ResourceDef {
2
+ /** Stable URI shown to MCP clients (e.g. Claude Desktop attachment pane). */
3
+ uri: string;
4
+ /** Short display name in the client. */
5
+ name: string;
6
+ /** One-line description for the LLM picking the right resource. */
7
+ description: string;
8
+ /** MIME type of the returned content. */
9
+ mimeType: string;
10
+ /** Existing remote tool name to call via the WS bridge to fetch content. */
11
+ remoteTool: string;
12
+ }
13
+ export declare const RESOURCES: ReadonlyArray<ResourceDef>;
14
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAA;IACX,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAA;IACnB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,SAAS,EAAE,aAAa,CAAC,WAAW,CAehD,CAAA"}
@@ -0,0 +1,22 @@
1
+ // MCP **resources** — read-only context the AI client can attach to its prompt without spending
2
+ // a tool call per read. Each entry binds a stable URI (the spec calls these "resources") to a
3
+ // fetcher; the fetcher calls back into the editor via the existing WS bridge using the SAME
4
+ // remote tool name we already ship — `get_graph`, `list_node_types`, etc. — so there's no new
5
+ // editor surface, just a different MCP-side exposure (resource vs tool).
6
+ export const RESOURCES = [
7
+ {
8
+ uri: 'graph://current',
9
+ name: 'Current graph',
10
+ description: 'The live editor graph as xenolith.v1 JSON — nodes, edges, comments. Attach this to ask the AI about the current state without forcing it to call get_graph.',
11
+ mimeType: 'application/json',
12
+ remoteTool: 'get_graph',
13
+ },
14
+ {
15
+ uri: 'schema://types',
16
+ name: 'Node type schemas',
17
+ description: 'Every registered node type with its pins (label/direction/data type) and widgets. Attach this so the AI knows the available types before designing a graph — saves a list_node_types call per session.',
18
+ mimeType: 'application/json',
19
+ remoteTool: 'list_node_types',
20
+ },
21
+ ];
22
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,8FAA8F;AAC9F,4FAA4F;AAC5F,8FAA8F;AAC9F,yEAAyE;AAezE,MAAM,CAAC,MAAM,SAAS,GAA+B;IACnD;QACE,GAAG,EAAE,iBAAiB;QACtB,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,6JAA6J;QAC1K,QAAQ,EAAE,kBAAkB;QAC5B,UAAU,EAAE,WAAW;KACxB;IACD;QACE,GAAG,EAAE,gBAAgB;QACrB,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,wMAAwM;QACrN,QAAQ,EAAE,kBAAkB;QAC5B,UAAU,EAAE,iBAAiB;KAC9B;CACF,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { EditorBridge } from './bridge.js';
3
+ /** Build the MCP server: advertise our tools, and on each tool call forward args to the connected
4
+ * editor over the WS bridge. The MCP SDK handles stdio framing + JSON-RPC. */
5
+ export declare function createMcpServer(bridge: EditorBridge): McpServer;
6
+ export declare function startStdio(mcp: McpServer): Promise<void>;
7
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAI1C;+EAC+E;AAC/E,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAuD/D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9D"}
package/dist/server.js ADDED
@@ -0,0 +1,58 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { EditorBridge } from './bridge.js';
4
+ import { TOOLS } from './tools.js';
5
+ import { RESOURCES } from './resources.js';
6
+ /** Build the MCP server: advertise our tools, and on each tool call forward args to the connected
7
+ * editor over the WS bridge. The MCP SDK handles stdio framing + JSON-RPC. */
8
+ export function createMcpServer(bridge) {
9
+ const mcp = new McpServer({ name: 'xenolith-graph', version: '0.7.0-beta.0' });
10
+ // Resources — read-only context. Each one forwards to an existing remote tool over the WS
11
+ // bridge so the editor needs no separate code path. MCP clients (Claude Desktop / Cursor)
12
+ // list these alongside tools and let the user attach them as context.
13
+ for (const r of RESOURCES) {
14
+ mcp.registerResource(r.name, r.uri, { description: r.description, mimeType: r.mimeType }, async (uri) => {
15
+ try {
16
+ const data = await bridge.current().call(r.remoteTool, {});
17
+ return { contents: [{ uri: uri.href, mimeType: r.mimeType, text: JSON.stringify(data, null, 2) }] };
18
+ }
19
+ catch (err) {
20
+ const message = err instanceof Error ? err.message : String(err);
21
+ return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: `error: ${message}` }] };
22
+ }
23
+ });
24
+ }
25
+ for (const def of Object.values(TOOLS)) {
26
+ mcp.registerTool(def.name, { description: def.description, inputSchema: def.schema.shape }, async (args) => {
27
+ try {
28
+ const result = await bridge.current().call(def.name, args);
29
+ // Screenshot tools return a data-URI in `dataUri`. Re-wrap as MCP ImageContent so clients
30
+ // (Claude Desktop / Cursor / etc.) actually render the picture instead of dumping the
31
+ // base64 string into chat. Everything else is JSON text content.
32
+ const r = (result ?? null);
33
+ if (r && typeof r.dataUri === 'string') {
34
+ const match = r.dataUri.match(/^data:([^;]+);base64,(.*)$/s);
35
+ if (match) {
36
+ return {
37
+ content: [
38
+ { type: 'image', data: match[2], mimeType: match[1] },
39
+ { type: 'text', text: JSON.stringify({ ...r, dataUri: '<image>' }) },
40
+ ],
41
+ };
42
+ }
43
+ }
44
+ return { content: [{ type: 'text', text: JSON.stringify(result ?? null) }] };
45
+ }
46
+ catch (err) {
47
+ const message = err instanceof Error ? err.message : String(err);
48
+ return { content: [{ type: 'text', text: `error: ${message}` }], isError: true };
49
+ }
50
+ });
51
+ }
52
+ return mcp;
53
+ }
54
+ export async function startStdio(mcp) {
55
+ const transport = new StdioServerTransport();
56
+ await mcp.connect(transport);
57
+ }
58
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,452 @@
1
+ import { z, type ZodTypeAny } from 'zod';
2
+ /** A declarative MCP tool. The server registers each one with the MCP SDK and routes the call to
3
+ * the connected editor via the WS bridge by name. Tools are intentionally thin — the editor owns
4
+ * validation and command semantics; the server just shapes the request and forwards it. */
5
+ export interface ToolDef<Schema extends ZodTypeAny> {
6
+ /** Stable tool name. MCP clients invoke by this; the WS protocol forwards by this. */
7
+ name: string;
8
+ /** Free-text description shown to the LLM. */
9
+ description: string;
10
+ /** Input schema (zod). Becomes JSON-Schema for the MCP advertisement. */
11
+ schema: Schema;
12
+ }
13
+ export declare const TOOLS: {
14
+ readonly list_node_types: {
15
+ readonly name: "list_node_types";
16
+ readonly description: "List every node type registered in the editor with its pins (direction/label/type). ALWAYS call this before add_node and connect_pins so you can use the real type names and pin labels — otherwise pins will not match.";
17
+ readonly schema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
18
+ };
19
+ readonly get_graph: {
20
+ readonly name: "get_graph";
21
+ readonly description: "Return the current graph as xenolith.v1 JSON (nodes, edges, comments). Read-only snapshot.";
22
+ readonly schema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
23
+ };
24
+ readonly add_node: {
25
+ readonly name: "add_node";
26
+ readonly description: "Insert a node of the given type. Coordinates are OPTIONAL: if omitted the editor drops it just to the right of the existing graph (or at the origin if empty). Prefer adding all nodes without coordinates, then calling auto_layout once to tidy the whole picture — the LLM has no idea about node sizes/spacing, so manual coords almost always overlap.";
27
+ readonly schema: z.ZodObject<{
28
+ type: z.ZodString;
29
+ x: z.ZodOptional<z.ZodNumber>;
30
+ y: z.ZodOptional<z.ZodNumber>;
31
+ state: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
32
+ }, "strict", z.ZodTypeAny, {
33
+ type: string;
34
+ x?: number | undefined;
35
+ y?: number | undefined;
36
+ state?: Record<string, unknown> | undefined;
37
+ }, {
38
+ type: string;
39
+ x?: number | undefined;
40
+ y?: number | undefined;
41
+ state?: Record<string, unknown> | undefined;
42
+ }>;
43
+ };
44
+ readonly connect_pins: {
45
+ readonly name: "connect_pins";
46
+ readonly description: "Connect an output pin (from) to a compatible input pin (to). Pin types must match (float→float, object→object). The `pin` field accepts the pin LABEL (\"Output\", \"In\") as returned by list_node_types, OR a numeric index (\"0\", \"1\"), OR the literal \"in\"/\"out\" for simple single-pin nodes — pick whatever is easiest. Never invent uuids. On error the response lists the available pins so you can retry.";
47
+ readonly schema: z.ZodObject<{
48
+ from: z.ZodObject<{
49
+ node: z.ZodString;
50
+ pin: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
51
+ }, "strip", z.ZodTypeAny, {
52
+ node: string;
53
+ pin: string | number;
54
+ }, {
55
+ node: string;
56
+ pin: string | number;
57
+ }>;
58
+ to: z.ZodObject<{
59
+ node: z.ZodString;
60
+ pin: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
61
+ }, "strip", z.ZodTypeAny, {
62
+ node: string;
63
+ pin: string | number;
64
+ }, {
65
+ node: string;
66
+ pin: string | number;
67
+ }>;
68
+ }, "strict", z.ZodTypeAny, {
69
+ from: {
70
+ node: string;
71
+ pin: string | number;
72
+ };
73
+ to: {
74
+ node: string;
75
+ pin: string | number;
76
+ };
77
+ }, {
78
+ from: {
79
+ node: string;
80
+ pin: string | number;
81
+ };
82
+ to: {
83
+ node: string;
84
+ pin: string | number;
85
+ };
86
+ }>;
87
+ };
88
+ readonly fit_view: {
89
+ readonly name: "fit_view";
90
+ readonly description: "Frame the whole graph (or a specific node subset) in the viewport with padding. No return value.";
91
+ readonly schema: z.ZodObject<{
92
+ nodeIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
93
+ padding: z.ZodOptional<z.ZodNumber>;
94
+ }, "strict", z.ZodTypeAny, {
95
+ nodeIds?: string[] | undefined;
96
+ padding?: number | undefined;
97
+ }, {
98
+ nodeIds?: string[] | undefined;
99
+ padding?: number | undefined;
100
+ }>;
101
+ };
102
+ readonly set_widget_value: {
103
+ readonly name: "set_widget_value";
104
+ readonly description: "Set the value of a widget on a node (slider/number/toggle/combo/text/color/custom). Value type must match the widget type (number for slider/number, boolean for toggle, string for combo/text/color, arbitrary JSON for custom). Undoable.";
105
+ readonly schema: z.ZodObject<{
106
+ nodeId: z.ZodString;
107
+ widget: z.ZodString;
108
+ value: z.ZodUnknown;
109
+ }, "strict", z.ZodTypeAny, {
110
+ nodeId: string;
111
+ widget: string;
112
+ value?: unknown;
113
+ }, {
114
+ nodeId: string;
115
+ widget: string;
116
+ value?: unknown;
117
+ }>;
118
+ };
119
+ readonly remove_node: {
120
+ readonly name: "remove_node";
121
+ readonly description: "Delete a node by id. Incident edges are removed automatically. Undoable.";
122
+ readonly schema: z.ZodObject<{
123
+ nodeId: z.ZodString;
124
+ }, "strict", z.ZodTypeAny, {
125
+ nodeId: string;
126
+ }, {
127
+ nodeId: string;
128
+ }>;
129
+ };
130
+ readonly disconnect_edge: {
131
+ readonly name: "disconnect_edge";
132
+ readonly description: "Remove an edge by id (as returned by connect_pins or get_graph).";
133
+ readonly schema: z.ZodObject<{
134
+ edgeId: z.ZodString;
135
+ }, "strict", z.ZodTypeAny, {
136
+ edgeId: string;
137
+ }, {
138
+ edgeId: string;
139
+ }>;
140
+ };
141
+ readonly create_macro: {
142
+ readonly name: "create_macro";
143
+ readonly description: "Wrap a set of nodes into a collapsed Macro (group). External edges touching the selection become proxy pins on the macro, so the macro behaves like a single node from the outside. Returns the macro id.";
144
+ readonly schema: z.ZodObject<{
145
+ nodeIds: z.ZodArray<z.ZodString, "many">;
146
+ title: z.ZodOptional<z.ZodString>;
147
+ }, "strict", z.ZodTypeAny, {
148
+ nodeIds: string[];
149
+ title?: string | undefined;
150
+ }, {
151
+ nodeIds: string[];
152
+ title?: string | undefined;
153
+ }>;
154
+ };
155
+ readonly expand_macro: {
156
+ readonly name: "expand_macro";
157
+ readonly description: "Open a collapsed macro inline — members become visible again. Camera animates to fit the group automatically.";
158
+ readonly schema: z.ZodObject<{
159
+ macroId: z.ZodString;
160
+ }, "strict", z.ZodTypeAny, {
161
+ macroId: string;
162
+ }, {
163
+ macroId: string;
164
+ }>;
165
+ };
166
+ readonly collapse_macro: {
167
+ readonly name: "collapse_macro";
168
+ readonly description: "Re-collapse an expanded macro back into a single node with proxy pins.";
169
+ readonly schema: z.ZodObject<{
170
+ macroId: z.ZodString;
171
+ }, "strict", z.ZodTypeAny, {
172
+ macroId: string;
173
+ }, {
174
+ macroId: string;
175
+ }>;
176
+ };
177
+ readonly auto_layout: {
178
+ readonly name: "auto_layout";
179
+ readonly description: "Tidy the entire graph: re-position every node using a layered left-to-right layout based on edge topology (sources on the left, sinks on the right). Call this AFTER adding nodes/edges so the result looks like a hand-arranged graph instead of overlapping boxes. Safe to call multiple times.";
180
+ readonly schema: z.ZodObject<{
181
+ direction: z.ZodOptional<z.ZodEnum<["LR", "TB"]>>;
182
+ spacing: z.ZodOptional<z.ZodNumber>;
183
+ }, "strict", z.ZodTypeAny, {
184
+ direction?: "LR" | "TB" | undefined;
185
+ spacing?: number | undefined;
186
+ }, {
187
+ direction?: "LR" | "TB" | undefined;
188
+ spacing?: number | undefined;
189
+ }>;
190
+ };
191
+ readonly set_category_palette: {
192
+ readonly name: "set_category_palette";
193
+ readonly description: "Recolour every node by category. Pass a map of category id → CSS colour. Categories come from node schemas — the values returned by list_node_types under `category` (e.g. \"logic\", \"data\", \"macro\", \"utility\", or whatever the host registered). Each entry can be (a) a plain \"#RRGGBB\" / rgba(...) / CSS-named colour for a solid pill, or (b) an object `{start, end}` for a two-stop gradient header. Pass an empty object to reset to the theme defaults.";
194
+ readonly schema: z.ZodObject<{
195
+ palette: z.ZodRecord<z.ZodString, z.ZodUnknown>;
196
+ }, "strict", z.ZodTypeAny, {
197
+ palette: Record<string, unknown>;
198
+ }, {
199
+ palette: Record<string, unknown>;
200
+ }>;
201
+ };
202
+ readonly set_theme: {
203
+ readonly name: "set_theme";
204
+ readonly description: "Override a subset of theme tokens (colours, gradients, geometry) at runtime. Pass a partial token object — anything you do not specify keeps its current value. The shape mirrors the editor's theme tokens; the most common subset is `color.accent`, `color.surface.*`, `color.text.*`, `geometry.node.radius`. Use this to make AI-driven recolours visible without uploading a whole new theme.";
205
+ readonly schema: z.ZodObject<{
206
+ tokens: z.ZodRecord<z.ZodString, z.ZodUnknown>;
207
+ }, "strict", z.ZodTypeAny, {
208
+ tokens: Record<string, unknown>;
209
+ }, {
210
+ tokens: Record<string, unknown>;
211
+ }>;
212
+ };
213
+ readonly register_node_schema: {
214
+ readonly name: "register_node_schema";
215
+ readonly description: "Define a brand-new node type the user can then instantiate via add_node. The schema must include `type` (unique identifier), `title`, optional `category`, and a `pins` array (each pin has `kind`, `direction`, `type`, optional `label`). Optional `widgets` array describes inline controls — for `combo` widgets you MUST pass a `values` array; `slider`/`number` accept `min`/`max`/`step`. If list_node_types already shows a type with the name you want, prefer add_node on the existing type rather than registering a variant with a different name.";
216
+ readonly schema: z.ZodObject<{
217
+ type: z.ZodString;
218
+ title: z.ZodOptional<z.ZodString>;
219
+ category: z.ZodOptional<z.ZodString>;
220
+ pins: z.ZodArray<z.ZodObject<{
221
+ kind: z.ZodDefault<z.ZodEnum<["data", "exec"]>>;
222
+ direction: z.ZodEnum<["in", "out"]>;
223
+ type: z.ZodString;
224
+ label: z.ZodOptional<z.ZodString>;
225
+ }, "strip", z.ZodTypeAny, {
226
+ kind: "data" | "exec";
227
+ type: string;
228
+ direction: "in" | "out";
229
+ label?: string | undefined;
230
+ }, {
231
+ type: string;
232
+ direction: "in" | "out";
233
+ kind?: "data" | "exec" | undefined;
234
+ label?: string | undefined;
235
+ }>, "many">;
236
+ widgets: z.ZodOptional<z.ZodArray<z.ZodObject<{
237
+ id: z.ZodString;
238
+ key: z.ZodOptional<z.ZodString>;
239
+ type: z.ZodEnum<["number", "slider", "toggle", "combo", "text", "color", "button"]>;
240
+ label: z.ZodOptional<z.ZodString>;
241
+ values: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
242
+ label: z.ZodString;
243
+ value: z.ZodString;
244
+ }, "strip", z.ZodTypeAny, {
245
+ value: string;
246
+ label: string;
247
+ }, {
248
+ value: string;
249
+ label: string;
250
+ }>]>, "many">>;
251
+ min: z.ZodOptional<z.ZodNumber>;
252
+ max: z.ZodOptional<z.ZodNumber>;
253
+ step: z.ZodOptional<z.ZodNumber>;
254
+ }, "strip", z.ZodTypeAny, {
255
+ id: string;
256
+ type: "number" | "slider" | "toggle" | "combo" | "text" | "color" | "button";
257
+ values?: (string | {
258
+ value: string;
259
+ label: string;
260
+ })[] | undefined;
261
+ label?: string | undefined;
262
+ key?: string | undefined;
263
+ min?: number | undefined;
264
+ max?: number | undefined;
265
+ step?: number | undefined;
266
+ }, {
267
+ id: string;
268
+ type: "number" | "slider" | "toggle" | "combo" | "text" | "color" | "button";
269
+ values?: (string | {
270
+ value: string;
271
+ label: string;
272
+ })[] | undefined;
273
+ label?: string | undefined;
274
+ key?: string | undefined;
275
+ min?: number | undefined;
276
+ max?: number | undefined;
277
+ step?: number | undefined;
278
+ }>, "many">>;
279
+ }, "strict", z.ZodTypeAny, {
280
+ type: string;
281
+ pins: {
282
+ kind: "data" | "exec";
283
+ type: string;
284
+ direction: "in" | "out";
285
+ label?: string | undefined;
286
+ }[];
287
+ title?: string | undefined;
288
+ category?: string | undefined;
289
+ widgets?: {
290
+ id: string;
291
+ type: "number" | "slider" | "toggle" | "combo" | "text" | "color" | "button";
292
+ values?: (string | {
293
+ value: string;
294
+ label: string;
295
+ })[] | undefined;
296
+ label?: string | undefined;
297
+ key?: string | undefined;
298
+ min?: number | undefined;
299
+ max?: number | undefined;
300
+ step?: number | undefined;
301
+ }[] | undefined;
302
+ }, {
303
+ type: string;
304
+ pins: {
305
+ type: string;
306
+ direction: "in" | "out";
307
+ kind?: "data" | "exec" | undefined;
308
+ label?: string | undefined;
309
+ }[];
310
+ title?: string | undefined;
311
+ category?: string | undefined;
312
+ widgets?: {
313
+ id: string;
314
+ type: "number" | "slider" | "toggle" | "combo" | "text" | "color" | "button";
315
+ values?: (string | {
316
+ value: string;
317
+ label: string;
318
+ })[] | undefined;
319
+ label?: string | undefined;
320
+ key?: string | undefined;
321
+ min?: number | undefined;
322
+ max?: number | undefined;
323
+ step?: number | undefined;
324
+ }[] | undefined;
325
+ }>;
326
+ };
327
+ readonly select_nodes: {
328
+ readonly name: "select_nodes";
329
+ readonly description: "Set the editor selection to exactly the listed node ids. Use to draw the user's attention to nodes the AI just changed, or to scope a follow-up operation visually.";
330
+ readonly schema: z.ZodObject<{
331
+ nodeIds: z.ZodArray<z.ZodString, "many">;
332
+ }, "strict", z.ZodTypeAny, {
333
+ nodeIds: string[];
334
+ }, {
335
+ nodeIds: string[];
336
+ }>;
337
+ };
338
+ readonly clear_selection: {
339
+ readonly name: "clear_selection";
340
+ readonly description: "Deselect every node.";
341
+ readonly schema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
342
+ };
343
+ readonly dive_into_template: {
344
+ readonly name: "dive_into_template";
345
+ readonly description: "Open a template-instance node to edit its inner subgraph. Pass the instance node id (as listed by get_graph). The breadcrumb in the editor updates so the user can see where they are.";
346
+ readonly schema: z.ZodObject<{
347
+ instanceId: z.ZodString;
348
+ }, "strict", z.ZodTypeAny, {
349
+ instanceId: string;
350
+ }, {
351
+ instanceId: string;
352
+ }>;
353
+ };
354
+ readonly dive_out: {
355
+ readonly name: "dive_out";
356
+ readonly description: "Pop out of the current subgraph back to its parent. Optional `toDepth` jumps multiple levels at once (0 = back to Root).";
357
+ readonly schema: z.ZodObject<{
358
+ toDepth: z.ZodOptional<z.ZodNumber>;
359
+ }, "strict", z.ZodTypeAny, {
360
+ toDepth?: number | undefined;
361
+ }, {
362
+ toDepth?: number | undefined;
363
+ }>;
364
+ };
365
+ readonly find_nodes: {
366
+ readonly name: "find_nodes";
367
+ readonly description: "Search the current graph for nodes matching a predicate. Returns ids + types + labels. Combine fields with AND. Use this instead of pulling the whole graph when you only need a subset.";
368
+ readonly schema: z.ZodObject<{
369
+ type: z.ZodOptional<z.ZodString>;
370
+ category: z.ZodOptional<z.ZodString>;
371
+ titleContains: z.ZodOptional<z.ZodString>;
372
+ }, "strict", z.ZodTypeAny, {
373
+ type?: string | undefined;
374
+ category?: string | undefined;
375
+ titleContains?: string | undefined;
376
+ }, {
377
+ type?: string | undefined;
378
+ category?: string | undefined;
379
+ titleContains?: string | undefined;
380
+ }>;
381
+ };
382
+ readonly describe_node: {
383
+ readonly name: "describe_node";
384
+ readonly description: "Return a detailed snapshot of one node: type, title, category, position, all pins (with live connections), and all widgets (with current values). Use before reasoning about a node — get_graph returns a thinner shape.";
385
+ readonly schema: z.ZodObject<{
386
+ nodeId: z.ZodString;
387
+ }, "strict", z.ZodTypeAny, {
388
+ nodeId: string;
389
+ }, {
390
+ nodeId: string;
391
+ }>;
392
+ };
393
+ readonly screenshot: {
394
+ readonly name: "screenshot";
395
+ readonly description: "Render the entire graph (NOT just the viewport — every node, padded) to a base64-encoded PNG/JPEG. Use to verify what the user is seeing after a series of edits. The response is large — only call when you need to \"see\" the result.";
396
+ readonly schema: z.ZodObject<{
397
+ format: z.ZodOptional<z.ZodEnum<["png", "jpeg"]>>;
398
+ scale: z.ZodOptional<z.ZodNumber>;
399
+ padding: z.ZodOptional<z.ZodNumber>;
400
+ }, "strict", z.ZodTypeAny, {
401
+ padding?: number | undefined;
402
+ format?: "png" | "jpeg" | undefined;
403
+ scale?: number | undefined;
404
+ }, {
405
+ padding?: number | undefined;
406
+ format?: "png" | "jpeg" | undefined;
407
+ scale?: number | undefined;
408
+ }>;
409
+ };
410
+ readonly node_screenshot: {
411
+ readonly name: "node_screenshot";
412
+ readonly description: "Render a single node's current view (with its widget values, status ring, the lot) to a base64-encoded image. Much smaller than full `screenshot`. Use when you want to inspect or show ONE node — e.g. \"did my set_widget_value land?\".";
413
+ readonly schema: z.ZodObject<{
414
+ nodeId: z.ZodString;
415
+ format: z.ZodOptional<z.ZodEnum<["png", "jpeg"]>>;
416
+ scale: z.ZodOptional<z.ZodNumber>;
417
+ }, "strict", z.ZodTypeAny, {
418
+ nodeId: string;
419
+ format?: "png" | "jpeg" | undefined;
420
+ scale?: number | undefined;
421
+ }, {
422
+ nodeId: string;
423
+ format?: "png" | "jpeg" | undefined;
424
+ scale?: number | undefined;
425
+ }>;
426
+ };
427
+ readonly list_recipes: {
428
+ readonly name: "list_recipes";
429
+ readonly description: "Return the named subgraph templates the editor knows about. Each entry has `id`, `title`, `description`, `category`, and `requires` (the schema types the recipe assumes exist). Use this BEFORE instantiate_recipe so you know which recipes are available and what types you may need to register_node_schema first.";
430
+ readonly schema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
431
+ };
432
+ readonly instantiate_recipe: {
433
+ readonly name: "instantiate_recipe";
434
+ readonly description: "Drop a named recipe into the current graph in one call. Creates every node + every edge, returns the map of recipe-local id → real node id (so you can describe_node / connect_pins to additional nodes after). If the recipe needs schemas that aren't registered, the call fails with a list of missing types — register them with register_node_schema and retry. Nodes are stacked at the origin; call auto_layout afterwards to tidy.";
435
+ readonly schema: z.ZodObject<{
436
+ id: z.ZodString;
437
+ x: z.ZodOptional<z.ZodNumber>;
438
+ y: z.ZodOptional<z.ZodNumber>;
439
+ }, "strict", z.ZodTypeAny, {
440
+ id: string;
441
+ x?: number | undefined;
442
+ y?: number | undefined;
443
+ }, {
444
+ id: string;
445
+ x?: number | undefined;
446
+ y?: number | undefined;
447
+ }>;
448
+ };
449
+ };
450
+ export type ToolName = keyof typeof TOOLS;
451
+ export declare const TOOL_NAMES: ToolName[];
452
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,KAAK,UAAU,EAAE,MAAM,KAAK,CAAA;AAExC;;4FAE4F;AAC5F,MAAM,WAAW,OAAO,CAAC,MAAM,SAAS,UAAU;IAChD,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAA;IACZ,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAA;CACf;AAED,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6LsC,CAAA;AAExD,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,KAAK,CAAA;AACzC,eAAO,MAAM,UAAU,EAAyB,QAAQ,EAAE,CAAA"}