(toolCall: McpToolCall)
| 178 | } |
| 179 | |
| 180 | async callTool(toolCall: McpToolCall): Promise<McpToolResult> { |
| 181 | if (!this.isConnected) { |
| 182 | throw new McpConnectionError('Not connected to server', this.config.name) |
| 183 | } |
| 184 | |
| 185 | const consentRequest: McpConsentRequest = { |
| 186 | type: 'tool_execution', |
| 187 | context: { |
| 188 | serverId: this.config.id, |
| 189 | serverName: this.config.name, |
| 190 | action: toolCall.name, |
| 191 | description: `Execute tool '${toolCall.name}' on ${this.config.name}`, |
| 192 | dataAccess: Object.keys(toolCall.arguments || {}), |
| 193 | sideEffects: ['tool_execution'], |
| 194 | }, |
| 195 | expires: Date.now() + 5 * 60 * 1000, |
| 196 | } |
| 197 | |
| 198 | const consentResponse = await this.requestConsent(consentRequest) |
| 199 | if (!consentResponse.granted) { |
| 200 | throw new McpError(`User consent denied for tool execution: ${toolCall.name}`, -32000, { |
| 201 | consentAuditId: consentResponse.auditId, |
| 202 | }) |
| 203 | } |
| 204 | |
| 205 | try { |
| 206 | logger.info(`Calling tool ${toolCall.name} on server ${this.config.name}`, { |
| 207 | consentAuditId: consentResponse.auditId, |
| 208 | protocolVersion: this.getNegotiatedVersion(), |
| 209 | }) |
| 210 | |
| 211 | const sdkResult = await this.client.callTool( |
| 212 | { name: toolCall.name, arguments: toolCall.arguments }, |
| 213 | undefined, |
| 214 | { timeout: getMaxExecutionTimeout() } |
| 215 | ) |
| 216 | |
| 217 | return sdkResult as McpToolResult |
| 218 | } catch (error) { |
| 219 | logger.error(`Failed to call tool ${toolCall.name} on server ${this.config.name}:`, error) |
| 220 | throw error |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | async ping(): Promise<{ _meta?: Record<string, any> }> { |
| 225 | if (!this.isConnected) { |
no test coverage detected