// --------------------------------------------------------------------------- // MCP tool discovery — connect to an MCP server and list its tools // --------------------------------------------------------------------------- import { Effect } from "effect"; import type { McpConnector } from "./connection"; import { McpToolDiscoveryError } from "./errors"; import { extractManifestFromListToolsResult, isListToolsResult, type McpToolManifest, } from "./manifest"; // --------------------------------------------------------------------------- // Public API // --------------------------------------------------------------------------- /** * Connect to an MCP server and discover all available tools. * Returns the parsed manifest containing server metadata and tool entries. */ export const discoverTools = ( connector: McpConnector, ): Effect.Effect => Effect.gen(function* () { // Acquire connection const connection = yield* connector.pipe( Effect.mapError( ({ message }) => new McpToolDiscoveryError({ stage: "connect", message: `Failed connecting to MCP server: ${message}`, }), ), ); // List tools const listResult = yield* Effect.tryPromise({ try: () => connection.client.listTools(), catch: () => new McpToolDiscoveryError({ stage: "list_tools", message: "Failed listing MCP tools", }), }); if (!isListToolsResult(listResult)) { yield* closeConnection(connection); return yield* new McpToolDiscoveryError({ stage: "list_tools", message: "MCP listTools response did not match the expected schema", }); } const manifest = extractManifestFromListToolsResult(listResult, { serverInfo: connection.client.getServerVersion?.(), instructions: connection.client.getInstructions?.(), }); // Close the connection after discovery yield* closeConnection(connection); return manifest; }); const closeConnection = (connection: { readonly close: () => Promise; }): Effect.Effect => Effect.ignore( Effect.tryPromise({ try: () => connection.close(), catch: () => new McpToolDiscoveryError({ stage: "list_tools", message: "Failed closing MCP connection", }), }), );