{"version":3,"sources":["../../src/client/host.ts"],"sourcesContent":["/**\n * Copyright 2025 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Root } from '@modelcontextprotocol/sdk/types.js';\nimport {\n  type DynamicActionProviderAction,\n  type DynamicResourceAction,\n  type ExecutablePrompt,\n  type Genkit,\n  type MultipartToolAction,\n  type PromptGenerateOptions,\n  type ToolAction,\n} from 'genkit';\nimport { logger } from 'genkit/logging';\nimport { GenkitMcpClient, McpServerConfig } from './client.mjs';\n\nexport interface McpHostOptions<M extends boolean = false> {\n  /**\n   * An optional client name for this MCP host. This name is advertised to MCP Servers\n   * as the connecting client name. Defaults to 'genkit-mcp'.\n   */\n  name?: string;\n  /**\n   * An optional version for this MCP host. Primarily for\n   * logging and identification within Genkit.\n   * Defaults to '1.0.0'.\n   */\n  version?: string;\n  /**\n   * A record for configuring multiple MCP servers. Each server connection is\n   * controlled by a `GenkitMcpClient` instance managed by `GenkitMcpHost`.\n   * The key in the record is used as the identifier for the MCP server.\n   */\n  mcpServers?: Record<string, McpServerConfig>;\n\n  /**\n   * If true, tool responses from the MCP server will be returned in their raw\n   * MCP format. Otherwise (default), they are processed and potentially\n   * simplified for better compatibility with Genkit's typical data structures.\n   */\n  rawToolResponses?: boolean;\n\n  /** If true, tools will be registered as multipart tool.v2 actions. */\n  multipart?: M;\n\n  /**\n   * When provided, each connected MCP server will be sent the roots specified here. Overridden by any specific roots sent in the `mcpServers` config for a given server.\n   */\n  roots?: Root[];\n}\n\nexport type McpHostOptionsWithCache<M extends boolean = false> = Omit<\n  McpHostOptions<M>,\n  'name'\n> & {\n  /**\n   * A client name for this MCP host. This name is advertised to MCP Servers\n   * as the connecting client name.\n   */\n  name: string;\n\n  /**\n   * Cache TTL. The dynamic action provider has a cache for the available actions\n   * The default TTL is 3 seconds.\n   * The cache will automatically be invalidated if any connections change.\n   *   Negative = no caching (expect noisy traces and slower resolution)\n   *   Zero or undefined = use the default 3000 millis (3 seconds)\n   *   Positive: The number of milliseconds to keep the cache.\n   */\n  cacheTTLMillis?: number;\n};\n\n/** Internal representation of client state for logging. */\ninterface ClientState {\n  error?: {\n    message: string;\n    detail?: any;\n  };\n}\n\n/**\n * Manages connections to multiple MCP (Model Context Protocol) servers.\n * Each server connection is individually configured and managed by an instance of `GenkitMcpClient`.\n * This host provides a centralized way to initialize, update, and interact with these clients.\n *\n * It allows for dynamic registration of tools from all connected and enabled MCP servers\n * into a Genkit instance.\n */\nexport class GenkitMcpHost<Multipart extends boolean = false> {\n  name: string;\n  private _clients: Record<string, GenkitMcpClient<Multipart>> = {};\n  private _clientStates: Record<string, ClientState> = {};\n  private _readyListeners: {\n    resolve: () => void;\n    reject: (err: Error) => void;\n  }[] = [];\n  private _ready = false;\n  private _dynamicActionProvider: DynamicActionProviderAction | undefined;\n  private roots: Root[] | undefined;\n  rawToolResponses?: boolean;\n  multipart?: Multipart;\n\n  constructor(options: McpHostOptions<Multipart>) {\n    this.name = options.name || 'genkit-mcp';\n    this.rawToolResponses = options.rawToolResponses;\n    this.multipart = options.multipart;\n    this.roots = options.roots;\n\n    if (options.mcpServers) {\n      this.updateServers(options.mcpServers);\n    } else {\n      this._ready = true;\n    }\n  }\n\n  set dynamicActionProvider(dap: DynamicActionProviderAction) {\n    this._dynamicActionProvider = dap;\n  }\n\n  _invalidateCache(): void {\n    if (this._dynamicActionProvider) {\n      this._dynamicActionProvider.invalidateCache();\n    }\n  }\n\n  /**\n   * Returns a Promise that resolves when the host has attempted to connect\n   * to all configured clients, or rejects if a critical error occurs during\n   * the initial connection phase.\n   */\n  async ready() {\n    if (this._ready) return;\n    return new Promise<void>((resolve, reject) => {\n      this._readyListeners.push({ resolve, reject });\n    });\n  }\n\n  /**\n   * Connects to a single MCP server defined by the provided configuration.\n   * If a server with the same name already exists, it will be disconnected first.\n   * Stores the client and transport references internally. Handles connection errors\n   * by marking the server as disabled.\n   * @param serverName The name to assign to this server connection.\n   * @param config The configuration object for the server.\n   */\n  async connect(serverName: string, config: McpServerConfig) {\n    const existingEntry = this._clients[serverName];\n    if (existingEntry) {\n      try {\n        await existingEntry._disconnect();\n      } catch (e) {\n        existingEntry.disable();\n        this.setError(serverName, {\n          message: `[MCP Host] Error disconnecting from existing connection for ${serverName}`,\n          detail: `Details: ${e}`,\n        });\n      }\n    }\n\n    logger.debug(\n      `[MCP Host] Connecting to MCP server '${serverName}' in host '${this.name}'.`\n    );\n    try {\n      const client = new GenkitMcpClient<Multipart>({\n        name: this.name,\n        serverName: serverName,\n        mcpServer: { ...config, roots: config.roots || this.roots },\n        rawToolResponses: this.rawToolResponses,\n        multipart: this.multipart,\n      });\n      this._clients[serverName] = client;\n    } catch (e) {\n      this.setError(serverName, {\n        message: `[MCP Host] Error connecting to ${serverName} with config ${config}`,\n        detail: `Details: ${e}`,\n      });\n    }\n    this._invalidateCache();\n  }\n\n  /**\n   * Disconnects the specified MCP server and removes its registration\n   * from this client instance.\n   * @param serverName The name of the server to disconnect.\n   */\n  async disconnect(serverName: string) {\n    const client = this._clients[serverName];\n    if (!client) {\n      logger.warn(`[MCP Host] unable to find server ${serverName}`);\n      return;\n    }\n\n    logger.debug(\n      `[MCP Host] Disconnecting MCP server '${serverName}' in host '${this.name}'.`\n    );\n    try {\n      await client._disconnect();\n    } catch (e) {\n      client.disable();\n      this.setError(serverName, {\n        message: `[MCP Host] Error disconnecting from existing connection for ${serverName}`,\n        detail: `Details: ${e}`,\n      });\n    }\n    delete this._clients[serverName];\n    this._invalidateCache();\n  }\n\n  /**\n   * Temporarily disables a server connection. Closes the underlying transport\n   * but retains the server's configuration. Does nothing if the server is\n   * already disabled.\n   * @param serverName The name of the server to disable.\n   */\n  async disable(serverName: string) {\n    const client = this._clients[serverName];\n    if (!client) {\n      logger.warn(`[MCP Host] unable to find server ${serverName}`);\n      return;\n    }\n    if (!client.isEnabled()) {\n      logger.warn(`[MCP Host] server ${serverName} already disabled`);\n      return;\n    }\n\n    logger.debug(\n      `[MCP Host] Disabling MCP server '${serverName}' in host '${this.name}'`\n    );\n    await client.disable();\n    this._invalidateCache();\n  }\n\n  /**\n   * Enables a server connection, including previously disabled ones. Attempts to reconnect\n   * using the stored transport. Does nothing if the server is not disabled.\n   * @param serverName The name of the server to re-enable.\n   */\n  async enable(serverName: string) {\n    const client = this._clients[serverName];\n    if (!client) {\n      logger.warn(`[MCP Host] unable to find server ${serverName}`);\n      return;\n    }\n\n    logger.debug(\n      `[MCP Host] Reenabling MCP server '${serverName}' in host '${this.name}'`\n    );\n    try {\n      await client.enable();\n    } catch (e) {\n      client.disable();\n      this.setError(serverName, {\n        message: `[MCP Host] Error reenabling server ${serverName}`,\n        detail: `Details: ${e}`,\n      });\n    }\n    this._invalidateCache();\n  }\n\n  /**\n   * Closes and then restarts the transport connection for the specified server.\n   * Useful for attempting to recover from connection issues without full\n   * reconfiguration.\n   * @param serverName The name of the server to reconnect.\n   */\n  async reconnect(serverName: string) {\n    const client = this._clients[serverName];\n    if (!client) {\n      logger.warn(`[MCP Host] unable to find server ${serverName}`);\n      return;\n    }\n\n    logger.debug(\n      `[MCP Host] Restarting connection to MCP server '${serverName}' in host '${this.name}'`\n    );\n    try {\n      await client.restart();\n    } catch (e) {\n      client.disable();\n      this.setError(serverName, {\n        message: `[MCP Host] Error restarting to server ${serverName}`,\n        detail: `Details: ${e}`,\n      });\n    }\n    this._invalidateCache();\n  }\n\n  /**\n   * Updates the connections based on a provided map of server configurations.\n   * - Connects any new servers defined in `mcpServers`.\n   * - Disconnects any servers currently connected but not present in `mcpServers`.\n   * - Reconnects existing servers if their configuration appears to have changed (implicitly handled by `connectServer`).\n   * Sets the client's ready state once all connection attempts are complete.\n   * @param mcpServers A record mapping server names to their configurations.\n   */\n  updateServers(mcpServers: Record<string, McpServerConfig>) {\n    this._ready = false;\n    const newServerNames = new Set(Object.keys(mcpServers));\n    const currentServerNames = new Set(Object.keys(this._clients));\n\n    const promises: Promise<void>[] = [];\n    for (const serverName in mcpServers) {\n      promises.push(this.connect(serverName, mcpServers[serverName]));\n    }\n\n    // Disconnect servers that are no longer in the config\n    for (const serverName of currentServerNames) {\n      if (!newServerNames.has(serverName)) {\n        this.disconnect(serverName);\n      }\n    }\n\n    Promise.all(promises)\n      .then(() => {\n        this._ready = true;\n        while (this._readyListeners.length) {\n          this._readyListeners.pop()?.resolve();\n        }\n      })\n      .catch((err) => {\n        while (this._readyListeners.length) {\n          this._readyListeners.pop()?.reject(err);\n        }\n      });\n\n    this._invalidateCache();\n  }\n\n  /**\n   * Retrieves all tools from all connected and enabled MCP clients managed by\n   * this instance. This method waits for the host to be ready (all initial\n   * connection attempts made) before fetching tools.\n   *\n   * It iterates through each managed `GenkitMcpClient`, and if the client is\n   * not disabled, it calls the client's `getTools` method to fetch its\n   * available tools. These are then aggregated into a single array.\n   *\n   * This is useful for dynamically providing a list of all available MCP tools\n   * to Genkit, for example, when setting up a Genkit plugin.\n   *\n   * ```ts\n   * const mcpHost = createMcpHost({ ... });\n   * // In your Genkit configuration:\n   * // const allMcpTools = await McpHost.getActiveTools(ai);\n   * // Then, these tools can be used or registered with Genkit.\n   * ```\n   *\n   * @param ai The Genkit instance, used by individual clients to define dynamic\n   * tools.\n   * @returns A Promise that resolves to an array of `ToolAction` from all\n   * active MCP clients.\n   */\n  async getActiveTools(\n    ai: Genkit\n  ): Promise<(Multipart extends true ? MultipartToolAction : ToolAction)[]> {\n    await this.ready();\n    let allTools: (Multipart extends true\n      ? MultipartToolAction\n      : ToolAction)[] = [];\n\n    for (const serverName in this._clients) {\n      const client = this._clients[serverName];\n      if (client.isEnabled() && !this.hasError(serverName)) {\n        try {\n          const tools = await client.getActiveTools(ai);\n          allTools.push(...tools);\n        } catch (e) {\n          logger.error(\n            `Error fetching active tools from client ${serverName}.`,\n            JSON.stringify(e)\n          );\n        }\n      }\n    }\n    return allTools;\n  }\n\n  /**\n   * Retrieves all resources from all connected and enabled MCP clients managed by\n   * this instance. This method waits for the host to be ready (all initial\n   * connection attempts made) before fetching resources.\n   *\n   * It iterates through each managed `GenkitMcpClient`, and if the client is\n   * not disabled, it calls the client's `getActiveResources` method to fetch its\n   * available resources. These are then aggregated into a single array.\n   *\n   * This is useful for dynamically providing a list of all available MCP resources\n   * to Genkit, for example, when setting up a Genkit plugin.\n   *\n   * @param ai The Genkit instance, used by individual clients to define dynamic\n   * resources.\n   * @returns A Promise that resolves to an array of `DynamicResourceAction` from all\n   * active MCP clients.\n   */\n  async getActiveResources(ai: Genkit): Promise<DynamicResourceAction[]> {\n    await this.ready();\n    let allResources: DynamicResourceAction[] = [];\n\n    for (const serverName in this._clients) {\n      const client = this._clients[serverName];\n      if (client.isEnabled() && !this.hasError(serverName)) {\n        try {\n          const resources = await client.getActiveResources(ai);\n          allResources.push(...resources);\n        } catch (e) {\n          logger.error(\n            `Error fetching active resources from client ${serverName}.`,\n            JSON.stringify(e)\n          );\n        }\n      }\n    }\n    return allResources;\n  }\n\n  /**\n   * Retrieves all prompts from all connected and enabled MCP clients managed by\n   * this instance. This method waits for the host to be ready (all initial\n   * connection attempts made) before fetching prompts.\n   *\n   * It iterates through each managed `GenkitMcpClient`, and if the client is\n   * not disabled, it calls the client's `getActivePrompts` method to fetch its\n   * available prompts. These are then aggregated into a single array.\n   *\n   * This is useful for dynamically providing a list of all available MCP prompts\n   * to Genkit, for example, when setting up a Genkit plugin.\n   *\n   * @param ai The Genkit instance, used by individual clients to define dynamic\n   * prompts.\n   * @returns A Promise that resolves to an array of `ExecutablePrompt` from all\n   * active MCP clients.\n   */\n  async getActivePrompts(ai: Genkit): Promise<ExecutablePrompt[]> {\n    await this.ready();\n    let allPrompts: ExecutablePrompt[] = [];\n\n    for (const serverName in this._clients) {\n      const client = this._clients[serverName];\n      if (client.isEnabled() && !this.hasError(serverName)) {\n        allPrompts.push(...(await client.getActivePrompts(ai)));\n      }\n    }\n    return allPrompts;\n  }\n\n  /**\n   * Get the specified prompt as an `ExecutablePrompt` available through the\n   * specified server. If no such prompt is found, return undefined.\n   */\n  async getPrompt(\n    ai: Genkit,\n    serverName: string,\n    promptName: string,\n    opts?: PromptGenerateOptions\n  ): Promise<ExecutablePrompt<any> | undefined> {\n    await this.ready();\n    const client = this._clients[serverName];\n    if (!client) {\n      logger.error(`No client found with name '${serverName}'.`);\n      return;\n    }\n    if (this.hasError(serverName)) {\n      const errorStringified = JSON.stringify(\n        this._clientStates[serverName].error\n      );\n      logger.error(\n        `Client '${serverName}' is in an error state. ${errorStringified}`\n      );\n    }\n    if (client.isEnabled()) {\n      const prompt = await client.getPrompt(ai, promptName, opts);\n      if (!prompt) {\n        logger.error(\n          `[MCP Host] Unable to fetch the specified ${promptName} in server ${serverName}.`\n        );\n        return;\n      }\n      return prompt;\n    }\n    return;\n  }\n\n  async close() {\n    for (const client of Object.values(this._clients)) {\n      await client._disconnect();\n    }\n    this._invalidateCache();\n  }\n\n  /** Helper method to track and log client errors. */\n  private setError(\n    serverName: string,\n    error: {\n      message: string;\n      detail?: any;\n    }\n  ) {\n    this._clientStates[serverName] = { error };\n    logger.warn(\n      `An error has occured while managing your MCP client '${serverName}'. The client may be disabled to avoid further issues. Please resolve the issue and reenable the client '${serverName}' to continue using its resources.`\n    );\n    logger.warn(error);\n  }\n\n  private hasError(serverName: string) {\n    return (\n      this._clientStates[serverName] && !!this._clientStates[serverName].error\n    );\n  }\n\n  /**\n   * Returns an array of all active clients.\n   */\n  get activeClients(): GenkitMcpClient<Multipart>[] {\n    return Object.values(this._clients).filter((c) => c.isEnabled());\n  }\n\n  /**\n   * Returns the client by name.\n   */\n  getClient(name: string) {\n    return this._clients[name];\n  }\n}\n"],"mappings":"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","names":[]}