comfyui-mcp 0.50.65 → 0.50.67

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/README.md CHANGED
@@ -797,7 +797,6 @@ src/
797
797
  model-resolver.ts # HuggingFace search, local models, downloads
798
798
  generation-tracker.ts # SQLite generation log, settings dedup, stats
799
799
  file-hasher.ts # SHA256 hashing of .safetensors with cache
800
- civitai-lookup.ts # CivitAI API lookup by content hash
801
800
  workflow-settings-extractor.ts # Extract settings from workflow JSON
802
801
  process-control.ts # Stop, start, restart ComfyUI process
803
802
  registry-client.ts # ComfyUI Registry API
@@ -47,11 +47,16 @@ export function identityReason(tabId, origin, workflowUuid, failure) {
47
47
  return ambiguousTurn(tabId, "no single tab's identity could be read");
48
48
  }
49
49
  if (!origin) {
50
+ // The relay case USED to land here and was told, correctly at the time, that
51
+ // its problem was permanent. It no longer is: the relay path now supplies the
52
+ // origin it already knows from COMFYUI_URL, so a relay session adopts fences
53
+ // like any other. Naming a fixed cause as the "known case" would send a
54
+ // reader to change a backend that is no longer the reason (#1077).
50
55
  return (`this tab's connection carries no server-observed Origin, and the workflow identity is ` +
51
- `bound to one — so the fence can never be adopted for it. This is structural, not ` +
52
- `transient: refreshing the tab will not change it. Relay-backend connections ` +
53
- `(COMFYUI_MCP_TUNNEL_BACKEND=relay) are the known case, because the relay protocol does ` +
54
- `not forward the browser's handshake Origin.`);
56
+ `bound to one — so the fence cannot be adopted for it. Refreshing the tab will not ` +
57
+ `change it. This means the connection reached the orchestrator by a path that neither ` +
58
+ `observed nor was told the panel's origin; if COMFYUI_URL is unset or unparseable for ` +
59
+ `this session, setting it to the URL the panel is served from is what supplies it.`);
55
60
  }
56
61
  return (`the workflow identity did not validate (uuid ${String(workflowUuid)} against origin ` +
57
62
  `${origin}) — a malformed uuid, or one bound to a different origin.`);
@@ -1 +1 @@
1
- {"version":3,"file":"fence-refusal.js","sourceRoot":"","sources":["../../src/orchestrator/fence-refusal.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,yEAAyE;AACzE,2DAA2D;AAC3D,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,4EAA4E;AAC5E,0DAA0D;AAC1D,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,uEAAuE;AACvE,6EAA6E;AAC7E,+EAA+E;AAC/E,sEAAsE;AACtE,4EAA4E;AAM5E,4EAA4E;AAC5E,SAAS,aAAa,CAAC,KAAa,EAAE,IAAY;IAChD,OAAO,CACL,2DAA2D,IAAI,SAAS,KAAK,eAAe;QAC5F,2EAA2E;QAC3E,mFAAmF;QACnF,+DAA+D,CAChE,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,OAAuB;IACtE,IAAI,OAAO,KAAK,WAAW;QAAE,OAAO,aAAa,CAAC,KAAK,EAAE,oCAAoC,CAAC,CAAC;IAC/F,OAAO,mBAAmB,KAAK,wDAAwD,CAAC;AAC1F,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,GAAG,KAAK,iFAAiF,CAAC;AACnG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,MAA0B,EAC1B,YAAqB,EACrB,OAAuB;IAEvB,IAAI,CAAC,MAAM,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QACvC,OAAO,aAAa,CAAC,KAAK,EAAE,wCAAwC,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CACL,wFAAwF;YACxF,mFAAmF;YACnF,8EAA8E;YAC9E,yFAAyF;YACzF,6CAA6C,CAC9C,CAAC;IACJ,CAAC;IACD,OAAO,CACL,gDAAgD,MAAM,CAAC,YAAY,CAAC,kBAAkB;QACtF,GAAG,MAAM,2DAA2D,CACrE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"fence-refusal.js","sourceRoot":"","sources":["../../src/orchestrator/fence-refusal.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,yEAAyE;AACzE,2DAA2D;AAC3D,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,4EAA4E;AAC5E,0DAA0D;AAC1D,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,uEAAuE;AACvE,6EAA6E;AAC7E,+EAA+E;AAC/E,sEAAsE;AACtE,4EAA4E;AAM5E,4EAA4E;AAC5E,SAAS,aAAa,CAAC,KAAa,EAAE,IAAY;IAChD,OAAO,CACL,2DAA2D,IAAI,SAAS,KAAK,eAAe;QAC5F,2EAA2E;QAC3E,mFAAmF;QACnF,+DAA+D,CAChE,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,OAAuB;IACtE,IAAI,OAAO,KAAK,WAAW;QAAE,OAAO,aAAa,CAAC,KAAK,EAAE,oCAAoC,CAAC,CAAC;IAC/F,OAAO,mBAAmB,KAAK,wDAAwD,CAAC;AAC1F,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,GAAG,KAAK,iFAAiF,CAAC;AACnG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,MAA0B,EAC1B,YAAqB,EACrB,OAAuB;IAEvB,IAAI,CAAC,MAAM,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QACvC,OAAO,aAAa,CAAC,KAAK,EAAE,wCAAwC,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,6EAA6E;QAC7E,8EAA8E;QAC9E,6EAA6E;QAC7E,wEAAwE;QACxE,mEAAmE;QACnE,OAAO,CACL,wFAAwF;YACxF,oFAAoF;YACpF,uFAAuF;YACvF,uFAAuF;YACvF,mFAAmF,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,CACL,gDAAgD,MAAM,CAAC,YAAY,CAAC,kBAAkB;QACtF,GAAG,MAAM,2DAA2D,CACrE,CAAC;AACJ,CAAC"}
@@ -714,7 +714,10 @@ function isLoopbackHostName(host) {
714
714
  }
715
715
  /** The scheme://host:port origin of a URL (default ports made explicit), or null if
716
716
  * unparseable. Loopback hosts canonicalize to their FAMILY loopback (v4 → 127.0.0.1,
717
- * v6 → ::1) — so localhost/127.0.0.1/0.0.0.0 compare equal, and ::1/:: compare equal,
717
+ * v6 → ::1) — so 127.0.0.1/0.0.0.0 compare equal, and ::1/:: compare equal. NOTE:
718
+ * `localhost` is deliberately NOT folded (loopbackFamily returns null for it), so it
719
+ * compares UNEQUAL to a concrete literal — callers that would harm a user by treating
720
+ * that as proof of difference must degrade it to "unknown" themselves (#1233),
718
721
  * but a v4 host and a v6 host DIFFER (they may be different instances). Ports differ. */
719
722
  function httpOriginOf(rawUrl) {
720
723
  try {
@@ -1002,14 +1005,50 @@ async function probeDeclineRecovery(base, windowMs, intervalMs, probeTimeoutMs,
1002
1005
  *
1003
1006
  * Pure, so the three-way decision is testable without a live panel.
1004
1007
  */
1005
- export function restartTimeoutFallbackAdvice({ headlessBase, panelBase, }) {
1008
+ export function restartTimeoutFallbackAdvice({ headlessBase, panelBase, observedOrigin = null, }) {
1006
1009
  if (panelBase != null && sameHttpBase(headlessBase, panelBase)) {
1007
1010
  return "or use restart_comfyui to restart the server directly without a panel card.";
1008
1011
  }
1009
- if (panelBase != null) {
1012
+ // Proven different: either the proof resolved a base that differs, or the observed
1013
+ // origin — which the browser sets and page JS cannot forge — differs outright.
1014
+ // ORIGIN-only compare for the raw Origin, deliberately. `tabServerOrigin` is pathless
1015
+ // (scheme+host+port — the browser sends no path on a WS upgrade), while `headlessBase`
1016
+ // may carry a basePath mount such as :8188/comfy. A path-AWARE compare therefore reads
1017
+ // a correctly-mounted install as a mismatch and fires the strong warning at a server
1018
+ // that IS the right one — the cry-wolf failure this branch exists to avoid, which is
1019
+ // how it was found. A pathless Origin can prove a different host:port; it cannot prove
1020
+ // a different path, so it is only ever used for the claim it can actually support.
1021
+ // (captureRebootHealthBase fails closed on the same ambiguity for the same reason.)
1022
+ // #1233 (codex) — a DNS-ambiguous `localhost` on EITHER side is NOT proof of a
1023
+ // different server. loopbackFamily() deliberately excludes it (a coordinator P0: it
1024
+ // can resolve to either family, or to something else entirely), so `localhost:8188`
1025
+ // vs `127.0.0.1:8188` canonicalizes unequal and would fire the strong warning at what
1026
+ // is very likely the same instance. Absence of proof is not proof of difference, so
1027
+ // an ambiguous host degrades to UNPROVEN — the same direction captureRebootHealthBase
1028
+ // takes for the same input.
1029
+ const dnsAmbiguous = (u) => {
1030
+ if (!u)
1031
+ return false;
1032
+ try {
1033
+ return new URL(u).hostname.toLowerCase().replace(/^\[|\]$/g, "") === "localhost";
1034
+ }
1035
+ catch {
1036
+ return false;
1037
+ }
1038
+ };
1039
+ const originMismatch = observedOrigin != null &&
1040
+ !dnsAmbiguous(observedOrigin) &&
1041
+ !dnsAmbiguous(headlessBase) &&
1042
+ !sameHttpOrigin(headlessBase, observedOrigin)
1043
+ ? observedOrigin
1044
+ : null;
1045
+ const proven = panelBase ?? originMismatch;
1046
+ if (proven != null) {
1010
1047
  return (`Do NOT reach for restart_comfyui here without checking: it targets ${headlessBase}, ` +
1011
- `while this panel is running inside ${panelBase}. Restarting the first would hit a ` +
1012
- "different server than the one you have been working on and may find nothing there at all.");
1048
+ `while this panel is running inside ${proven}. Restarting the first would hit a ` +
1049
+ "different server than the one you have been working on. That may find nothing there " +
1050
+ "at all — or it may SUCCEED and take down a ComfyUI you did not mean to touch, which " +
1051
+ "on a shared instance is the worse outcome.");
1013
1052
  }
1014
1053
  return (`or use restart_comfyui, which restarts ${headlessBase} directly without a panel ` +
1015
1054
  "card — check that this is the same ComfyUI you have been working on, since I " +
@@ -8100,6 +8139,9 @@ export function buildPanelToolDefs() {
8100
8139
  const fallback = restartTimeoutFallbackAdvice({
8101
8140
  headlessBase: getComfyUIBaseUrl(),
8102
8141
  panelBase: captureRebootHealthBase(ctx),
8142
+ // #1233 — the raw observed origin, so a CONFIRMED mismatch is not lost inside
8143
+ // the proof's null. Server-observed on the WS upgrade; page JS cannot forge it.
8144
+ observedOrigin: ctx.bridge?.tabServerOrigin?.(ctx.tabId) ?? null,
8103
8145
  });
8104
8146
  return ok(`No confirmation received within ${Math.round(confirmBudget / 1000)}s, so I did NOT ` +
8105
8147
  "restart ComfyUI. The panel tab may be backgrounded or still reconnecting after a " +