modelcontextprotocol / modelcontextprotocol/ext-apps
Apps cannot call their server's tools through a namespacing aggregator
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 387
- Avg merge
- 3h 21m
- Merged PRs (30d)
- 6
Description
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:
// what the app sends (AppBridge forwards it verbatim to the server)
{"method":"tools/call","params":{"name":"get-time"}}
// what comes back
{"error":{"code":-32043,"message":"unknown name \"get-time\": no upstream owns this namespace"}}
// what the model uses, from the same tools/list the host holds
{"method":"tools/call","params":{"name":"alpha__get-time"}} → ok
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.toolInfoor fromtools/listrather 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 receivestoolInfo. - 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).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/app-bridge.ts, especially the oncalltool handler installed in connect, and inspect examples/lazy-auth-server/src/mcp-app.ts for hardcoded tool calls. Compare those paths with the hostContext.toolInfo and ui/initialize behavior described in the issue. Done requires an agreed direction, then corresponding specification, example, or implementation changes that let apps call tools through a namespacing aggregator.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100