{"record":{"id":"3a9252ef74f0c3ca","repo":"vercel/ai","slug":"no-tools-call-handler-configured","errorCode":null,"errorMessage":"No tools/call handler configured","messagePattern":"No tools/call handler configured","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react/src/mcp-apps/bridge.ts","lineNumber":358,"sourceCode":"  ): Promise<unknown> {\n    switch (request.method) {\n      case 'ui/initialize':\n        return {\n          protocolVersion: MCP_APP_PROTOCOL_VERSION,\n          hostCapabilities: {\n            ...(this.handlers.callTool != null ? { serverTools: {} } : {}),\n            ...(this.handlers.readResource != null\n              ? { serverResources: {} }\n              : {}),\n            ...(this.handlers.onLog != null ? { logging: {} } : {}),\n          },\n          hostInfo: this.hostInfo,\n          hostContext: this.hostContext,\n        };\n\n      case 'tools/call': {\n        if (this.handlers.callTool == null) {\n          throw new Error('No tools/call handler configured');\n        }\n        const params = assertToolCallParams(request.params);\n        // Deny-by-default: the (untrusted) MCP App may only invoke tools the\n        // host has explicitly allow-listed. Omitting `allowedTools` exposes no\n        // tools, rather than forwarding every requested tool to `callTool`.\n        if (\n          this.handlers.allowedTools == null ||\n          !this.handlers.allowedTools.includes(params.name)\n        ) {\n          throw new Error(`Tool is not app-visible: ${params.name}`);\n        }\n        return this.handlers.callTool(params);\n      }\n\n      case 'resources/read':\n        if (this.handlers.readResource == null) {\n          throw new Error('No resources/read handler configured');\n        }","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/react/src/mcp-apps/bridge.ts#L340-L376","documentation":"The iframe app sent a `tools/call` request, but the host bridge was constructed without a `callTool` handler in its `handlers` object. The bridge refuses to proxy the request since there is no host callback to execute it. This is a host configuration error surfaced as a JSON-RPC error to the iframe and to `onError`.","triggerScenarios":"`new MCPAppBridge({ handlers: { ... } })` was called without `callTool`, then the app called `tools/call` (the app may attempt this because `ui/initialize` reports serverTools capability based on handler presence).","commonSituations":"Host intentionally disabled tool access but the app still calls tools; copy-pasted bridge setup omitted `callTool`; conditional handler wiring where the flag was false at mount time.","solutions":["Add a `callTool` handler (and `allowedTools` allow-list) when constructing MCPAppBridge if the app should invoke tools.","If tools should remain unavailable, configure the app to not call tools — the host will never accept them.","Verify handlers were not spread/overridden after bridge construction.","Check `ui/initialize`'s reported capabilities: serverTools is only advertised when `callTool` exists."],"exampleFix":"// before\nconst bridge = new MCPAppBridge({ targetWindow, handlers: { onError: console.error } })\n// after\nconst bridge = new MCPAppBridge({\n  targetWindow,\n  handlers: {\n    allowedTools: ['search'],\n    callTool: params => client.callTool(params),\n    onError: console.error,\n  },\n})","handlingStrategy":"validation","validationCode":"// host-side, at construction time:\nconst bridge = new MCPAppBridge({\n  targetWindow,\n  handlers: {\n    ...(appNeedsTools\n      ? { allowedTools: ['search'], callTool: p => client.callTool(p) }\n      : {}),\n    onError: e => console.error('MCP App bridge error:', e),\n  },\n});\nif (appNeedsTools) console.assert('callTool' in bridgeHandlers, 'callTool handler required');","typeGuard":"function hasCallToolHandler(h: unknown): h is { callTool: (p: any) => unknown } {\n  return typeof h === 'object' && h !== null && 'callTool' in h &&\n    typeof (h as any).callTool === 'function';\n}","tryCatchPattern":"try {\n  await appRequest;\n} catch (error) {\n  if (error instanceof Error && error.message === 'No tools/call handler configured') {\n    console.error('Bridge was built without a callTool handler; add one or stop the app from calling tools');\n  }\n}","preventionTips":["Always configure callTool (plus allowedTools) when embedding apps that invoke tools.","Wire handlers.onError to catch and log bridge errors during development.","Keep handler wiring in one place and assert required keys at startup.","Remember serverTools capability is only advertised when callTool exists — align app expectations with it."],"tags":["mcp-apps","configuration","handler","iframe"],"backgroundTag":"missing-handler-configuration","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}