From 8efe8efbc7c3708c15512f4a1ca18f596a0fa067 Mon Sep 17 00:00:00 2001 From: Anna Tchijova Date: Wed, 14 Oct 2026 13:57:48 -0300 Subject: [PATCH] fix(quickstart): resolve host-qualified tool names in callServerTool The quickstart example's callServerTool call hardcodes the literal tool name "get-time" instead of recovering it from getHostContext().toolInfo, so the widget's own follow-up tool calls break under any host that qualifies tool names to avoid collisions across multiple aggregated servers (e.g. "pdf-server-get-time"). Apply the resolveToolName pattern @jcollas proposed in #753 to this example specifically, since docs/quickstart.md embeds it verbatim and it's the template most third-party app authors fork first. The other 14 affected examples listed in #753 share the same root cause and fix shape and are left for a follow-up. docs/quickstart.md is regenerated from the source file via `npm run sync:snippets`, not hand-edited. Closes part of #753 --- docs/quickstart.md | 19 ++++++++++++++++++- examples/quickstart/src/mcp-app.ts | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index 7235ceeda..6068bd479 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -404,10 +404,27 @@ app.ontoolresult = (result) => { serverTimeEl.textContent = time ?? "[ERROR]"; }; +// Recover whatever prefix a multi-server host applied to this app's entry +// tool (e.g. "pdf-server-get-time" behind an aggregator) and reapply it to +// any tool this app calls back into, so callServerTool keeps working once +// the app is no longer connected 1:1 to a single server. +function resolveToolName(baseName: string): string { + const invokedName = app.getHostContext()?.toolInfo?.tool.name; + if (!invokedName) return baseName; + const entryTools = ["get-time"]; + const ownToolName = entryTools.find((t) => invokedName.endsWith(t)); + if (!ownToolName) return baseName; + const prefix = invokedName.slice(0, invokedName.length - ownToolName.length); + return prefix + baseName; +} + // Wire up button click getTimeBtn.addEventListener("click", async () => { // `app.callServerTool()` lets the UI request fresh data from the server - const result = await app.callServerTool({ name: "get-time", arguments: {} }); + const result = await app.callServerTool({ + name: resolveToolName("get-time"), + arguments: {}, + }); const time = result.content?.find((c) => c.type === "text")?.text; serverTimeEl.textContent = time ?? "[ERROR]"; }); diff --git a/examples/quickstart/src/mcp-app.ts b/examples/quickstart/src/mcp-app.ts index 5780bb706..c4d410570 100644 --- a/examples/quickstart/src/mcp-app.ts +++ b/examples/quickstart/src/mcp-app.ts @@ -14,10 +14,27 @@ app.ontoolresult = (result) => { serverTimeEl.textContent = time ?? "[ERROR]"; }; +// Recover whatever prefix a multi-server host applied to this app's entry +// tool (e.g. "pdf-server-get-time" behind an aggregator) and reapply it to +// any tool this app calls back into, so callServerTool keeps working once +// the app is no longer connected 1:1 to a single server. +function resolveToolName(baseName: string): string { + const invokedName = app.getHostContext()?.toolInfo?.tool.name; + if (!invokedName) return baseName; + const entryTools = ["get-time"]; + const ownToolName = entryTools.find((t) => invokedName.endsWith(t)); + if (!ownToolName) return baseName; + const prefix = invokedName.slice(0, invokedName.length - ownToolName.length); + return prefix + baseName; +} + // Wire up button click getTimeBtn.addEventListener("click", async () => { // `app.callServerTool()` lets the UI request fresh data from the server - const result = await app.callServerTool({ name: "get-time", arguments: {} }); + const result = await app.callServerTool({ + name: resolveToolName("get-time"), + arguments: {}, + }); const time = result.content?.find((c) => c.type === "text")?.text; serverTimeEl.textContent = time ?? "[ERROR]"; });