UNPKG

@tanstack/ai

Version:

Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.

72 lines (71 loc) 2.28 kB
class MCPDuplicateToolNameError extends Error { constructor(toolName) { super( `Duplicate MCP tool name "${toolName}" in chat({ mcp.clients }). Set a unique \`prefix\` on one of the MCP clients (or use a pool, which auto-prefixes) to disambiguate.` ); this.toolName = toolName; this.name = "MCPDuplicateToolNameError"; } toolName; } class MCPManager { static from(options) { return new MCPManager(options); } #sources; #shouldClose; #lazyTools; #onDiscoveryError; constructor(options) { this.#sources = options?.clients ?? []; this.#shouldClose = options ? options.connection !== "keep-alive" : false; this.#lazyTools = options?.lazyTools ?? false; this.#onDiscoveryError = options?.onDiscoveryError; } /** * Discover + merge tools from all sources. Throws on a fatal discovery error * (no `onDiscoveryError`, or it re-threw) or a duplicate tool name; in that * case it first closes any connected sources when the policy is 'close'. */ async discover() { if (this.#sources.length === 0) return []; try { const settled = await Promise.allSettled( this.#sources.map((s) => s.tools({ lazy: this.#lazyTools })) ); const tools = []; const zipped = this.#sources.map( (source, i) => [source, settled[i]] ); for (const [source, result] of zipped) { if (result === void 0) continue; if (result.status === "fulfilled") { tools.push(...result.value); } else if (this.#onDiscoveryError) { await this.#onDiscoveryError(result.reason, source); } else { throw result.reason; } } const seen = /* @__PURE__ */ new Set(); for (const t of tools) { if (seen.has(t.name)) throw new MCPDuplicateToolNameError(t.name); seen.add(t.name); } return tools; } catch (err) { await this.dispose(); throw err; } } /** Close sources iff policy is 'close'. Idempotent; never throws. */ async dispose() { if (!this.#shouldClose || this.#sources.length === 0) return; await Promise.allSettled(this.#sources.map((s) => s.close())); } } export { MCPDuplicateToolNameError, MCPManager }; //# sourceMappingURL=manager.js.map