{"record":{"id":"118b71a3667ce01f","repo":"vercel/ai","slug":"tool-is-not-app-visible-params-name","errorCode":null,"errorMessage":"Tool is not app-visible: ${params.name}","messagePattern":"Tool is not app-visible: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react/src/mcp-apps/bridge.ts","lineNumber":368,"sourceCode":"            ...(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        }\n        return this.handlers.readResource(\n          assertResourceReadParams(request.params),\n        );\n\n      case 'resources/list':\n        if (this.handlers.listResources == null) {\n          throw new Error('No resources/list handler configured');\n        }\n        return this.handlers.listResources(request.params);\n","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/react/src/mcp-apps/bridge.ts#L350-L386","documentation":"The MCP Apps bridge is deny-by-default: an app iframe may only invoke tools explicitly listed in the host's `allowedTools` array. This error is thrown when the app requests a tool that either is not in `allowedTools` or when `allowedTools` was omitted entirely (which exposes no tools). It prevents untrusted frames from invoking arbitrary server tools.","triggerScenarios":"The iframe calls `tools/call` with `name: 'deleteUser'` but the host configured `allowedTools: ['search']`; or the host never set `allowedTools`, so every tool call is rejected.","commonSituations":"New tool added to the app but not added to the host allow-list; tool renamed in the app while the allow-list kept the old name; developer assumed tools were exposed by default and omitted `allowedTools`; case-sensitivity mismatch between tool names.","solutions":["Add the requested tool's exact name to `handlers.allowedTools` in the MCPAppBridge configuration.","Remember that omitting `allowedTools` exposes zero tools — you must opt in explicitly.","Verify the tool name string matches exactly (case, spacing) between app and allow-list.","If the tool should not be app-visible, fix the app to use an allow-listed tool instead."],"exampleFix":"// before\nhandlers: { allowedTools: ['search'], callTool: p => client.callTool(p) }\n// after\nhandlers: { allowedTools: ['search', 'refreshDashboardData'], callTool: p => client.callTool(p) }","handlingStrategy":"validation","validationCode":"// host-side, before constructing the bridge, keep allow-list in sync with the app:\nconst APP_VISIBLE_TOOLS = ['search', 'refreshDashboardData'] as const;\nconst handlers = {\n  allowedTools: [...APP_VISIBLE_TOOLS],\n  callTool: (params: { name: string }) => {\n    if (!(APP_VISIBLE_TOOLS as readonly string[]).includes(params.name)) {\n      throw new Error(`Tool ${params.name} not exposed to apps`);\n    }\n    return client.callTool(params);\n  },\n};","typeGuard":"function isAllowedTool(name: string, allowedTools: string[] | undefined): boolean {\n  return allowedTools != null && allowedTools.includes(name);\n}","tryCatchPattern":"try {\n  await callTool({ name: toolName, arguments });\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('Tool is not app-visible:')) {\n    const tool = error.message.split(': ')[1];\n    console.warn(`Tool \"${tool}\" is not in handlers.allowedTools; add it to expose it to the app`);\n  }\n}","preventionTips":["Every tool the app should invoke must appear verbatim in handlers.allowedTools — omitting allowedTools exposes none.","Keep the allow-list in a shared constant synced with the app's tool manifest.","Update the allow-list whenever tools are added or renamed.","Watch tool-name casing and whitespace; matches are exact."],"tags":["mcp-apps","security","allowlist","authorization","iframe"],"backgroundTag":"tool-not-allowlisted","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}