@genkit-ai/mcp 1.14.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +205 -0
  3. package/examples/client/index.js +36 -0
  4. package/examples/client/package.json +25 -0
  5. package/examples/server/index.js +46 -0
  6. package/examples/server/package.json +18 -0
  7. package/examples/server/prompts/port_code.prompt +13 -0
  8. package/lib/client/client.d.mts +177 -0
  9. package/lib/client/client.d.ts +177 -0
  10. package/lib/client/client.js +282 -0
  11. package/lib/client/client.js.map +1 -0
  12. package/lib/client/client.mjs +267 -0
  13. package/lib/client/client.mjs.map +1 -0
  14. package/lib/client/host.d.mts +202 -0
  15. package/lib/client/host.d.ts +202 -0
  16. package/lib/client/host.js +392 -0
  17. package/lib/client/host.js.map +1 -0
  18. package/lib/client/host.mjs +368 -0
  19. package/lib/client/host.mjs.map +1 -0
  20. package/lib/client/index.d.mts +9 -0
  21. package/lib/client/index.d.ts +9 -0
  22. package/lib/client/index.js +32 -0
  23. package/lib/client/index.js.map +1 -0
  24. package/lib/client/index.mjs +7 -0
  25. package/lib/client/index.mjs.map +1 -0
  26. package/lib/index.d.mts +12 -0
  27. package/lib/index.d.ts +12 -0
  28. package/lib/index.js +48 -0
  29. package/lib/index.js.map +1 -0
  30. package/lib/index.mjs +22 -0
  31. package/lib/index.mjs.map +1 -0
  32. package/lib/server.d.mts +188 -0
  33. package/lib/server.d.ts +188 -0
  34. package/lib/server.js +280 -0
  35. package/lib/server.js.map +1 -0
  36. package/lib/server.mjs +249 -0
  37. package/lib/server.mjs.map +1 -0
  38. package/lib/util/index.d.mts +11 -0
  39. package/lib/util/index.d.ts +11 -0
  40. package/lib/util/index.js +29 -0
  41. package/lib/util/index.js.map +1 -0
  42. package/lib/util/index.mjs +5 -0
  43. package/lib/util/index.mjs.map +1 -0
  44. package/lib/util/message.d.mts +43 -0
  45. package/lib/util/message.d.ts +43 -0
  46. package/lib/util/message.js +61 -0
  47. package/lib/util/message.js.map +1 -0
  48. package/lib/util/message.mjs +36 -0
  49. package/lib/util/message.mjs.map +1 -0
  50. package/lib/util/prompts.d.mts +45 -0
  51. package/lib/util/prompts.d.ts +45 -0
  52. package/lib/util/prompts.js +147 -0
  53. package/lib/util/prompts.js.map +1 -0
  54. package/lib/util/prompts.mjs +123 -0
  55. package/lib/util/prompts.mjs.map +1 -0
  56. package/lib/util/resource.d.mts +28 -0
  57. package/lib/util/resource.d.ts +28 -0
  58. package/lib/util/resource.js +116 -0
  59. package/lib/util/resource.js.map +1 -0
  60. package/lib/util/resource.mjs +95 -0
  61. package/lib/util/resource.mjs.map +1 -0
  62. package/lib/util/tools.d.mts +37 -0
  63. package/lib/util/tools.d.ts +37 -0
  64. package/lib/util/tools.js +120 -0
  65. package/lib/util/tools.js.map +1 -0
  66. package/lib/util/tools.mjs +95 -0
  67. package/lib/util/tools.mjs.map +1 -0
  68. package/lib/util/transport.d.mts +39 -0
  69. package/lib/util/transport.d.ts +39 -0
  70. package/lib/util/transport.js +63 -0
  71. package/lib/util/transport.js.map +1 -0
  72. package/lib/util/transport.mjs +29 -0
  73. package/lib/util/transport.mjs.map +1 -0
  74. package/package.json +57 -0
  75. package/src/client/client.ts +414 -0
  76. package/src/client/host.ts +485 -0
  77. package/src/client/index.ts +29 -0
  78. package/src/index.ts +114 -0
  79. package/src/server.ts +330 -0
  80. package/src/util/index.ts +20 -0
  81. package/src/util/message.ts +72 -0
  82. package/src/util/prompts.ts +223 -0
  83. package/src/util/resource.ts +141 -0
  84. package/src/util/tools.ts +164 -0
  85. package/src/util/transport.ts +67 -0
  86. package/tests/fakes.ts +221 -0
  87. package/tests/host_test.ts +609 -0
  88. package/tests/server_test.ts +165 -0
@@ -0,0 +1,267 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import {
3
+ ListRootsRequestSchema
4
+ } from "@modelcontextprotocol/sdk/types.js";
5
+ import {
6
+ GenkitError
7
+ } from "genkit";
8
+ import { logger } from "genkit/logging";
9
+ import {
10
+ fetchAllPrompts,
11
+ fetchDynamicTools,
12
+ getExecutablePrompt,
13
+ transportFrom
14
+ } from "../util";
15
+ import { fetchDynamicResources } from "../util/resource";
16
+ class GenkitMcpClient {
17
+ _server;
18
+ sessionId;
19
+ name;
20
+ suppliedServerName;
21
+ version;
22
+ serverConfig;
23
+ rawToolResponses;
24
+ disabled;
25
+ roots;
26
+ _readyListeners = [];
27
+ _ready = false;
28
+ constructor(options) {
29
+ this.name = options.name;
30
+ this.suppliedServerName = options.serverName;
31
+ this.version = options.version || "1.0.0";
32
+ this.serverConfig = options.mcpServer;
33
+ this.rawToolResponses = !!options.rawToolResponses;
34
+ this.disabled = !!options.mcpServer.disabled;
35
+ this.roots = options.mcpServer.roots;
36
+ this.sessionId = options.sessionId;
37
+ this._initializeConnection();
38
+ }
39
+ get serverName() {
40
+ return this.suppliedServerName ?? this._server?.client.getServerVersion()?.name ?? "unknown-server";
41
+ }
42
+ async updateRoots(roots) {
43
+ this.roots = roots;
44
+ await this._server?.client.sendRootsListChanged();
45
+ }
46
+ /**
47
+ * Sets up a connection based on a provided map of server configurations.
48
+ * - Reconnects existing servers if their configuration appears to have
49
+ * changed (implicitly handled by `connectServer`).
50
+ * - Sets the client's ready state once all connection attempts are complete.
51
+ * @param mcpServers A record mapping server names to their configurations.
52
+ */
53
+ async _initializeConnection() {
54
+ this._ready = false;
55
+ try {
56
+ await this._connect();
57
+ this._ready = true;
58
+ while (this._readyListeners.length) {
59
+ this._readyListeners.pop()?.resolve();
60
+ }
61
+ } catch (err) {
62
+ while (this._readyListeners.length) {
63
+ this._readyListeners.pop()?.reject(err);
64
+ }
65
+ }
66
+ if (this.roots) {
67
+ await this.updateRoots(this.roots);
68
+ }
69
+ }
70
+ /**
71
+ * Returns a Promise that resolves when the client has attempted to connect
72
+ * to all configured servers, or rejects if a critical error occurs during
73
+ * the initial connection phase.
74
+ */
75
+ async ready() {
76
+ if (this._ready) return;
77
+ return new Promise((resolve, reject) => {
78
+ this._readyListeners.push({ resolve, reject });
79
+ });
80
+ }
81
+ /**
82
+ * Connects to a single MCP server defined by the provided configuration.
83
+ * @param config The configuration object for the server.
84
+ */
85
+ async _connect() {
86
+ if (this._server) await this._server.transport.close();
87
+ logger.debug(
88
+ `[MCP Client] Connecting MCP server '${this.serverName}' in client '${this.name}'.`
89
+ );
90
+ const { transport, type: transportType } = await transportFrom(
91
+ this.serverConfig,
92
+ this.sessionId
93
+ );
94
+ if (!transport) {
95
+ throw new GenkitError({
96
+ status: "INVALID_ARGUMENT",
97
+ message: `[MCP Client] Could not determine valid transport config from supplied options.`
98
+ });
99
+ }
100
+ let error;
101
+ const client = new Client(
102
+ { name: this.name, version: this.version },
103
+ { capabilities: { roots: { listChanged: true } } }
104
+ );
105
+ client.setRequestHandler(ListRootsRequestSchema, () => {
106
+ logger.debug(`[MCP Client] fetching roots for ${this.name}`);
107
+ return { roots: this.roots || [] };
108
+ });
109
+ try {
110
+ await client.connect(transport);
111
+ } catch (e) {
112
+ logger.warn(
113
+ `[MCP Client] Error connecting server via ${transportType} transport: ${e}`
114
+ );
115
+ this.disabled = true;
116
+ error = e.toString();
117
+ }
118
+ this._server = {
119
+ client,
120
+ transport,
121
+ error
122
+ };
123
+ }
124
+ /**
125
+ * Disconnects the MCP server and removes its registration
126
+ * from this client instance.
127
+ */
128
+ async _disconnect() {
129
+ if (this._server) {
130
+ logger.debug(
131
+ `[MCP Client] Disconnecting MCP server in client '${this.name}'.`
132
+ );
133
+ await this._server.client.close();
134
+ this._server = void 0;
135
+ }
136
+ }
137
+ /**
138
+ * Disables a server. Closes the underlying transport and server's configuration. Does nothing if the server is
139
+ * already disabled.
140
+ */
141
+ async disable() {
142
+ if (!this.isEnabled()) return;
143
+ if (this._server) {
144
+ logger.debug(
145
+ `[MCP Client] Disabling MCP server in client '${this.name}'`
146
+ );
147
+ await this._disconnect();
148
+ this.disabled = true;
149
+ }
150
+ }
151
+ /**
152
+ * Whether this client-server connection is enabled or not.
153
+ */
154
+ isEnabled() {
155
+ return !this.disabled;
156
+ }
157
+ /**
158
+ * Enables a server connection, including previously disabled ones. Does nothing if the
159
+ * server is not disabled.
160
+ */
161
+ async enable() {
162
+ if (this.isEnabled()) return;
163
+ logger.debug(`[MCP Client] Reenabling MCP server in client '${this.name}'`);
164
+ await this._initializeConnection();
165
+ this.disabled = !!this._server.error;
166
+ }
167
+ /**
168
+ * Closes and then restarts the transport connection for the specified server.
169
+ * Useful for attempting to recover from connection issues without full
170
+ * reconfiguration.
171
+ */
172
+ async restart() {
173
+ if (this._server) {
174
+ logger.debug(
175
+ `[MCP Client] Restarting connection to MCP server in client '${this.name}'`
176
+ );
177
+ await this._disconnect();
178
+ await this._initializeConnection();
179
+ }
180
+ }
181
+ /**
182
+ * Fetches all tools available through this client, if the server
183
+ * configuration is not disabled.
184
+ */
185
+ async getActiveTools(ai) {
186
+ await this.ready();
187
+ let tools = [];
188
+ if (this._server) {
189
+ const capabilities = this._server.client.getServerCapabilities();
190
+ if (capabilities?.tools)
191
+ tools.push(
192
+ ...await fetchDynamicTools(ai, this._server.client, {
193
+ rawToolResponses: this.rawToolResponses,
194
+ serverName: this.serverName,
195
+ name: this.name
196
+ })
197
+ );
198
+ }
199
+ return tools;
200
+ }
201
+ /**
202
+ * Fetches all resources available through this client, if the server
203
+ * configuration is not disabled.
204
+ */
205
+ async getActiveResources(ai) {
206
+ await this.ready();
207
+ let resources = [];
208
+ if (this._server) {
209
+ const capabilities = this._server.client.getServerCapabilities();
210
+ if (capabilities?.resources)
211
+ resources.push(
212
+ ...await fetchDynamicResources(ai, this._server.client, {
213
+ serverName: this.serverName,
214
+ name: this.name
215
+ })
216
+ );
217
+ }
218
+ return resources;
219
+ }
220
+ /**
221
+ * Fetches all active prompts available through this client, if the server
222
+ * configuration supports prompts.
223
+ * @param ai The Genkit instance.
224
+ * @param options Optional prompt generation options.
225
+ * @returns A promise that resolves to an array of ExecutablePrompt.
226
+ */
227
+ async getActivePrompts(ai, options) {
228
+ if (this._server?.client.getServerCapabilities()?.prompts) {
229
+ return fetchAllPrompts(this._server.client, {
230
+ ai,
231
+ serverName: this.serverName,
232
+ name: this.name,
233
+ options
234
+ });
235
+ }
236
+ return [];
237
+ }
238
+ /**
239
+ * Get the specified prompt as an `ExecutablePrompt` available through this
240
+ * client. If no such prompt is found, return undefined.
241
+ */
242
+ async getPrompt(ai, promptName, opts) {
243
+ await this.ready();
244
+ if (this._server) {
245
+ const capabilities = await this._server.client.getServerCapabilities();
246
+ if (capabilities?.prompts) {
247
+ return await getExecutablePrompt(this._server.client, {
248
+ ai,
249
+ serverName: this.name,
250
+ promptName,
251
+ name: this.name,
252
+ options: opts
253
+ });
254
+ }
255
+ logger.debug(`[MCP Client] No prompts are found in this MCP server.`);
256
+ }
257
+ return;
258
+ }
259
+ /** Returns the underlying MCP SDK client if one has been initialized. */
260
+ get mcpClient() {
261
+ return this._server?.client;
262
+ }
263
+ }
264
+ export {
265
+ GenkitMcpClient
266
+ };
267
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/client.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 { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { StdioServerParameters } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport type { StreamableHTTPClientTransportOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {\n ListRootsRequestSchema,\n Root,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n DynamicResourceAction,\n ExecutablePrompt,\n Genkit,\n GenkitError,\n PromptGenerateOptions,\n ToolAction,\n} from 'genkit';\nimport { logger } from 'genkit/logging';\nimport {\n fetchAllPrompts,\n fetchDynamicTools,\n getExecutablePrompt,\n transportFrom,\n} from '../util';\nimport { fetchDynamicResources } from '../util/resource';\n\ninterface McpServerRef {\n client: Client;\n transport: Transport;\n error?: string;\n}\n\nexport interface McpServerControls {\n /** when true, the server will be stopped and its registered components will\n * not appear in lists/plugins/etc */\n disabled?: boolean;\n\n // MCP roots configuration. See: https://modelcontextprotocol.io/docs/concepts/roots\n roots?: Root[];\n}\n\nexport type McpStdioServerConfig = StdioServerParameters & {\n url?: never;\n transport?: never;\n};\n\nexport type McpStreamableHttpConfig = {\n url: string;\n command?: never;\n transport?: never;\n} & Omit<StreamableHTTPClientTransportOptions, 'sessionId'>;\n\nexport type McpTransportServerConfig = {\n transport: Transport;\n command?: never;\n url?: never;\n};\n\n/**\n * Configuration for an individual MCP server. The interface should be familiar\n * and compatible with existing tool configurations e.g. Cursor or Claude\n * Desktop.\n *\n * In addition to stdio servers, remote servers are supported via URL and\n * custom/arbitary transports are supported as well.\n */\nexport type McpServerConfig = (\n | McpStdioServerConfig\n | McpStreamableHttpConfig\n | McpTransportServerConfig\n) &\n McpServerControls;\n\n/**\n * Configuration options for an individual `GenkitMcpClient` instance.\n * This defines how the client connects to a single MCP server and how it behaves.\n */\nexport type McpClientOptions = {\n /** Client name to advertise to the server. */\n name: string;\n /** Name for the server, defaults to the server's advertised name. */\n serverName?: string;\n\n /**\n * An optional version number for this client. This is primarily for logging\n * and identification purposes. Defaults to '1.0.0'.\n */\n version?: string;\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 /** The server configuration to connect. */\n mcpServer: McpServerConfig;\n /** Manually supply a session id for HTTP streaming clients if desired. */\n sessionId?: string;\n};\n\n/**\n * Represents a client connection to a single MCP (Model Context Protocol) server.\n * It handles the lifecycle of the connection (connect, disconnect, disable, re-enable, reconnect)\n * and provides methods to fetch tools from the connected server.\n *\n * An instance of `GenkitMcpClient` is typically managed by a `GenkitMcpHost`\n * when dealing with multiple MCP server connections.\n */\nexport class GenkitMcpClient {\n _server?: McpServerRef;\n\n sessionId?: string;\n readonly name: string;\n readonly suppliedServerName?: string;\n private version: string;\n private serverConfig: McpServerConfig;\n private rawToolResponses?: boolean;\n private disabled: boolean;\n private roots?: Root[];\n\n private _readyListeners: {\n resolve: () => void;\n reject: (err: Error) => void;\n }[] = [];\n private _ready = false;\n\n constructor(options: McpClientOptions) {\n this.name = options.name;\n this.suppliedServerName = options.serverName;\n this.version = options.version || '1.0.0';\n this.serverConfig = options.mcpServer;\n this.rawToolResponses = !!options.rawToolResponses;\n this.disabled = !!options.mcpServer.disabled;\n this.roots = options.mcpServer.roots;\n this.sessionId = options.sessionId;\n\n this._initializeConnection();\n }\n\n get serverName(): string {\n return (\n this.suppliedServerName ??\n this._server?.client.getServerVersion()?.name ??\n 'unknown-server'\n );\n }\n\n async updateRoots(roots: Root[]) {\n this.roots = roots;\n await this._server?.client.sendRootsListChanged();\n }\n\n /**\n * Sets up a connection based on a provided map of server configurations.\n * - Reconnects existing servers if their configuration appears to have\n * 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 private async _initializeConnection() {\n this._ready = false;\n try {\n await this._connect();\n this._ready = true;\n while (this._readyListeners.length) {\n this._readyListeners.pop()?.resolve();\n }\n } catch (err) {\n while (this._readyListeners.length) {\n this._readyListeners.pop()?.reject(err as Error);\n }\n }\n if (this.roots) {\n await this.updateRoots(this.roots);\n }\n }\n\n /**\n * Returns a Promise that resolves when the client has attempted to connect\n * to all configured servers, 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 * @param config The configuration object for the server.\n */\n private async _connect() {\n if (this._server) await this._server.transport.close();\n logger.debug(\n `[MCP Client] Connecting MCP server '${this.serverName}' in client '${this.name}'.`\n );\n\n const { transport, type: transportType } = await transportFrom(\n this.serverConfig,\n this.sessionId\n );\n if (!transport) {\n throw new GenkitError({\n status: 'INVALID_ARGUMENT',\n message: `[MCP Client] Could not determine valid transport config from supplied options.`,\n });\n }\n\n let error: string | undefined;\n\n const client = new Client(\n { name: this.name, version: this.version },\n { capabilities: { roots: { listChanged: true } } }\n );\n client.setRequestHandler(ListRootsRequestSchema, () => {\n logger.debug(`[MCP Client] fetching roots for ${this.name}`);\n return { roots: this.roots || [] };\n });\n\n try {\n await client.connect(transport);\n } catch (e) {\n logger.warn(\n `[MCP Client] Error connecting server via ${transportType} transport: ${e}`\n );\n this.disabled = true;\n error = (e as Error).toString();\n }\n\n this._server = {\n client,\n transport,\n error,\n } as McpServerRef;\n }\n\n /**\n * Disconnects the MCP server and removes its registration\n * from this client instance.\n */\n async _disconnect() {\n if (this._server) {\n logger.debug(\n `[MCP Client] Disconnecting MCP server in client '${this.name}'.`\n );\n await this._server.client.close();\n this._server = undefined;\n }\n }\n\n /**\n * Disables a server. Closes the underlying transport and server's configuration. Does nothing if the server is\n * already disabled.\n */\n async disable() {\n if (!this.isEnabled()) return;\n if (this._server) {\n logger.debug(\n `[MCP Client] Disabling MCP server in client '${this.name}'`\n );\n await this._disconnect();\n this.disabled = true;\n }\n }\n\n /**\n * Whether this client-server connection is enabled or not.\n */\n isEnabled() {\n return !this.disabled;\n }\n\n /**\n * Enables a server connection, including previously disabled ones. Does nothing if the\n * server is not disabled.\n */\n async enable() {\n if (this.isEnabled()) return;\n logger.debug(`[MCP Client] Reenabling MCP server in client '${this.name}'`);\n await this._initializeConnection();\n this.disabled = !!this._server!.error;\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 */\n async restart() {\n if (this._server) {\n logger.debug(\n `[MCP Client] Restarting connection to MCP server in client '${this.name}'`\n );\n await this._disconnect();\n await this._initializeConnection();\n }\n }\n\n /**\n * Fetches all tools available through this client, if the server\n * configuration is not disabled.\n */\n async getActiveTools(ai: Genkit): Promise<ToolAction[]> {\n await this.ready();\n let tools: ToolAction[] = [];\n\n if (this._server) {\n const capabilities = this._server.client.getServerCapabilities();\n if (capabilities?.tools)\n tools.push(\n ...(await fetchDynamicTools(ai, this._server.client, {\n rawToolResponses: this.rawToolResponses,\n serverName: this.serverName,\n name: this.name,\n }))\n );\n }\n\n return tools;\n }\n\n /**\n * Fetches all resources available through this client, if the server\n * configuration is not disabled.\n */\n async getActiveResources(ai: Genkit): Promise<DynamicResourceAction[]> {\n await this.ready();\n let resources: DynamicResourceAction[] = [];\n\n if (this._server) {\n const capabilities = this._server.client.getServerCapabilities();\n if (capabilities?.resources)\n resources.push(\n ...(await fetchDynamicResources(ai, this._server.client, {\n serverName: this.serverName,\n name: this.name,\n }))\n );\n }\n\n return resources;\n }\n\n /**\n * Fetches all active prompts available through this client, if the server\n * configuration supports prompts.\n * @param ai The Genkit instance.\n * @param options Optional prompt generation options.\n * @returns A promise that resolves to an array of ExecutablePrompt.\n */\n async getActivePrompts(\n ai: Genkit,\n options?: PromptGenerateOptions\n ): Promise<ExecutablePrompt[]> {\n if (this._server?.client.getServerCapabilities()?.prompts) {\n return fetchAllPrompts(this._server.client, {\n ai,\n serverName: this.serverName,\n name: this.name,\n options,\n });\n }\n return [];\n }\n\n /**\n * Get the specified prompt as an `ExecutablePrompt` available through this\n * client. If no such prompt is found, return undefined.\n */\n async getPrompt(\n ai: Genkit,\n promptName: string,\n opts?: PromptGenerateOptions\n ): Promise<ExecutablePrompt | undefined> {\n await this.ready();\n\n if (this._server) {\n const capabilities = await this._server.client.getServerCapabilities();\n if (capabilities?.prompts) {\n return await getExecutablePrompt(this._server.client, {\n ai,\n serverName: this.name,\n promptName,\n name: this.name,\n options: opts,\n });\n }\n logger.debug(`[MCP Client] No prompts are found in this MCP server.`);\n }\n return;\n }\n\n /** Returns the underlying MCP SDK client if one has been initialized. */\n get mcpClient(): Client | undefined {\n return this._server?.client;\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,202 @@
1
+ import '@modelcontextprotocol/sdk/client/sse.js';
2
+ import '@modelcontextprotocol/sdk/client/stdio.js';
3
+ import '@modelcontextprotocol/sdk/shared/transport.js';
4
+ import { McpServerConfig, GenkitMcpClient } from './client.mjs';
5
+ import { Root } from '@modelcontextprotocol/sdk/types.js';
6
+ import { Genkit, ToolAction, DynamicResourceAction, ExecutablePrompt, PromptGenerateOptions } from 'genkit';
7
+ import '@modelcontextprotocol/sdk/client/index.js';
8
+ import '@modelcontextprotocol/sdk/client/streamableHttp.js';
9
+
10
+ /**
11
+ * Copyright 2025 Google LLC
12
+ *
13
+ * Licensed under the Apache License, Version 2.0 (the "License");
14
+ * you may not use this file except in compliance with the License.
15
+ * You may obtain a copy of the License at
16
+ *
17
+ * http://www.apache.org/licenses/LICENSE-2.0
18
+ *
19
+ * Unless required by applicable law or agreed to in writing, software
20
+ * distributed under the License is distributed on an "AS IS" BASIS,
21
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ * See the License for the specific language governing permissions and
23
+ * limitations under the License.
24
+ */
25
+
26
+ interface McpHostOptions {
27
+ /**
28
+ * An optional client name for this MCP host. This name is advertised to MCP Servers
29
+ * as the connecting client name. Defaults to 'genkit-mcp'.
30
+ */
31
+ name?: string;
32
+ /**
33
+ * An optional version for this MCP host. Primarily for
34
+ * logging and identification within Genkit.
35
+ * Defaults to '1.0.0'.
36
+ */
37
+ version?: string;
38
+ /**
39
+ * A record for configuring multiple MCP servers. Each server connection is
40
+ * controlled by a `GenkitMcpClient` instance managed by `GenkitMcpHost`.
41
+ * The key in the record is used as the identifier for the MCP server.
42
+ */
43
+ mcpServers?: Record<string, McpServerConfig>;
44
+ /**
45
+ * If true, tool responses from the MCP server will be returned in their raw
46
+ * MCP format. Otherwise (default), they are processed and potentially
47
+ * simplified for better compatibility with Genkit's typical data structures.
48
+ */
49
+ rawToolResponses?: boolean;
50
+ /**
51
+ * 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.
52
+ */
53
+ roots?: Root[];
54
+ }
55
+ /**
56
+ * Manages connections to multiple MCP (Model Context Protocol) servers.
57
+ * Each server connection is individually configured and managed by an instance of `GenkitMcpClient`.
58
+ * This host provides a centralized way to initialize, update, and interact with these clients.
59
+ *
60
+ * It allows for dynamic registration of tools from all connected and enabled MCP servers
61
+ * into a Genkit instance.
62
+ */
63
+ declare class GenkitMcpHost {
64
+ name: string;
65
+ private _clients;
66
+ private _clientStates;
67
+ private _readyListeners;
68
+ private _ready;
69
+ private roots;
70
+ rawToolResponses?: boolean;
71
+ constructor(options: McpHostOptions);
72
+ /**
73
+ * Returns a Promise that resolves when the host has attempted to connect
74
+ * to all configured clients, or rejects if a critical error occurs during
75
+ * the initial connection phase.
76
+ */
77
+ ready(): Promise<void>;
78
+ /**
79
+ * Connects to a single MCP server defined by the provided configuration.
80
+ * If a server with the same name already exists, it will be disconnected first.
81
+ * Stores the client and transport references internally. Handles connection errors
82
+ * by marking the server as disabled.
83
+ * @param serverName The name to assign to this server connection.
84
+ * @param config The configuration object for the server.
85
+ */
86
+ connect(serverName: string, config: McpServerConfig): Promise<void>;
87
+ /**
88
+ * Disconnects the specified MCP server and removes its registration
89
+ * from this client instance.
90
+ * @param serverName The name of the server to disconnect.
91
+ */
92
+ disconnect(serverName: string): Promise<void>;
93
+ /**
94
+ * Temporarily disables a server connection. Closes the underlying transport
95
+ * but retains the server's configuration. Does nothing if the server is
96
+ * already disabled.
97
+ * @param serverName The name of the server to disable.
98
+ */
99
+ disable(serverName: string): Promise<void>;
100
+ /**
101
+ * Enables a server connection, including previously disabled ones. Attempts to reconnect
102
+ * using the stored transport. Does nothing if the server is not disabled.
103
+ * @param serverName The name of the server to re-enable.
104
+ */
105
+ enable(serverName: string): Promise<void>;
106
+ /**
107
+ * Closes and then restarts the transport connection for the specified server.
108
+ * Useful for attempting to recover from connection issues without full
109
+ * reconfiguration.
110
+ * @param serverName The name of the server to reconnect.
111
+ */
112
+ reconnect(serverName: string): Promise<void>;
113
+ /**
114
+ * Updates the connections based on a provided map of server configurations.
115
+ * - Connects any new servers defined in `mcpServers`.
116
+ * - Disconnects any servers currently connected but not present in `mcpServers`.
117
+ * - Reconnects existing servers if their configuration appears to have changed (implicitly handled by `connectServer`).
118
+ * Sets the client's ready state once all connection attempts are complete.
119
+ * @param mcpServers A record mapping server names to their configurations.
120
+ */
121
+ updateServers(mcpServers: Record<string, McpServerConfig>): void;
122
+ /**
123
+ * Retrieves all tools from all connected and enabled MCP clients managed by
124
+ * this instance. This method waits for the host to be ready (all initial
125
+ * connection attempts made) before fetching tools.
126
+ *
127
+ * It iterates through each managed `GenkitMcpClient`, and if the client is
128
+ * not disabled, it calls the client's `getTools` method to fetch its
129
+ * available tools. These are then aggregated into a single array.
130
+ *
131
+ * This is useful for dynamically providing a list of all available MCP tools
132
+ * to Genkit, for example, when setting up a Genkit plugin.
133
+ *
134
+ * ```ts
135
+ * const mcpHost = createMcpHost({ ... });
136
+ * // In your Genkit configuration:
137
+ * // const allMcpTools = await McpHost.getActiveTools(ai);
138
+ * // Then, these tools can be used or registered with Genkit.
139
+ * ```
140
+ *
141
+ * @param ai The Genkit instance, used by individual clients to define dynamic
142
+ * tools.
143
+ * @returns A Promise that resolves to an array of `ToolAction` from all
144
+ * active MCP clients.
145
+ */
146
+ getActiveTools(ai: Genkit): Promise<ToolAction[]>;
147
+ /**
148
+ * Retrieves all resources from all connected and enabled MCP clients managed by
149
+ * this instance. This method waits for the host to be ready (all initial
150
+ * connection attempts made) before fetching resources.
151
+ *
152
+ * It iterates through each managed `GenkitMcpClient`, and if the client is
153
+ * not disabled, it calls the client's `getActiveResources` method to fetch its
154
+ * available resources. These are then aggregated into a single array.
155
+ *
156
+ * This is useful for dynamically providing a list of all available MCP resources
157
+ * to Genkit, for example, when setting up a Genkit plugin.
158
+ *
159
+ * @param ai The Genkit instance, used by individual clients to define dynamic
160
+ * resources.
161
+ * @returns A Promise that resolves to an array of `DynamicResourceAction` from all
162
+ * active MCP clients.
163
+ */
164
+ getActiveResources(ai: Genkit): Promise<DynamicResourceAction[]>;
165
+ /**
166
+ * Retrieves all prompts from all connected and enabled MCP clients managed by
167
+ * this instance. This method waits for the host to be ready (all initial
168
+ * connection attempts made) before fetching prompts.
169
+ *
170
+ * It iterates through each managed `GenkitMcpClient`, and if the client is
171
+ * not disabled, it calls the client's `getActivePrompts` method to fetch its
172
+ * available prompts. These are then aggregated into a single array.
173
+ *
174
+ * This is useful for dynamically providing a list of all available MCP prompts
175
+ * to Genkit, for example, when setting up a Genkit plugin.
176
+ *
177
+ * @param ai The Genkit instance, used by individual clients to define dynamic
178
+ * prompts.
179
+ * @returns A Promise that resolves to an array of `ExecutablePrompt` from all
180
+ * active MCP clients.
181
+ */
182
+ getActivePrompts(ai: Genkit): Promise<ExecutablePrompt[]>;
183
+ /**
184
+ * Get the specified prompt as an `ExecutablePrompt` available through the
185
+ * specified server. If no such prompt is found, return undefined.
186
+ */
187
+ getPrompt(ai: Genkit, serverName: string, promptName: string, opts?: PromptGenerateOptions): Promise<ExecutablePrompt<any> | undefined>;
188
+ close(): Promise<void>;
189
+ /** Helper method to track and log client errors. */
190
+ private setError;
191
+ private hasError;
192
+ /**
193
+ * Returns an array of all active clients.
194
+ */
195
+ get activeClients(): GenkitMcpClient[];
196
+ /**
197
+ * Returns the client by name.
198
+ */
199
+ getClient(name: string): GenkitMcpClient;
200
+ }
201
+
202
+ export { GenkitMcpHost, type McpHostOptions };