construct-shader-graph-mcp 0.4.0 → 0.6.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 +1 -1
- package/src/guidance/skill.md +2 -2
- package/src/server.mjs +62 -1
package/package.json
CHANGED
package/src/guidance/skill.md
CHANGED
|
@@ -186,8 +186,8 @@ Side-effecting calls:
|
|
|
186
186
|
When the model does not know which node type to use:
|
|
187
187
|
|
|
188
188
|
- Prefer `nodeTypes.search(query)` to search by concept.
|
|
189
|
-
- Use `nodeTypes.list()`
|
|
190
|
-
- Use `nodeTypes.get(typeKey)` to inspect one exact type before creating it.
|
|
189
|
+
- Use `nodeTypes.list()` only for lightweight discovery of available names/categories/tags.
|
|
190
|
+
- Use `nodeTypes.get(typeKey)` to inspect one exact type in full before creating it.
|
|
191
191
|
- Use `nodes.search(query)` as a convenience alias for node type search.
|
|
192
192
|
- Use `uniforms.getNodeTypes()` to discover generated uniform-backed node types.
|
|
193
193
|
- Use `customNodes.list()` to discover reusable custom node definitions already in the project.
|
package/src/server.mjs
CHANGED
|
@@ -22,6 +22,7 @@ let localServer = null;
|
|
|
22
22
|
let bridge = null;
|
|
23
23
|
let controlServer = null;
|
|
24
24
|
let isPrimaryInstance = false;
|
|
25
|
+
let promotionInFlight = null;
|
|
25
26
|
|
|
26
27
|
function log(message, ...args) {
|
|
27
28
|
console.error(`[construct-shader-graph-mcp] ${message}`, ...args);
|
|
@@ -706,7 +707,7 @@ function createProxyServer() {
|
|
|
706
707
|
return server;
|
|
707
708
|
}
|
|
708
709
|
|
|
709
|
-
function
|
|
710
|
+
function callPrimaryToolDirect(tool, input) {
|
|
710
711
|
return new Promise((resolve, reject) => {
|
|
711
712
|
const socket = net.createConnection({
|
|
712
713
|
host: "127.0.0.1",
|
|
@@ -751,6 +752,66 @@ function callPrimaryTool(tool, input) {
|
|
|
751
752
|
});
|
|
752
753
|
}
|
|
753
754
|
|
|
755
|
+
async function tryPromoteToPrimary() {
|
|
756
|
+
if (isPrimaryInstance) return true;
|
|
757
|
+
|
|
758
|
+
// Deduplicate concurrent promotion attempts
|
|
759
|
+
if (promotionInFlight) return promotionInFlight;
|
|
760
|
+
|
|
761
|
+
promotionInFlight = (async () => {
|
|
762
|
+
try {
|
|
763
|
+
await startPrimaryBackend();
|
|
764
|
+
log("promoted to primary instance");
|
|
765
|
+
return true;
|
|
766
|
+
} catch (err) {
|
|
767
|
+
if (err?.code === "EADDRINUSE") {
|
|
768
|
+
log("promotion failed: another primary appeared");
|
|
769
|
+
} else {
|
|
770
|
+
log("promotion failed:", err.message);
|
|
771
|
+
}
|
|
772
|
+
// Reset partial state
|
|
773
|
+
isPrimaryInstance = false;
|
|
774
|
+
localServer = null;
|
|
775
|
+
bridge = null;
|
|
776
|
+
controlServer = null;
|
|
777
|
+
return false;
|
|
778
|
+
} finally {
|
|
779
|
+
promotionInFlight = null;
|
|
780
|
+
}
|
|
781
|
+
})();
|
|
782
|
+
|
|
783
|
+
return promotionInFlight;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function executeToolLocally(toolName, input) {
|
|
787
|
+
const tool = createToolDefinitions().find((t) => t.name === toolName);
|
|
788
|
+
if (!tool) throw new Error(`Unknown tool '${toolName}'`);
|
|
789
|
+
return tool.handler(input || {});
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
async function callPrimaryTool(toolName, input) {
|
|
793
|
+
// If we're already promoted, go local
|
|
794
|
+
if (isPrimaryInstance) {
|
|
795
|
+
return executeToolLocally(toolName, input);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
try {
|
|
799
|
+
return await callPrimaryToolDirect(toolName, input);
|
|
800
|
+
} catch (error) {
|
|
801
|
+
// If connection refused, the primary is gone — try to take over
|
|
802
|
+
if (error?.code === "ECONNREFUSED") {
|
|
803
|
+
log("primary unreachable, attempting promotion...");
|
|
804
|
+
const promoted = await tryPromoteToPrimary();
|
|
805
|
+
if (promoted) {
|
|
806
|
+
return executeToolLocally(toolName, input);
|
|
807
|
+
}
|
|
808
|
+
// Another primary appeared while we promoted — retry via proxy
|
|
809
|
+
return callPrimaryToolDirect(toolName, input);
|
|
810
|
+
}
|
|
811
|
+
throw error;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
754
815
|
async function ensureBackend() {
|
|
755
816
|
try {
|
|
756
817
|
await startPrimaryBackend();
|