Skip to content
9 changes: 6 additions & 3 deletions packages/provider-pi/src/server/mcpExtensionSource.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,12 @@ describe("Pi tool discovery permissions", () => {
},
},
};
assert.isUndefined(
await toolCall!({ toolName: "tool_search", input: { query: "preview_snapshot" } }, ctx),
);
for (const builtinPath of ["builtin:tool-search", "<builtin:tool-search>"]) {
searchPath = builtinPath;
assert.isUndefined(
await toolCall!({ toolName: "tool_search", input: { query: "preview_snapshot" } }, ctx),
);
}
assert.equal(confirmations.length, 0);
const result = await toolCall!({ toolName: "mcp__t3-code__preview_snapshot", input: {} }, ctx);
assert.equal(result?.block, true);
Expand Down
4 changes: 3 additions & 1 deletion packages/provider-pi/src/server/mcpExtensionSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,9 +343,11 @@ export default async function t3McpExtension(pi: ExtensionAPI) {
// keep their normal meaning without replacing or shadowing Pi's runtime.
// Only Pi's own search is known to be read-only. An extension that replaces
// it keeps the name, and cannot discover deferred tools either.
// OmO reports Pi's builtin search with angle brackets around the same path.
const BUILTIN_TOOL_SEARCH_PATHS = new Set(["builtin:tool-search", "<builtin:tool-search>"]);
const hasBuiltinToolSearch = () =>
typeof pi.getAllTools === "function" &&
pi.getAllTools().some((tool) => tool.name === "tool_search" && tool.sourceInfo?.path === "builtin:tool-search");
pi.getAllTools().some((tool) => tool.name === "tool_search" && BUILTIN_TOOL_SEARCH_PATHS.has(tool.sourceInfo?.path ?? ""));

const readOnlyMcpTools = new Set<string>();
const isReadOnlyMcpTool = (name: string) => {
Expand Down
Loading