MCPTool.ts
1 import { z } from 'zod/v4' 2 import { buildTool, type ToolDef } from '../../Tool.js' 3 import { lazySchema } from '../../utils/lazySchema.js' 4 import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' 5 import { isOutputLineTruncated } from '../../utils/terminal.js' 6 import { DESCRIPTION, PROMPT } from './prompt.js' 7 import { 8 renderToolResultMessage, 9 renderToolUseMessage, 10 renderToolUseProgressMessage, 11 } from './UI.js' 12 13 // Allow any input object since MCP tools define their own schemas 14 export const inputSchema = lazySchema(() => z.object({}).passthrough()) 15 type InputSchema = ReturnType<typeof inputSchema> 16 17 export const outputSchema = lazySchema(() => 18 z.string().describe('MCP tool execution result'), 19 ) 20 type OutputSchema = ReturnType<typeof outputSchema> 21 22 export type Output = z.infer<OutputSchema> 23 24 // Re-export MCPProgress from centralized types to break import cycles 25 export type { MCPProgress } from '../../types/tools.js' 26 27 export const MCPTool = buildTool({ 28 isMcp: true, 29 // Overridden in mcpClient.ts with the real MCP tool name + args 30 isOpenWorld() { 31 return false 32 }, 33 // Overridden in mcpClient.ts 34 name: 'mcp', 35 maxResultSizeChars: 100_000, 36 // Overridden in mcpClient.ts 37 async description() { 38 return DESCRIPTION 39 }, 40 // Overridden in mcpClient.ts 41 async prompt() { 42 return PROMPT 43 }, 44 get inputSchema(): InputSchema { 45 return inputSchema() 46 }, 47 get outputSchema(): OutputSchema { 48 return outputSchema() 49 }, 50 // Overridden in mcpClient.ts 51 async call() { 52 return { 53 data: '', 54 } 55 }, 56 async checkPermissions(): Promise<PermissionResult> { 57 return { 58 behavior: 'passthrough', 59 message: 'MCPTool requires permission.', 60 } 61 }, 62 renderToolUseMessage, 63 // Overridden in mcpClient.ts 64 userFacingName: () => 'mcp', 65 renderToolUseProgressMessage, 66 renderToolResultMessage, 67 isResultTruncated(output: Output): boolean { 68 return isOutputLineTruncated(output) 69 }, 70 mapToolResultToToolResultBlockParam(content, toolUseID) { 71 return { 72 tool_use_id: toolUseID, 73 type: 'tool_result', 74 content, 75 } 76 }, 77 } satisfies ToolDef<InputSchema, Output>)