| | import { Client } from "@modelcontextprotocol/sdk/client"; |
| | import { getClient } from "./clientPool"; |
| |
|
| | export interface McpServerConfig { |
| | name: string; |
| | url: string; |
| | headers?: Record<string, string>; |
| | } |
| |
|
| | const DEFAULT_TIMEOUT_MS = 30_000; |
| |
|
| | export type McpToolTextResponse = { |
| | text: string; |
| | |
| | structured?: unknown; |
| | |
| | content?: unknown[]; |
| | }; |
| |
|
| | export async function callMcpTool( |
| | server: McpServerConfig, |
| | tool: string, |
| | args: unknown = {}, |
| | { |
| | timeoutMs = DEFAULT_TIMEOUT_MS, |
| | signal, |
| | client, |
| | }: { timeoutMs?: number; signal?: AbortSignal; client?: Client } = {} |
| | ): Promise<McpToolTextResponse> { |
| | const normalizedArgs = |
| | typeof args === "object" && args !== null && !Array.isArray(args) |
| | ? (args as Record<string, unknown>) |
| | : undefined; |
| |
|
| | |
| | |
| | const activeClient = client ?? (await getClient(server, signal)); |
| |
|
| | |
| | const response = await activeClient.callTool( |
| | { name: tool, arguments: normalizedArgs }, |
| | undefined, |
| | { signal, timeout: timeoutMs } |
| | ); |
| |
|
| | const parts = Array.isArray(response?.content) ? (response.content as Array<unknown>) : []; |
| | const textParts = parts |
| | .filter((part): part is { type: "text"; text: string } => { |
| | if (typeof part !== "object" || part === null) return false; |
| | const obj = part as Record<string, unknown>; |
| | return obj["type"] === "text" && typeof obj["text"] === "string"; |
| | }) |
| | .map((p) => p.text); |
| |
|
| | const text = textParts.join("\n"); |
| | const structured = (response as unknown as { structuredContent?: unknown })?.structuredContent; |
| | const contentBlocks = Array.isArray(response?.content) |
| | ? (response.content as unknown[]) |
| | : undefined; |
| | return { text, structured, content: contentBlocks }; |
| | } |
| |
|