diff options
| author | Tommaso Sciortino <[email protected]> | 2025-05-30 18:25:47 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-05-30 18:25:47 -0700 |
| commit | 21fba832d1b4ea7af43fb887d9b2b38fcf8210d0 (patch) | |
| tree | 7200d2fac3a55c385e0a2dac34b5282c942364bc /packages/core/src/tools/mcp-tool.ts | |
| parent | c81148a0cc8489f657901c2cc7247c0834075e1a (diff) | |
Rename server->core (#638)
Diffstat (limited to 'packages/core/src/tools/mcp-tool.ts')
| -rw-r--r-- | packages/core/src/tools/mcp-tool.ts | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/packages/core/src/tools/mcp-tool.ts b/packages/core/src/tools/mcp-tool.ts new file mode 100644 index 00000000..d02b8632 --- /dev/null +++ b/packages/core/src/tools/mcp-tool.ts @@ -0,0 +1,102 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { + BaseTool, + ToolResult, + ToolCallConfirmationDetails, + ToolConfirmationOutcome, + ToolMcpConfirmationDetails, +} from './tools.js'; + +type ToolParams = Record<string, unknown>; + +export const MCP_TOOL_DEFAULT_TIMEOUT_MSEC = 10 * 60 * 1000; // default to 10 minutes + +export class DiscoveredMCPTool extends BaseTool<ToolParams, ToolResult> { + private static readonly whitelist: Set<string> = new Set(); + + constructor( + private readonly mcpClient: Client, + private readonly serverName: string, // Added for server identification + readonly name: string, + readonly description: string, + readonly parameterSchema: Record<string, unknown>, + readonly serverToolName: string, + readonly timeout?: number, + readonly trust?: boolean, + ) { + description += ` + +This MCP tool was discovered from a local MCP server using JSON RPC 2.0 over stdio transport protocol. +When called, this tool will invoke the \`tools/call\` method for tool name \`${name}\`. +MCP servers can be configured in project or user settings. +Returns the MCP server response as a json string. +`; + super( + name, + name, + description, + parameterSchema, + true, // isOutputMarkdown + false, // canUpdateOutput + ); + } + + async shouldConfirmExecute( + _params: ToolParams, + _abortSignal: AbortSignal, + ): Promise<ToolCallConfirmationDetails | false> { + const serverWhitelistKey = this.serverName; + const toolWhitelistKey = `${this.serverName}.${this.serverToolName}`; + + if (this.trust) { + return false; // server is trusted, no confirmation needed + } + + if ( + DiscoveredMCPTool.whitelist.has(serverWhitelistKey) || + DiscoveredMCPTool.whitelist.has(toolWhitelistKey) + ) { + return false; // server and/or tool already whitelisted + } + + const confirmationDetails: ToolMcpConfirmationDetails = { + type: 'mcp', + title: 'Confirm MCP Tool Execution', + serverName: this.serverName, + toolName: this.serverToolName, + toolDisplayName: this.name, + onConfirm: async (outcome: ToolConfirmationOutcome) => { + if (outcome === ToolConfirmationOutcome.ProceedAlwaysServer) { + DiscoveredMCPTool.whitelist.add(serverWhitelistKey); + } else if (outcome === ToolConfirmationOutcome.ProceedAlwaysTool) { + DiscoveredMCPTool.whitelist.add(toolWhitelistKey); + } + }, + }; + return confirmationDetails; + } + + async execute(params: ToolParams): Promise<ToolResult> { + const result = await this.mcpClient.callTool( + { + name: this.serverToolName, + arguments: params, + }, + undefined, // skip resultSchema to specify options (RequestOptions) + { + timeout: this.timeout ?? MCP_TOOL_DEFAULT_TIMEOUT_MSEC, + }, + ); + const output = '```json\n' + JSON.stringify(result, null, 2) + '\n```'; + return { + llmContent: output, + returnDisplay: output, + }; + } +} |
