-
Notifications
You must be signed in to change notification settings - Fork 59
spec: Add tool registration for Apps, to be called by Host (WebMCP-style!) #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This PR adds comprehensive tool support for MCP Apps, enabling apps to register their own tools and handle tool calls from the host. - Add `registerTool()` method for registering tools with input/output schemas - Add `oncalltool` setter for handling tool call requests from host - Add `onlisttools` setter for handling tool list requests from host - Add `sendToolListChanged()` for notifying host of tool updates - Registered tools support enable/disable/update/remove operations - Add `sendCallTool()` method for calling tools on the app - Add `sendListTools()` method for listing available app tools - Fix: Use correct ListToolsResultSchema (was ListToolsRequestSchema) - Add comprehensive tests for tool registration lifecycle - Add tests for input/output schema validation - Add tests for bidirectional tool call communication - Add tests for tool list change notifications - All 27 tests passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Implement automatic `oncalltool` and `onlisttools` handlers that are initialized when apps register tools. This removes the need for manual handler setup and ensures tools work seamlessly out of the box. - Add automatic `oncalltool` handler that routes calls to registered tools - Add automatic `onlisttools` handler that returns full Tool objects with JSON schemas - Convert Zod schemas to MCP-compliant JSON Schema using `zod-to-json-schema` - Add 27 comprehensive tests covering automatic handlers and tool lifecycle - Test coverage includes error handling, schema validation, and multi-app isolation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Always return inputSchema as object (never undefined) - Keep filter for enabled tools only in list - Update test to match behavior (only enabled tools in list) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1dba38b to
55ad06a
Compare
| const tool2 = app.registerTool("tool2", {}, async (_args: any) => ({ | ||
| content: [], | ||
| })); | ||
| const tool3 = app.registerTool("tool3", {}, async (_args: any) => ({ |
| const appCapabilities = { tools: { listChanged: true } }; | ||
| app = new App(testAppInfo, appCapabilities, { autoResize: false }); | ||
|
|
||
| const tool1 = app.registerTool( |
@modelcontextprotocol/ext-apps
@modelcontextprotocol/server-basic-react
@modelcontextprotocol/server-basic-vanillajs
@modelcontextprotocol/server-budget-allocator
@modelcontextprotocol/server-cohort-heatmap
@modelcontextprotocol/server-customer-segmentation
@modelcontextprotocol/server-scenario-modeler
@modelcontextprotocol/server-system-monitor
@modelcontextprotocol/server-threejs
@modelcontextprotocol/server-wiki-explorer
commit: |
Avoid double-verb naming pattern for consistency with existing API.
|
How should it would if I'm in a chat and have multiple MCP apps currently visible, and they register the same tool? Does the host send tool calls to most recent one? (If so is there a way to signal to the older app that it can no longer receive tool calls?) I think I'm also not clear on the lifetime of apps. Currently in the spec there is no specific bounds on the lifetime of the MCP apps. For VS Code, we implement virtualization and so an app is not loaded if the user has it scrolled out of the viewport. But now we need to actively keep app apps alive for some amount of time (forever?) in case a model decides to later call them. For long chat sessions this could get quite expensive. I think #125 is a simpler approach that should cover the bases here without introducing lifetime concerns |
Summary
This PR enables Apps to register their own tools that agents can call, making apps introspectable and accessible to the model without DOM parsing.
Apps expose semantic interfaces (state queries, operations) via standard MCP tools. The agent discovers capabilities via
tools/list, queries state, and drives interactions.This is a different model from other approaches where apps keep the model informed through side channels (e.g., OAI Apps SDK sending widget state changes to the model, MCP-UI adding tool call results to chat history). Instead, the agent actively queries app state and executes operations through tools.
Example:
Agent interaction:
Changes
App side (
app.ts)registerTool()- Register tools with Zod validationoncalltool/onlisttools- Handle tool requestssendToolListChanged()- Notify on tool updatesenable(),disable(),update(),remove()Host side (
app-bridge.ts)sendCallTool()- Call app toolssendListTools()- List app toolsListToolsResultSchemaCapabilities (
types.ts)tools: { listChanged?: boolean }serverTools: { listChanged?: boolean }(existing)Tests: ✓ 27 passing, 100% coverage
Design
Reuses standard MCP messages:
tools/call,tools/list,notifications/tools/list_changedSimilar to WebMCP but without turning the App (embedded page) into an MCP server - apps register tools within the App/Host architecture.
Lifecycle: App tools exist only while app loaded (ephemeral, sandboxed)
Separation: Server tools (persistent, trusted) vs App tools (ephemeral, sandboxed)
Breaking Changes
None. Purely additive.
Related
Implements the gist of #35 (WebMCP-style tool registration) while preserving the App/Host architecture.
🤖 Generated with Claude Code