construct-shader-graph-mcp 0.7.0 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "construct-shader-graph-mcp",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Standalone MCP server for Construct Shader Graph",
5
5
  "type": "module",
6
6
  "files": [
@@ -124,6 +124,7 @@ Read-only calls:
124
124
  - `getManifest`
125
125
  - `nodes.list`
126
126
  - `nodes.get`
127
+ - `nodes.getInfo`
127
128
  - `nodes.getPorts`
128
129
  - `nodes.search`
129
130
  - `nodeTypes.list`
@@ -223,7 +224,7 @@ This is one of the most important workflows.
223
224
 
224
225
  To change a node's editable input values:
225
226
 
226
- 1. Read the node with `nodes.get(nodeId)`.
227
+ 1. Read the node with `nodes.getInfo(nodeId)`.
227
228
  2. Inspect `editableInputValues` to see which inputs are editable and currently unconnected.
228
229
  3. Edit with `nodes.edit(nodeId, { inputValues: ... })`.
229
230
 
@@ -236,10 +237,10 @@ Rules:
236
237
 
237
238
  Example workflow:
238
239
 
239
- - call `nodes.get(nodeId)`
240
+ - call `nodes.getInfo(nodeId)`
240
241
  - inspect `editableInputValues`
241
242
  - call `nodes.edit(nodeId, { inputValues: { B: [0, 0, 0, 1] } })`
242
- - re-read the node with `nodes.get(nodeId)`
243
+ - re-read the node with `nodes.getInfo(nodeId)`
243
244
 
244
245
  Name-based example:
245
246
 
package/src/server.mjs CHANGED
@@ -33,7 +33,60 @@ function nowIso() {
33
33
  }
34
34
 
35
35
  function loadSkillText() {
36
- return fs.readFileSync(SKILL_PATH, "utf8");
36
+ try {
37
+ return fs.readFileSync(SKILL_PATH, "utf8");
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+
43
+ async function fetchGuidanceFromApp() {
44
+ if (!selectedSessionId) {
45
+ return null;
46
+ }
47
+
48
+ const session = sessions.get(selectedSessionId);
49
+ if (!session) {
50
+ return null;
51
+ }
52
+
53
+ try {
54
+ const result = await invokeSession(session, "getGuidance", []);
55
+ if (result?.ok && result.result) {
56
+ return result.result;
57
+ }
58
+ } catch {
59
+ // Fall back to local file.
60
+ }
61
+
62
+ return null;
63
+ }
64
+
65
+ async function getSkillText() {
66
+ const appGuidance = await fetchGuidanceFromApp();
67
+ if (appGuidance?.skill) {
68
+ return appGuidance.skill;
69
+ }
70
+
71
+ return loadSkillText() || "No guidance available.";
72
+ }
73
+
74
+ async function getQuickstartText() {
75
+ const appGuidance = await fetchGuidanceFromApp();
76
+ if (appGuidance?.quickstart) {
77
+ return appGuidance.quickstart;
78
+ }
79
+
80
+ return loadQuickstartText();
81
+ }
82
+
83
+ async function getPromptPreambleText() {
84
+ const appGuidance = await fetchGuidanceFromApp();
85
+ if (appGuidance?.preamble) {
86
+ return appGuidance.preamble;
87
+ }
88
+
89
+ return getPromptPreamble();
37
90
  }
38
91
 
39
92
  function loadQuickstartText() {
@@ -65,7 +118,7 @@ Use MCP tools only.
65
118
  ## Important method patterns
66
119
 
67
120
  - Discover node types: nodeTypes.search, nodeTypes.list, nodeTypes.get
68
- - Inspect graph: nodes.list, nodes.get, nodes.getPorts, wires.getAll, uniforms.list
121
+ - Inspect graph: nodes.list, nodes.getInfo, nodes.getPorts, wires.getAll, uniforms.list
69
122
  - Edit node input values: nodes.edit(nodeId, { inputValues: { PortName: value } })
70
123
  - Wire nodes: wires.create({ from, to }) after inspecting both ports
71
124
  - Validate: ai.runDebugCheck({ includeScreenshot: true })
@@ -86,7 +139,7 @@ function getPromptPreamble() {
86
139
  function getSessionSummary(session) {
87
140
  return {
88
141
  sessionId: session.sessionId,
89
- project: session.project,
142
+ projectName: session.project?.name || "Untitled Shader",
90
143
  connectedAt: session.connectedAt,
91
144
  updatedAt: session.updatedAt,
92
145
  manifestVersion: session.manifest?.version || null,
@@ -170,7 +223,7 @@ function createToolDefinitions() {
170
223
  handler: async () => {
171
224
  const result = {
172
225
  title: "Construct Shader Graph MCP Guidance",
173
- content: loadSkillText(),
226
+ content: await getSkillText(),
174
227
  };
175
228
  return {
176
229
  content: [{ type: "text", text: result.content }],
@@ -188,14 +241,7 @@ function createToolDefinitions() {
188
241
  projects: z.array(
189
242
  z.object({
190
243
  sessionId: z.string(),
191
- project: z.object({
192
- name: z.string(),
193
- version: z.string().optional(),
194
- author: z.string().optional(),
195
- category: z.string().optional(),
196
- description: z.string().optional(),
197
- shaderInfo: z.any().optional(),
198
- }),
244
+ projectName: z.string(),
199
245
  connectedAt: z.string(),
200
246
  updatedAt: z.string(),
201
247
  manifestVersion: z.string().nullable(),
@@ -234,7 +280,7 @@ function createToolDefinitions() {
234
280
  },
235
281
  outputSchema: {
236
282
  sessionId: z.string(),
237
- project: z.any(),
283
+ projectName: z.string(),
238
284
  },
239
285
  },
240
286
  handler: async ({ sessionId }) => {
@@ -242,7 +288,7 @@ function createToolDefinitions() {
242
288
  selectedSessionId = sessionId;
243
289
  const result = {
244
290
  sessionId,
245
- project: session.project,
291
+ projectName: session.project?.name || "Untitled Shader",
246
292
  };
247
293
  return {
248
294
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
@@ -263,7 +309,6 @@ function createToolDefinitions() {
263
309
  },
264
310
  outputSchema: {
265
311
  sessionId: z.string(),
266
- project: z.any(),
267
312
  manifest: z.any(),
268
313
  },
269
314
  },
@@ -273,7 +318,6 @@ function createToolDefinitions() {
273
318
  : ensureSelectedSession();
274
319
  const result = {
275
320
  sessionId: session.sessionId,
276
- project: session.project,
277
321
  manifest: session.manifest,
278
322
  };
279
323
  return {
@@ -304,7 +348,7 @@ function createToolDefinitions() {
304
348
  },
305
349
  outputSchema: {
306
350
  sessionId: z.string(),
307
- project: z.any(),
351
+ // project: z.any(),
308
352
  method: z.string(),
309
353
  args: z.array(z.any()),
310
354
  durationMs: z.number(),
@@ -348,7 +392,7 @@ function registerResources(server) {
348
392
  {
349
393
  uri: uri.href,
350
394
  mimeType: "text/markdown",
351
- text: loadSkillText(),
395
+ text: await getSkillText(),
352
396
  },
353
397
  ],
354
398
  }),
@@ -367,108 +411,7 @@ function registerResources(server) {
367
411
  {
368
412
  uri: uri.href,
369
413
  mimeType: "text/markdown",
370
- text: loadQuickstartText(),
371
- },
372
- ],
373
- }),
374
- );
375
- }
376
-
377
- function registerPrompts(server) {
378
- server.registerPrompt(
379
- "work-with-shader-graph",
380
- {
381
- title: "Work With Shader Graph",
382
- description:
383
- "General prompt for safely inspecting and editing a Construct Shader Graph project.",
384
- argsSchema: z.object({
385
- task: z.string().optional().describe("The user task to accomplish."),
386
- }),
387
- },
388
- ({ task }) => ({
389
- messages: [
390
- {
391
- role: "user",
392
- content: {
393
- type: "text",
394
- text: `${getPromptPreamble()}\n\nFollow the full guidance resource if more detail is needed.\n\nTask: ${task || "Inspect the current project, understand its graph state, and proceed safely."}`,
395
- },
396
- },
397
- ],
398
- }),
399
- );
400
-
401
- server.registerPrompt(
402
- "inspect-graph",
403
- {
404
- title: "Inspect Graph",
405
- description:
406
- "Prompt for safely inspecting the current graph before any edits.",
407
- argsSchema: z.object({
408
- focus: z
409
- .string()
410
- .optional()
411
- .describe(
412
- "Optional area to inspect, like uniforms, preview, or node types.",
413
- ),
414
- }),
415
- },
416
- ({ focus }) => ({
417
- messages: [
418
- {
419
- role: "user",
420
- content: {
421
- type: "text",
422
- text: `${getPromptPreamble()}\n\nInspect the current graph without mutating it. Read nodes, wires, uniforms, shader info, and any relevant settings first. ${focus ? `Focus on: ${focus}.` : ""}`,
423
- },
424
- },
425
- ],
426
- }),
427
- );
428
-
429
- server.registerPrompt(
430
- "edit-graph-safely",
431
- {
432
- title: "Edit Graph Safely",
433
- description: "Prompt for making a small validated graph edit with MCP.",
434
- argsSchema: z.object({
435
- task: z.string().describe("The graph edit to perform."),
436
- }),
437
- },
438
- ({ task }) => ({
439
- messages: [
440
- {
441
- role: "user",
442
- content: {
443
- type: "text",
444
- text: `${getPromptPreamble()}\n\nMake the smallest valid change that satisfies this task: ${task}\n\nBefore wiring, inspect ports. Before choosing a node type, use nodeTypes.search or nodeTypes.list. After each structural edit, re-read affected nodes or ports and validate preview/code if relevant.`,
445
- },
446
- },
447
- ],
448
- }),
449
- );
450
-
451
- server.registerPrompt(
452
- "debug-preview-errors",
453
- {
454
- title: "Debug Preview Errors",
455
- description:
456
- "Prompt for debugging generated code or preview issues in a shader graph project.",
457
- argsSchema: z.object({
458
- issue: z
459
- .string()
460
- .optional()
461
- .describe("Optional description of the observed preview issue."),
462
- }),
463
- },
464
- ({ issue }) => ({
465
- messages: [
466
- {
467
- role: "user",
468
- content: {
469
- type: "text",
470
- text: `${getPromptPreamble()}\n\nDebug the current shader graph by inspecting shader.getGeneratedCode, preview.getErrors, preview settings, node preview, and ai.runDebugCheck. ${issue ? `Observed issue: ${issue}` : ""}`,
471
- },
414
+ text: await getQuickstartText(),
472
415
  },
473
416
  ],
474
417
  }),
@@ -482,7 +425,6 @@ function createLocalServer() {
482
425
  });
483
426
 
484
427
  registerResources(server);
485
- registerPrompts(server);
486
428
  createToolDefinitions().forEach((tool) => {
487
429
  server.registerTool(tool.name, tool.config, tool.handler);
488
430
  });
@@ -697,7 +639,6 @@ function createProxyServer() {
697
639
  });
698
640
 
699
641
  registerResources(server);
700
- registerPrompts(server);
701
642
  createToolDefinitions().forEach((tool) => {
702
643
  server.registerTool(tool.name, tool.config, async (input = {}) => {
703
644
  return callPrimaryTool(tool.name, input);