Summary
An app calls its server's tools by the name the server registered. When the host is connected to an aggregating intermediary (an MCP gateway, proxy, or multi-server bridge) rather than to the server directly, that name has usually been rewritten to keep two servers' tools distinct — and the app has no way to learn the rewritten name. Its tools/call fails.
This is not a hypothetical intermediary: aggregation is a common deployment for MCP, and prefixing tool names is how essentially every aggregator keeps search from one server distinct from search from another.
Observed
Behind a gateway that exposes an upstream's get-time as alpha__get-time:
examples/lazy-auth-server/src/mcp-app.ts is one of the apps in this repository that would hit it — it calls callTool("get_secret") and callTool("revoke_auth_token") with names written into the bundle.
The reference AppBridge forwards an app's tools/call straight through (src/app-bridge.ts, the oncalltool installed in connect), so nothing between the app and the server corrects or rejects the name; the failure surfaces as a server-side error for a tool the app can see listed under a different name.
What already works
An app that reads hostContext.toolInfo.tool.name from the ui/initialize result gets the name the host knows, which is correct through an aggregator. So the gap is specific: an app can always call the tool that opened it, but not any other tool on its own server.
Possible directions
- Document the constraint — apps SHOULD derive names from
hostContext.toolInfo or from tools/list rather than hardcoding them. Cheapest, and it makes existing examples the guidance rather than the counterexample.
- Give the app the callable set at initialize — e.g. the tools of the originating server in
McpUiInitializeResult, which is where the app already receives toolInfo.
- Let the app address tools relative to its own server, leaving the host to map that onto whatever name it holds.
Happy to send a PR for (1) against the examples and the spec text if that is the direction you'd want.
Context
Found while adding MCP Apps support to an MCP gateway. Everything else federated cleanly — _meta.ui survives, and interface resources resolve once the gateway scopes ui:// URIs per server (they are unique only within a server, which is a separate report I can file if useful).
Summary
An app calls its server's tools by the name the server registered. When the host is connected to an aggregating intermediary (an MCP gateway, proxy, or multi-server bridge) rather than to the server directly, that name has usually been rewritten to keep two servers' tools distinct — and the app has no way to learn the rewritten name. Its
tools/callfails.This is not a hypothetical intermediary: aggregation is a common deployment for MCP, and prefixing tool names is how essentially every aggregator keeps
searchfrom one server distinct fromsearchfrom another.Observed
Behind a gateway that exposes an upstream's
get-timeasalpha__get-time:examples/lazy-auth-server/src/mcp-app.tsis one of the apps in this repository that would hit it — it callscallTool("get_secret")andcallTool("revoke_auth_token")with names written into the bundle.The reference
AppBridgeforwards an app'stools/callstraight through (src/app-bridge.ts, theoncalltoolinstalled inconnect), so nothing between the app and the server corrects or rejects the name; the failure surfaces as a server-side error for a tool the app can see listed under a different name.What already works
An app that reads
hostContext.toolInfo.tool.namefrom theui/initializeresult gets the name the host knows, which is correct through an aggregator. So the gap is specific: an app can always call the tool that opened it, but not any other tool on its own server.Possible directions
hostContext.toolInfoor fromtools/listrather than hardcoding them. Cheapest, and it makes existing examples the guidance rather than the counterexample.McpUiInitializeResult, which is where the app already receivestoolInfo.Happy to send a PR for (1) against the examples and the spec text if that is the direction you'd want.
Context
Found while adding MCP Apps support to an MCP gateway. Everything else federated cleanly —
_meta.uisurvives, and interface resources resolve once the gateway scopesui://URIs per server (they are unique only within a server, which is a separate report I can file if useful).