From 742d47fe711e4d22e919f09c0cc239ad9120df3f Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 2 Jul 2026 22:14:26 +0200 Subject: [PATCH] fix(browser-tools): restore MCP-compatible outputs Browser tools were registering union output schemas that the MCP SDK could not validate at call time. Use raw object output shapes and cover the real tools/call boundary. --- .../src/server/agent/mcp-server.test.ts | 144 ++++++++++++++++ .../server/src/server/agent/mcp-server.ts | 38 +---- .../server/src/server/agent/tools/types.ts | 2 +- .../src/server/browser-tools/tools.test.ts | 51 ------ .../server/src/server/browser-tools/tools.ts | 154 +++++------------- 5 files changed, 191 insertions(+), 198 deletions(-) diff --git a/packages/server/src/server/agent/mcp-server.test.ts b/packages/server/src/server/agent/mcp-server.test.ts index 871503eaf..3ed596563 100644 --- a/packages/server/src/server/agent/mcp-server.test.ts +++ b/packages/server/src/server/agent/mcp-server.test.ts @@ -1,4 +1,6 @@ import { execFileSync } from "node:child_process"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; import { describe, expect, it, vi } from "vitest"; import { realpathSync, rmSync } from "node:fs"; import { access, mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; @@ -13,6 +15,7 @@ import { AgentManager, type ManagedAgent } from "./agent-manager.js"; import { AgentStorage, type StoredAgentRecord } from "./agent-storage.js"; import { createTestAgentClients } from "../test-utils/fake-agent-client.js"; import type { AgentMode, AgentProvider, ProviderSnapshotEntry } from "./agent-sdk-types.js"; +import type { ProviderSnapshotManager } from "./provider-snapshot-manager.js"; import { createProviderSnapshotManagerStub } from "../test-utils/session-stubs.js"; import { AgentListItemPayloadSchema, @@ -36,6 +39,8 @@ import { WorkspaceGitServiceImpl } from "../workspace-git-service.js"; import type { GitHubService } from "../../services/github-service.js"; import type { TerminalManager } from "../../terminal/terminal-manager.js"; import { PARENT_AGENT_ID_LABEL } from "@getpaseo/protocol/agent-labels"; +import type { BrowserToolsBroker, BrowserToolsExecuteInput } from "../browser-tools/broker.js"; +import type { BrowserToolsResponsePayload } from "../browser-tools/errors.js"; const REPO_CWD = resolvePath("/tmp/repo"); const TARGET_CWD = resolvePath("/tmp/target"); @@ -487,6 +492,77 @@ function createGitHubServiceStub(): GitHubService { }; } +class FakeBrowserToolsBroker { + public readonly calls: BrowserToolsExecuteInput[] = []; + + public constructor(private readonly response: BrowserToolsResponsePayload) {} + + public async execute(input: BrowserToolsExecuteInput): Promise { + this.calls.push(input); + return this.response; + } +} + +class BoundaryAgentManagerFake { + private readonly agent = createManagedAgent({ + id: "agent-1", + cwd: REPO_CWD, + workspaceId: BROWSER_WORKSPACE_ID, + }); + + public getAgent(agentId: string): ManagedAgent | null { + return agentId === this.agent.id ? this.agent : null; + } + + public listAgents(): ManagedAgent[] { + return []; + } +} + +class BoundaryAgentStorageFake { + public async list(): Promise { + return []; + } +} + +class BoundaryProviderSnapshotManagerFake { + public listRegisteredProviderIds(): AgentProvider[] { + return []; + } + + public hasProvider(): boolean { + return false; + } + + public getProviderLabel(provider: AgentProvider): string { + return provider; + } + + public async listProviders(): Promise { + return []; + } + + public async getProvider(): Promise { + throw new Error("Provider catalog is not used by this boundary test"); + } + + public async listModels(): Promise<[]> { + return []; + } + + public async listModes(): Promise<[]> { + return []; + } +} + +async function connectInMemoryMcpClient(server: Awaited>) { + const client = new Client({ name: "paseo-test-client", version: "0.0.0" }); + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + await server.connect(serverTransport); + await client.connect(clientTransport); + return client; +} + function createStoredSchedule(input: CreateScheduleInput): StoredSchedule { const now = "2026-04-11T00:00:00.000Z"; return { @@ -582,6 +658,74 @@ function createPaseoWorktreeForMcpTest(options: { describe("browser MCP tools", () => { const logger = createTestLogger(); + it("calls registered tools through the MCP SDK with listed output schemas", async () => { + const agentManager = new BoundaryAgentManagerFake(); + const agentStorage = new BoundaryAgentStorageFake(); + const broker = new FakeBrowserToolsBroker({ + requestId: "req-browser-tabs", + ok: true, + result: { command: "list_tabs", tabs: [] }, + }); + const server = await createAgentMcpServer({ + agentManager: agentManager as AgentManager, + agentStorage: agentStorage as AgentStorage, + providerSnapshotManager: + new BoundaryProviderSnapshotManagerFake() as unknown as ProviderSnapshotManager, + browserToolsBroker: broker as BrowserToolsBroker, + callerAgentId: "agent-1", + logger, + }); + const client = await connectInMemoryMcpClient(server); + + try { + const browserResult = await client.callTool({ + name: "browser_list_tabs", + arguments: {}, + }); + const listAgentsResult = await client.callTool({ + name: "list_agents", + arguments: {}, + }); + + expect(broker.calls).toEqual([ + { + agentId: "agent-1", + cwd: REPO_CWD, + workspaceId: BROWSER_WORKSPACE_ID, + command: { command: "list_tabs", args: {} }, + }, + ]); + expect(browserResult.isError).not.toBe(true); + expect(browserResult.structuredContent).toEqual({ + ok: true, + result: { command: "list_tabs", tabs: [] }, + context: { agentId: "agent-1", cwd: REPO_CWD, workspaceId: BROWSER_WORKSPACE_ID }, + }); + expect(listAgentsResult.isError).not.toBe(true); + expect(listAgentsResult.structuredContent).toEqual({ + agents: [], + }); + + const listedTools = await client.listTools(); + const toolsByName = new Map(listedTools.tools.map((tool) => [tool.name, tool])); + const registeredTools = Reflect.get(server, "_registeredTools") as Record< + string, + RegisteredMcpTool + >; + + for (const [name, tool] of Object.entries(registeredTools)) { + if (tool.outputSchema !== undefined) { + expect(toolsByName.get(name)?.outputSchema, `${name} outputSchema`).toEqual( + expect.objectContaining({ type: "object" }), + ); + } + } + } finally { + await client.close(); + await server.close(); + } + }); + it("keeps browser tools registered when browser tools are disabled", async () => { const { agentManager, agentStorage, spies } = createTestDeps(); spies.agentManager.getAgent.mockReturnValue({ diff --git a/packages/server/src/server/agent/mcp-server.ts b/packages/server/src/server/agent/mcp-server.ts index 5e9204b77..684cd4414 100644 --- a/packages/server/src/server/agent/mcp-server.ts +++ b/packages/server/src/server/agent/mcp-server.ts @@ -5,7 +5,6 @@ import type { ServerNotification, ServerRequest, } from "@modelcontextprotocol/sdk/types.js"; -import { z } from "zod"; import { createPaseoToolCatalog, type PaseoToolHostDependencies } from "./tools/paseo-tools.js"; import type { PaseoToolResult } from "./tools/types.js"; @@ -14,39 +13,6 @@ export type AgentMcpServerOptions = PaseoToolHostDependencies; type McpToolContext = RequestHandlerExtra; -function isZodSchema(value: unknown): value is z.ZodType { - return ( - typeof value === "object" && - value !== null && - typeof (value as { safeParseAsync?: unknown }).safeParseAsync === "function" - ); -} - -function relaxMcpOutputSchema(outputSchema: unknown): unknown { - if (!outputSchema) { - return outputSchema; - } - - if (isZodSchema(outputSchema)) { - return outputSchema instanceof z.ZodObject ? outputSchema.passthrough() : outputSchema; - } - - return z.object(outputSchema as z.ZodRawShape).passthrough(); -} - -function relaxMcpToolOutputSchema( - config: TConfig, -): TConfig { - if (config.outputSchema === undefined) { - return config; - } - - return { - ...config, - outputSchema: relaxMcpOutputSchema(config.outputSchema), - } as TConfig; -} - function formatStructuredContentForModel(structuredContent: unknown): string { if ( !structuredContent || @@ -115,12 +81,12 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom for (const tool of catalog.tools.values()) { server.registerTool( tool.name, - relaxMcpToolOutputSchema({ + { title: tool.title, description: tool.description, inputSchema: tool.inputSchema, outputSchema: tool.outputSchema, - }), + }, async (args: unknown, context?: McpToolContext) => toMcpToolResult(await catalog.executeTool(tool.name, args, { signal: context?.signal })), ); diff --git a/packages/server/src/server/agent/tools/types.ts b/packages/server/src/server/agent/tools/types.ts index 593f912d7..181eed106 100644 --- a/packages/server/src/server/agent/tools/types.ts +++ b/packages/server/src/server/agent/tools/types.ts @@ -14,7 +14,7 @@ export interface PaseoToolConfig { title?: string; description?: string; inputSchema?: z.ZodRawShape | z.ZodType; - outputSchema?: z.ZodRawShape | z.ZodType; + outputSchema?: z.ZodRawShape; } export interface PaseoToolDefinition extends PaseoToolConfig { diff --git a/packages/server/src/server/browser-tools/tools.test.ts b/packages/server/src/server/browser-tools/tools.test.ts index 94a4ee154..7d697d361 100644 --- a/packages/server/src/server/browser-tools/tools.test.ts +++ b/packages/server/src/server/browser-tools/tools.test.ts @@ -68,10 +68,6 @@ class BrowserToolHarness { return this.get(name).handler(parsed, {}); } - public outputParses(name: string, output: unknown) { - return schemaFor(this.get(name).config.outputSchema).safeParse(output); - } - private get(name: string): RegisteredTool { const tool = this.tools.get(name); if (!tool) { @@ -739,53 +735,6 @@ describe("registerBrowserTools", () => { }); }); - test("new tab declares the shape it returns", async () => { - const harness = new BrowserToolHarness(); - harness.broker.setResponse(newTabPayload()); - - const response = await harness.execute("browser_new_tab", {}); - - expect(harness.outputParses("browser_new_tab", response.structuredContent)).toEqual({ - success: true, - data: response.structuredContent, - }); - }); - - test("list tabs declares the shape it returns", async () => { - const harness = new BrowserToolHarness(); - - const response = await harness.execute("browser_list_tabs", {}); - - expect(harness.outputParses("browser_list_tabs", response.structuredContent)).toEqual({ - success: true, - data: response.structuredContent, - }); - }); - - test("snapshot declares the shape it returns", async () => { - const harness = new BrowserToolHarness(); - harness.broker.setResponse(snapshotPayload()); - - const response = await harness.execute("browser_snapshot", { browserId: BROWSER_ID }); - - expect(harness.outputParses("browser_snapshot", response.structuredContent)).toEqual({ - success: true, - data: response.structuredContent, - }); - }); - - test("screenshot declares the shape it returns", async () => { - const harness = new BrowserToolHarness(); - harness.broker.setResponse(screenshotPayload()); - - const response = await harness.execute("browser_screenshot", { browserId: BROWSER_ID }); - - expect(harness.outputParses("browser_screenshot", response.structuredContent)).toEqual({ - success: true, - data: response.structuredContent, - }); - }); - test("snapshot rejects calls without a browser id", () => { const harness = new BrowserToolHarness(); diff --git a/packages/server/src/server/browser-tools/tools.ts b/packages/server/src/server/browser-tools/tools.ts index 6e3b612fa..e1f6423c1 100644 --- a/packages/server/src/server/browser-tools/tools.ts +++ b/packages/server/src/server/browser-tools/tools.ts @@ -1,36 +1,5 @@ import { z } from "zod"; -import { - BrowserAutomationBackResultSchema, - BrowserAutomationBrowserIdSchema, - BrowserAutomationCheckResultSchema, - BrowserAutomationClearResultSchema, - BrowserAutomationClickResultSchema, - BrowserAutomationDownloadResultSchema, - BrowserAutomationDragResultSchema, - BrowserAutomationEnvironmentResultSchema, - BrowserAutomationErrorSchema, - BrowserAutomationFillResultSchema, - BrowserAutomationFocusResultSchema, - BrowserAutomationForwardResultSchema, - BrowserAutomationFullPageScreenshotResultSchema, - BrowserAutomationHoverResultSchema, - BrowserAutomationKeypressResultSchema, - BrowserAutomationListTabsResultSchema, - BrowserAutomationLogsResultSchema, - BrowserAutomationNavigateResultSchema, - BrowserAutomationNewTabResultSchema, - BrowserAutomationPageInfoResultSchema, - BrowserAutomationPdfResultSchema, - BrowserAutomationReloadResultSchema, - BrowserAutomationScreenshotResultSchema, - BrowserAutomationSelectResultSchema, - BrowserAutomationSetBackgroundResultSchema, - BrowserAutomationSnapshotResultSchema, - BrowserAutomationStorageResultSchema, - BrowserAutomationTypeResultSchema, - BrowserAutomationUploadResultSchema, - BrowserAutomationWaitResultSchema, -} from "@getpaseo/protocol/browser-automation/rpc-schemas"; +import { BrowserAutomationBrowserIdSchema } from "@getpaseo/protocol/browser-automation/rpc-schemas"; import type { BrowserToolsBroker } from "./broker.js"; import type { BrowserToolsResponsePayload } from "./errors.js"; import type { @@ -66,29 +35,25 @@ const WORKSPACE_CONTEXT_MESSAGE = const URL_WHITESPACE_PATTERN = /\s/; const NON_HTTP_EXPLICIT_SCHEME_PATTERN = /^(?!https?:\/\/)[a-z][a-z0-9+.-]*:\/\//i; -const BrowserToolContextSchema = z.object({ - agentId: z.string().optional(), - cwd: z.string().optional(), - workspaceId: z.string().optional(), - browserId: z.string().optional(), -}); - -const BrowserToolErrorOutputSchema = z.object({ - ok: z.literal(false), - error: BrowserAutomationErrorSchema, - context: BrowserToolContextSchema, -}); - -function browserToolOutputSchema(resultSchema: ResultSchema) { - return z.discriminatedUnion("ok", [ - z.object({ - ok: z.literal(true), - result: resultSchema, - context: BrowserToolContextSchema, - }), - BrowserToolErrorOutputSchema, - ]); -} +const BrowserToolOutputSchema = { + ok: z.boolean(), + result: z.unknown().optional(), + error: z + .object({ + code: z.string(), + message: z.string(), + retryable: z.boolean(), + }) + .optional(), + context: z + .object({ + agentId: z.string().optional(), + cwd: z.string().optional(), + workspaceId: z.string().optional(), + browserId: z.string().optional(), + }) + .optional(), +}; const BrowserHttpUrlInputSchema = z .string() @@ -116,37 +81,6 @@ const BrowserWaitInputSchema = z message: "browser_wait requires exactly one of text or url", }); -const BrowserToolOutputs = { - listTabs: browserToolOutputSchema(BrowserAutomationListTabsResultSchema), - newTab: browserToolOutputSchema(BrowserAutomationNewTabResultSchema), - pageInfo: browserToolOutputSchema(BrowserAutomationPageInfoResultSchema), - snapshot: browserToolOutputSchema(BrowserAutomationSnapshotResultSchema), - click: browserToolOutputSchema(BrowserAutomationClickResultSchema), - fill: browserToolOutputSchema(BrowserAutomationFillResultSchema), - wait: browserToolOutputSchema(BrowserAutomationWaitResultSchema), - type: browserToolOutputSchema(BrowserAutomationTypeResultSchema), - keypress: browserToolOutputSchema(BrowserAutomationKeypressResultSchema), - navigate: browserToolOutputSchema(BrowserAutomationNavigateResultSchema), - back: browserToolOutputSchema(BrowserAutomationBackResultSchema), - forward: browserToolOutputSchema(BrowserAutomationForwardResultSchema), - reload: browserToolOutputSchema(BrowserAutomationReloadResultSchema), - screenshot: browserToolOutputSchema(BrowserAutomationScreenshotResultSchema), - fullPageScreenshot: browserToolOutputSchema(BrowserAutomationFullPageScreenshotResultSchema), - pdf: browserToolOutputSchema(BrowserAutomationPdfResultSchema), - download: browserToolOutputSchema(BrowserAutomationDownloadResultSchema), - upload: browserToolOutputSchema(BrowserAutomationUploadResultSchema), - focus: browserToolOutputSchema(BrowserAutomationFocusResultSchema), - clear: browserToolOutputSchema(BrowserAutomationClearResultSchema), - check: browserToolOutputSchema(BrowserAutomationCheckResultSchema), - select: browserToolOutputSchema(BrowserAutomationSelectResultSchema), - hover: browserToolOutputSchema(BrowserAutomationHoverResultSchema), - drag: browserToolOutputSchema(BrowserAutomationDragResultSchema), - logs: browserToolOutputSchema(BrowserAutomationLogsResultSchema), - storage: browserToolOutputSchema(BrowserAutomationStorageResultSchema), - environment: browserToolOutputSchema(BrowserAutomationEnvironmentResultSchema), - setBackground: browserToolOutputSchema(BrowserAutomationSetBackgroundResultSchema), -} as const; - export function registerBrowserTools(options: RegisterBrowserToolsOptions): void { options.registerTool( "browser_list_tabs", @@ -155,7 +89,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void description: "List open Paseo desktop browser tabs for this agent's workspace. Use returned browserId values with tab-scoped tools.", inputSchema: {}, - outputSchema: BrowserToolOutputs.listTabs, + outputSchema: BrowserToolOutputSchema, }, async () => { const context = resolveBrowserToolContext(options); @@ -185,7 +119,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void inputSchema: { url: BrowserHttpUrlInputSchema.optional(), }, - outputSchema: BrowserToolOutputs.newTab, + outputSchema: BrowserToolOutputSchema, }, async ({ url }) => { const context = resolveBrowserToolContext(options); @@ -215,7 +149,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void inputSchema: { browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.pageInfo, + outputSchema: BrowserToolOutputSchema, }, async ({ browserId }) => { const context = resolveBrowserToolContext(options); @@ -244,7 +178,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void inputSchema: { browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.snapshot, + outputSchema: BrowserToolOutputSchema, }, async ({ browserId }) => { const context = resolveBrowserToolContext(options); @@ -274,7 +208,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void ref: BrowserRefInputSchema, browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.click, + outputSchema: BrowserToolOutputSchema, }, async ({ ref, browserId }) => { const context = resolveBrowserToolContext(options); @@ -306,7 +240,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void value: z.string(), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.fill, + outputSchema: BrowserToolOutputSchema, }, async ({ ref, value, browserId }) => { const context = resolveBrowserToolContext(options); @@ -335,7 +269,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void description: "Wait until a Paseo desktop browser tab contains text or reaches a URL fragment. Use browserId from browser_new_tab or browser_list_tabs; waits up to 5s by default on the desktop side.", inputSchema: BrowserWaitInputSchema, - outputSchema: BrowserToolOutputs.wait, + outputSchema: BrowserToolOutputSchema, }, async ({ text, url, timeoutMs, browserId }) => { const context = resolveBrowserToolContext(options); @@ -370,7 +304,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void ref: BrowserRefInputSchema.optional(), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.type, + outputSchema: BrowserToolOutputSchema, }, async ({ text, ref, browserId }) => { const context = resolveBrowserToolContext(options); @@ -403,7 +337,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void ref: BrowserRefInputSchema.optional(), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.keypress, + outputSchema: BrowserToolOutputSchema, }, async ({ key, ref, browserId }) => { const context = resolveBrowserToolContext(options); @@ -432,7 +366,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void description: "Navigate a Paseo desktop browser tab to a URL. Use browserId from browser_new_tab or browser_list_tabs; pass an http(s) URL or a scheme-less host URL, which is treated as http.", inputSchema: { url: BrowserHttpUrlInputSchema, browserId: BrowserAutomationBrowserIdSchema }, - outputSchema: BrowserToolOutputs.navigate, + outputSchema: BrowserToolOutputSchema, }, async ({ url, browserId }) => { const context = resolveBrowserToolContext(options); @@ -482,7 +416,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void title: toolConfig.title, description: toolConfig.description, inputSchema: { browserId: BrowserAutomationBrowserIdSchema }, - outputSchema: BrowserToolOutputs[toolConfig.command], + outputSchema: BrowserToolOutputSchema, }, async ({ browserId }) => { const context = resolveBrowserToolContext(options); @@ -510,7 +444,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void description: "Capture a PNG screenshot of a Paseo desktop browser tab. Use browserId from browser_new_tab or browser_list_tabs.", inputSchema: { browserId: BrowserAutomationBrowserIdSchema }, - outputSchema: BrowserToolOutputs.screenshot, + outputSchema: BrowserToolOutputSchema, }, async ({ browserId }) => { const context = resolveBrowserToolContext(options); @@ -537,7 +471,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void description: "Capture a full-page PNG screenshot of a Paseo desktop browser tab. Use browserId from browser_new_tab or browser_list_tabs.", inputSchema: { browserId: BrowserAutomationBrowserIdSchema }, - outputSchema: BrowserToolOutputs.fullPageScreenshot, + outputSchema: BrowserToolOutputSchema, }, async ({ browserId }) => { const context = resolveBrowserToolContext(options); @@ -568,7 +502,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void landscape: z.boolean().optional(), printBackground: z.boolean().default(true), }, - outputSchema: BrowserToolOutputs.pdf, + outputSchema: BrowserToolOutputSchema, }, async ({ browserId, landscape, printBackground }) => { const context = resolveBrowserToolContext(options); @@ -601,7 +535,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void fileName: z.string().min(1).optional(), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.download, + outputSchema: BrowserToolOutputSchema, }, async ({ url, fileName, browserId }) => { const context = resolveBrowserToolContext(options); @@ -634,7 +568,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void filePaths: z.array(z.string().min(1)).min(1), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.upload, + outputSchema: BrowserToolOutputSchema, }, async ({ ref, filePaths, browserId }) => { const context = resolveBrowserToolContext(options); @@ -685,7 +619,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void title: toolConfig.title, description: toolConfig.description, inputSchema: { ref: BrowserRefInputSchema, browserId: BrowserAutomationBrowserIdSchema }, - outputSchema: BrowserToolOutputs[toolConfig.command], + outputSchema: BrowserToolOutputSchema, }, async ({ ref, browserId }) => { const context = resolveBrowserToolContext(options); @@ -718,7 +652,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void checked: z.boolean().default(true), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.check, + outputSchema: BrowserToolOutputSchema, }, async ({ ref, checked, browserId }) => { const context = resolveBrowserToolContext(options); @@ -751,7 +685,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void value: z.string(), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.select, + outputSchema: BrowserToolOutputSchema, }, async ({ ref, value, browserId }) => { const context = resolveBrowserToolContext(options); @@ -784,7 +718,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void targetRef: BrowserRefInputSchema, browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.drag, + outputSchema: BrowserToolOutputSchema, }, async ({ sourceRef, targetRef, browserId }) => { const context = resolveBrowserToolContext(options); @@ -816,7 +750,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void maxEntries: z.number().int().positive().max(200).optional(), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.logs, + outputSchema: BrowserToolOutputSchema, }, async ({ maxEntries, browserId }) => { const context = resolveBrowserToolContext(options); @@ -844,7 +778,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void description: "Read cookies plus localStorage and sessionStorage for a Paseo desktop browser tab. Use browserId from browser_new_tab or browser_list_tabs.", inputSchema: { browserId: BrowserAutomationBrowserIdSchema }, - outputSchema: BrowserToolOutputs.storage, + outputSchema: BrowserToolOutputSchema, }, async ({ browserId }) => { const context = resolveBrowserToolContext(options); @@ -887,7 +821,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void .optional(), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.environment, + outputSchema: BrowserToolOutputSchema, }, async ({ viewport, geolocation, browserId }) => { const context = resolveBrowserToolContext(options); @@ -919,7 +853,7 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void color: z.string().min(1), browserId: BrowserAutomationBrowserIdSchema, }, - outputSchema: BrowserToolOutputs.setBackground, + outputSchema: BrowserToolOutputSchema, }, async ({ color, browserId }) => { const context = resolveBrowserToolContext(options);