@genkit-ai/mcp 1.33.0 → 1.35.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.
- package/lib/client/client.d.mts +9 -6
- package/lib/client/client.d.ts +9 -6
- package/lib/client/client.js +19 -7
- package/lib/client/client.js.map +1 -1
- package/lib/client/client.mjs +19 -7
- package/lib/client/client.mjs.map +1 -1
- package/lib/client/host.d.mts +11 -8
- package/lib/client/host.d.ts +11 -8
- package/lib/client/host.js +4 -1
- package/lib/client/host.js.map +1 -1
- package/lib/client/host.mjs +4 -1
- package/lib/client/host.mjs.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/index.mjs.map +1 -1
- package/lib/server.d.mts +4 -4
- package/lib/server.d.ts +4 -4
- package/lib/util/tools.d.mts +5 -3
- package/lib/util/tools.d.ts +5 -3
- package/lib/util/tools.js +152 -23
- package/lib/util/tools.js.map +1 -1
- package/lib/util/tools.mjs +156 -24
- package/lib/util/tools.mjs.map +1 -1
- package/package.json +3 -3
- package/src/client/client.ts +38 -14
- package/src/client/host.ts +23 -9
- package/src/index.ts +16 -9
- package/src/util/tools.ts +204 -35
- package/tests/host_test.ts +151 -1
- package/tests/tools_test.ts +201 -0
package/lib/client/client.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { StdioServerParameters } from '@modelcontextprotocol/sdk/client/stdio.js
|
|
|
3
3
|
import { StreamableHTTPClientTransportOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
4
|
import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
5
5
|
import { Root } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
-
import { DynamicActionProviderAction, Genkit, ToolAction, DynamicResourceAction, PromptGenerateOptions, ExecutablePrompt } from 'genkit';
|
|
6
|
+
import { DynamicActionProviderAction, Genkit, MultipartToolAction, ToolAction, DynamicResourceAction, PromptGenerateOptions, ExecutablePrompt } from 'genkit';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Copyright 2025 Google LLC
|
|
@@ -59,7 +59,7 @@ type McpServerConfig = (McpStdioServerConfig | McpStreamableHttpConfig | McpTran
|
|
|
59
59
|
* Configuration options for an individual `GenkitMcpClient` instance.
|
|
60
60
|
* This defines how the client connects to a single MCP server and how it behaves.
|
|
61
61
|
*/
|
|
62
|
-
type McpClientOptions = {
|
|
62
|
+
type McpClientOptions<M extends boolean = false> = {
|
|
63
63
|
/** Client name to advertise to the server. */
|
|
64
64
|
name: string;
|
|
65
65
|
/** Name for the server, defaults to the server's advertised name. */
|
|
@@ -75,12 +75,14 @@ type McpClientOptions = {
|
|
|
75
75
|
* simplified for better compatibility with Genkit's typical data structures.
|
|
76
76
|
*/
|
|
77
77
|
rawToolResponses?: boolean;
|
|
78
|
+
/** If true, tools will be registered as multipart tool.v2 actions. */
|
|
79
|
+
multipart?: M;
|
|
78
80
|
/** The server configuration to connect. */
|
|
79
81
|
mcpServer: McpServerConfig;
|
|
80
82
|
/** Manually supply a session id for HTTP streaming clients if desired. */
|
|
81
83
|
sessionId?: string;
|
|
82
84
|
};
|
|
83
|
-
type McpClientOptionsWithCache = McpClientOptions & {
|
|
85
|
+
type McpClientOptionsWithCache<M extends boolean = false> = McpClientOptions<M> & {
|
|
84
86
|
cacheTtlMillis?: number;
|
|
85
87
|
};
|
|
86
88
|
/**
|
|
@@ -91,7 +93,7 @@ type McpClientOptionsWithCache = McpClientOptions & {
|
|
|
91
93
|
* An instance of `GenkitMcpClient` is typically managed by a `GenkitMcpHost`
|
|
92
94
|
* when dealing with multiple MCP server connections.
|
|
93
95
|
*/
|
|
94
|
-
declare class GenkitMcpClient {
|
|
96
|
+
declare class GenkitMcpClient<Multipart extends boolean = false> {
|
|
95
97
|
_server?: McpServerRef;
|
|
96
98
|
private _dynamicActionProvider;
|
|
97
99
|
sessionId?: string;
|
|
@@ -100,11 +102,12 @@ declare class GenkitMcpClient {
|
|
|
100
102
|
private version;
|
|
101
103
|
private serverConfig;
|
|
102
104
|
private rawToolResponses?;
|
|
105
|
+
private multipart?;
|
|
103
106
|
private disabled;
|
|
104
107
|
private roots?;
|
|
105
108
|
private _readyListeners;
|
|
106
109
|
private _ready;
|
|
107
|
-
constructor(options: McpClientOptions);
|
|
110
|
+
constructor(options: McpClientOptions<Multipart>);
|
|
108
111
|
set dynamicActionProvider(dap: DynamicActionProviderAction);
|
|
109
112
|
_invalidateDapCache(): void;
|
|
110
113
|
get serverName(): string;
|
|
@@ -157,7 +160,7 @@ declare class GenkitMcpClient {
|
|
|
157
160
|
* Fetches all tools available through this client, if the server
|
|
158
161
|
* configuration is not disabled.
|
|
159
162
|
*/
|
|
160
|
-
getActiveTools(ai: Genkit): Promise<ToolAction[]>;
|
|
163
|
+
getActiveTools(ai: Genkit): Promise<(Multipart extends true ? MultipartToolAction : ToolAction)[]>;
|
|
161
164
|
/**
|
|
162
165
|
* Fetches all resources available through this client, if the server
|
|
163
166
|
* configuration is not disabled.
|
package/lib/client/client.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { StdioServerParameters } from '@modelcontextprotocol/sdk/client/stdio.js
|
|
|
3
3
|
import { StreamableHTTPClientTransportOptions } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
4
|
import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
5
5
|
import { Root } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
-
import { DynamicActionProviderAction, Genkit, ToolAction, DynamicResourceAction, PromptGenerateOptions, ExecutablePrompt } from 'genkit';
|
|
6
|
+
import { DynamicActionProviderAction, Genkit, MultipartToolAction, ToolAction, DynamicResourceAction, PromptGenerateOptions, ExecutablePrompt } from 'genkit';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Copyright 2025 Google LLC
|
|
@@ -59,7 +59,7 @@ type McpServerConfig = (McpStdioServerConfig | McpStreamableHttpConfig | McpTran
|
|
|
59
59
|
* Configuration options for an individual `GenkitMcpClient` instance.
|
|
60
60
|
* This defines how the client connects to a single MCP server and how it behaves.
|
|
61
61
|
*/
|
|
62
|
-
type McpClientOptions = {
|
|
62
|
+
type McpClientOptions<M extends boolean = false> = {
|
|
63
63
|
/** Client name to advertise to the server. */
|
|
64
64
|
name: string;
|
|
65
65
|
/** Name for the server, defaults to the server's advertised name. */
|
|
@@ -75,12 +75,14 @@ type McpClientOptions = {
|
|
|
75
75
|
* simplified for better compatibility with Genkit's typical data structures.
|
|
76
76
|
*/
|
|
77
77
|
rawToolResponses?: boolean;
|
|
78
|
+
/** If true, tools will be registered as multipart tool.v2 actions. */
|
|
79
|
+
multipart?: M;
|
|
78
80
|
/** The server configuration to connect. */
|
|
79
81
|
mcpServer: McpServerConfig;
|
|
80
82
|
/** Manually supply a session id for HTTP streaming clients if desired. */
|
|
81
83
|
sessionId?: string;
|
|
82
84
|
};
|
|
83
|
-
type McpClientOptionsWithCache = McpClientOptions & {
|
|
85
|
+
type McpClientOptionsWithCache<M extends boolean = false> = McpClientOptions<M> & {
|
|
84
86
|
cacheTtlMillis?: number;
|
|
85
87
|
};
|
|
86
88
|
/**
|
|
@@ -91,7 +93,7 @@ type McpClientOptionsWithCache = McpClientOptions & {
|
|
|
91
93
|
* An instance of `GenkitMcpClient` is typically managed by a `GenkitMcpHost`
|
|
92
94
|
* when dealing with multiple MCP server connections.
|
|
93
95
|
*/
|
|
94
|
-
declare class GenkitMcpClient {
|
|
96
|
+
declare class GenkitMcpClient<Multipart extends boolean = false> {
|
|
95
97
|
_server?: McpServerRef;
|
|
96
98
|
private _dynamicActionProvider;
|
|
97
99
|
sessionId?: string;
|
|
@@ -100,11 +102,12 @@ declare class GenkitMcpClient {
|
|
|
100
102
|
private version;
|
|
101
103
|
private serverConfig;
|
|
102
104
|
private rawToolResponses?;
|
|
105
|
+
private multipart?;
|
|
103
106
|
private disabled;
|
|
104
107
|
private roots?;
|
|
105
108
|
private _readyListeners;
|
|
106
109
|
private _ready;
|
|
107
|
-
constructor(options: McpClientOptions);
|
|
110
|
+
constructor(options: McpClientOptions<Multipart>);
|
|
108
111
|
set dynamicActionProvider(dap: DynamicActionProviderAction);
|
|
109
112
|
_invalidateDapCache(): void;
|
|
110
113
|
get serverName(): string;
|
|
@@ -157,7 +160,7 @@ declare class GenkitMcpClient {
|
|
|
157
160
|
* Fetches all tools available through this client, if the server
|
|
158
161
|
* configuration is not disabled.
|
|
159
162
|
*/
|
|
160
|
-
getActiveTools(ai: Genkit): Promise<ToolAction[]>;
|
|
163
|
+
getActiveTools(ai: Genkit): Promise<(Multipart extends true ? MultipartToolAction : ToolAction)[]>;
|
|
161
164
|
/**
|
|
162
165
|
* Fetches all resources available through this client, if the server
|
|
163
166
|
* configuration is not disabled.
|
package/lib/client/client.js
CHANGED
|
@@ -36,6 +36,7 @@ class GenkitMcpClient {
|
|
|
36
36
|
version;
|
|
37
37
|
serverConfig;
|
|
38
38
|
rawToolResponses;
|
|
39
|
+
multipart;
|
|
39
40
|
disabled;
|
|
40
41
|
roots;
|
|
41
42
|
_readyListeners = [];
|
|
@@ -46,6 +47,7 @@ class GenkitMcpClient {
|
|
|
46
47
|
this.version = options.version || "1.0.0";
|
|
47
48
|
this.serverConfig = options.mcpServer;
|
|
48
49
|
this.rawToolResponses = !!options.rawToolResponses;
|
|
50
|
+
this.multipart = !!options.multipart;
|
|
49
51
|
this.disabled = !!options.mcpServer.disabled;
|
|
50
52
|
this.roots = options.mcpServer.roots;
|
|
51
53
|
this.sessionId = options.sessionId;
|
|
@@ -215,19 +217,29 @@ class GenkitMcpClient {
|
|
|
215
217
|
*/
|
|
216
218
|
async getActiveTools(ai) {
|
|
217
219
|
await this.ready();
|
|
218
|
-
let tools = [];
|
|
219
220
|
if (this._server) {
|
|
220
221
|
const capabilities = this._server.client.getServerCapabilities();
|
|
221
|
-
if (capabilities?.tools)
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
if (capabilities?.tools) {
|
|
223
|
+
if (this.multipart) {
|
|
224
|
+
const tools = await (0, import_util.fetchDynamicTools)(ai, this._server.client, {
|
|
224
225
|
rawToolResponses: this.rawToolResponses,
|
|
226
|
+
multipart: true,
|
|
225
227
|
serverName: this.serverName,
|
|
226
228
|
name: this.name
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
+
});
|
|
230
|
+
return tools;
|
|
231
|
+
} else {
|
|
232
|
+
const tools = await (0, import_util.fetchDynamicTools)(ai, this._server.client, {
|
|
233
|
+
rawToolResponses: this.rawToolResponses,
|
|
234
|
+
multipart: false,
|
|
235
|
+
serverName: this.serverName,
|
|
236
|
+
name: this.name
|
|
237
|
+
});
|
|
238
|
+
return tools;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
229
241
|
}
|
|
230
|
-
return
|
|
242
|
+
return [];
|
|
231
243
|
}
|
|
232
244
|
/**
|
|
233
245
|
* Fetches all resources available through this client, if the server
|
package/lib/client/client.js.map
CHANGED
|
@@ -1 +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 GenkitError,\n type DynamicActionProviderAction,\n type DynamicResourceAction,\n type ExecutablePrompt,\n type Genkit,\n type PromptGenerateOptions,\n type 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\nexport type McpClientOptionsWithCache = McpClientOptions & {\n cacheTtlMillis?: number;\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 private _dynamicActionProvider: DynamicActionProviderAction | undefined;\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 set dynamicActionProvider(dap: DynamicActionProviderAction) {\n this._dynamicActionProvider = dap;\n }\n\n _invalidateDapCache(): void {\n if (this._dynamicActionProvider) {\n this._dynamicActionProvider.invalidateCache();\n }\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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":[]}
|
|
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 GenkitError,\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 {\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<M extends boolean = false> = {\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 /** If true, tools will be registered as multipart tool.v2 actions. */\n multipart?: M;\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\nexport type McpClientOptionsWithCache<M extends boolean = false> =\n McpClientOptions<M> & {\n cacheTtlMillis?: number;\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<Multipart extends boolean = false> {\n _server?: McpServerRef;\n private _dynamicActionProvider: DynamicActionProviderAction | undefined;\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 multipart?: 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<Multipart>) {\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.multipart = !!options.multipart;\n this.disabled = !!options.mcpServer.disabled;\n this.roots = options.mcpServer.roots;\n this.sessionId = options.sessionId;\n\n this._initializeConnection();\n }\n\n set dynamicActionProvider(dap: DynamicActionProviderAction) {\n this._dynamicActionProvider = dap;\n }\n\n _invalidateDapCache(): void {\n if (this._dynamicActionProvider) {\n this._dynamicActionProvider.invalidateCache();\n }\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\n }\n }\n\n /**\n * Fetches all tools available through this client, if the server\n * configuration is not disabled.\n */\n async getActiveTools(\n ai: Genkit\n ): Promise<(Multipart extends true ? MultipartToolAction : ToolAction)[]> {\n await this.ready();\n\n if (this._server) {\n const capabilities = this._server.client.getServerCapabilities();\n if (capabilities?.tools) {\n if (this.multipart) {\n const tools = await fetchDynamicTools(ai, this._server.client, {\n rawToolResponses: this.rawToolResponses,\n multipart: true,\n serverName: this.serverName,\n name: this.name,\n });\n return tools as unknown as (Multipart extends true\n ? MultipartToolAction\n : ToolAction)[];\n } else {\n const tools = await fetchDynamicTools(ai, this._server.client, {\n rawToolResponses: this.rawToolResponses,\n multipart: false,\n serverName: this.serverName,\n name: this.name,\n });\n return tools as unknown as (Multipart extends true\n ? MultipartToolAction\n : ToolAction)[];\n }\n }\n }\n\n return [] as unknown as (Multipart extends true\n ? MultipartToolAction\n : ToolAction)[];\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":[]}
|
package/lib/client/client.mjs
CHANGED
|
@@ -22,6 +22,7 @@ class GenkitMcpClient {
|
|
|
22
22
|
version;
|
|
23
23
|
serverConfig;
|
|
24
24
|
rawToolResponses;
|
|
25
|
+
multipart;
|
|
25
26
|
disabled;
|
|
26
27
|
roots;
|
|
27
28
|
_readyListeners = [];
|
|
@@ -32,6 +33,7 @@ class GenkitMcpClient {
|
|
|
32
33
|
this.version = options.version || "1.0.0";
|
|
33
34
|
this.serverConfig = options.mcpServer;
|
|
34
35
|
this.rawToolResponses = !!options.rawToolResponses;
|
|
36
|
+
this.multipart = !!options.multipart;
|
|
35
37
|
this.disabled = !!options.mcpServer.disabled;
|
|
36
38
|
this.roots = options.mcpServer.roots;
|
|
37
39
|
this.sessionId = options.sessionId;
|
|
@@ -201,19 +203,29 @@ class GenkitMcpClient {
|
|
|
201
203
|
*/
|
|
202
204
|
async getActiveTools(ai) {
|
|
203
205
|
await this.ready();
|
|
204
|
-
let tools = [];
|
|
205
206
|
if (this._server) {
|
|
206
207
|
const capabilities = this._server.client.getServerCapabilities();
|
|
207
|
-
if (capabilities?.tools)
|
|
208
|
-
|
|
209
|
-
|
|
208
|
+
if (capabilities?.tools) {
|
|
209
|
+
if (this.multipart) {
|
|
210
|
+
const tools = await fetchDynamicTools(ai, this._server.client, {
|
|
210
211
|
rawToolResponses: this.rawToolResponses,
|
|
212
|
+
multipart: true,
|
|
211
213
|
serverName: this.serverName,
|
|
212
214
|
name: this.name
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
+
});
|
|
216
|
+
return tools;
|
|
217
|
+
} else {
|
|
218
|
+
const tools = await fetchDynamicTools(ai, this._server.client, {
|
|
219
|
+
rawToolResponses: this.rawToolResponses,
|
|
220
|
+
multipart: false,
|
|
221
|
+
serverName: this.serverName,
|
|
222
|
+
name: this.name
|
|
223
|
+
});
|
|
224
|
+
return tools;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
215
227
|
}
|
|
216
|
-
return
|
|
228
|
+
return [];
|
|
217
229
|
}
|
|
218
230
|
/**
|
|
219
231
|
* Fetches all resources available through this client, if the server
|
|
@@ -1 +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 GenkitError,\n type DynamicActionProviderAction,\n type DynamicResourceAction,\n type ExecutablePrompt,\n type Genkit,\n type PromptGenerateOptions,\n type 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\nexport type McpClientOptionsWithCache = McpClientOptions & {\n cacheTtlMillis?: number;\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 private _dynamicActionProvider: DynamicActionProviderAction | undefined;\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 set dynamicActionProvider(dap: DynamicActionProviderAction) {\n this._dynamicActionProvider = dap;\n }\n\n _invalidateDapCache(): void {\n if (this._dynamicActionProvider) {\n this._dynamicActionProvider.invalidateCache();\n }\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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":[]}
|
|
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 GenkitError,\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 {\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<M extends boolean = false> = {\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 /** If true, tools will be registered as multipart tool.v2 actions. */\n multipart?: M;\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\nexport type McpClientOptionsWithCache<M extends boolean = false> =\n McpClientOptions<M> & {\n cacheTtlMillis?: number;\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<Multipart extends boolean = false> {\n _server?: McpServerRef;\n private _dynamicActionProvider: DynamicActionProviderAction | undefined;\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 multipart?: 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<Multipart>) {\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.multipart = !!options.multipart;\n this.disabled = !!options.mcpServer.disabled;\n this.roots = options.mcpServer.roots;\n this.sessionId = options.sessionId;\n\n this._initializeConnection();\n }\n\n set dynamicActionProvider(dap: DynamicActionProviderAction) {\n this._dynamicActionProvider = dap;\n }\n\n _invalidateDapCache(): void {\n if (this._dynamicActionProvider) {\n this._dynamicActionProvider.invalidateCache();\n }\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\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 this._invalidateDapCache();\n }\n }\n\n /**\n * Fetches all tools available through this client, if the server\n * configuration is not disabled.\n */\n async getActiveTools(\n ai: Genkit\n ): Promise<(Multipart extends true ? MultipartToolAction : ToolAction)[]> {\n await this.ready();\n\n if (this._server) {\n const capabilities = this._server.client.getServerCapabilities();\n if (capabilities?.tools) {\n if (this.multipart) {\n const tools = await fetchDynamicTools(ai, this._server.client, {\n rawToolResponses: this.rawToolResponses,\n multipart: true,\n serverName: this.serverName,\n name: this.name,\n });\n return tools as unknown as (Multipart extends true\n ? MultipartToolAction\n : ToolAction)[];\n } else {\n const tools = await fetchDynamicTools(ai, this._server.client, {\n rawToolResponses: this.rawToolResponses,\n multipart: false,\n serverName: this.serverName,\n name: this.name,\n });\n return tools as unknown as (Multipart extends true\n ? MultipartToolAction\n : ToolAction)[];\n }\n }\n }\n\n return [] as unknown as (Multipart extends true\n ? MultipartToolAction\n : ToolAction)[];\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":[]}
|
package/lib/client/host.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import '@modelcontextprotocol/sdk/client/stdio.js';
|
|
|
3
3
|
import '@modelcontextprotocol/sdk/shared/transport.js';
|
|
4
4
|
import { McpServerConfig, GenkitMcpClient } from './client.mjs';
|
|
5
5
|
import { Root } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
-
import { DynamicActionProviderAction, Genkit, ToolAction, DynamicResourceAction, ExecutablePrompt, PromptGenerateOptions } from 'genkit';
|
|
6
|
+
import { DynamicActionProviderAction, Genkit, MultipartToolAction, ToolAction, DynamicResourceAction, ExecutablePrompt, PromptGenerateOptions } from 'genkit';
|
|
7
7
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
8
8
|
import '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
9
9
|
|
|
@@ -23,7 +23,7 @@ import '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
|
23
23
|
* limitations under the License.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
interface McpHostOptions {
|
|
26
|
+
interface McpHostOptions<M extends boolean = false> {
|
|
27
27
|
/**
|
|
28
28
|
* An optional client name for this MCP host. This name is advertised to MCP Servers
|
|
29
29
|
* as the connecting client name. Defaults to 'genkit-mcp'.
|
|
@@ -47,12 +47,14 @@ interface McpHostOptions {
|
|
|
47
47
|
* simplified for better compatibility with Genkit's typical data structures.
|
|
48
48
|
*/
|
|
49
49
|
rawToolResponses?: boolean;
|
|
50
|
+
/** If true, tools will be registered as multipart tool.v2 actions. */
|
|
51
|
+
multipart?: M;
|
|
50
52
|
/**
|
|
51
53
|
* 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
54
|
*/
|
|
53
55
|
roots?: Root[];
|
|
54
56
|
}
|
|
55
|
-
type McpHostOptionsWithCache = Omit<McpHostOptions
|
|
57
|
+
type McpHostOptionsWithCache<M extends boolean = false> = Omit<McpHostOptions<M>, 'name'> & {
|
|
56
58
|
/**
|
|
57
59
|
* A client name for this MCP host. This name is advertised to MCP Servers
|
|
58
60
|
* as the connecting client name.
|
|
@@ -76,7 +78,7 @@ type McpHostOptionsWithCache = Omit<McpHostOptions, 'name'> & {
|
|
|
76
78
|
* It allows for dynamic registration of tools from all connected and enabled MCP servers
|
|
77
79
|
* into a Genkit instance.
|
|
78
80
|
*/
|
|
79
|
-
declare class GenkitMcpHost {
|
|
81
|
+
declare class GenkitMcpHost<Multipart extends boolean = false> {
|
|
80
82
|
name: string;
|
|
81
83
|
private _clients;
|
|
82
84
|
private _clientStates;
|
|
@@ -85,7 +87,8 @@ declare class GenkitMcpHost {
|
|
|
85
87
|
private _dynamicActionProvider;
|
|
86
88
|
private roots;
|
|
87
89
|
rawToolResponses?: boolean;
|
|
88
|
-
|
|
90
|
+
multipart?: Multipart;
|
|
91
|
+
constructor(options: McpHostOptions<Multipart>);
|
|
89
92
|
set dynamicActionProvider(dap: DynamicActionProviderAction);
|
|
90
93
|
_invalidateCache(): void;
|
|
91
94
|
/**
|
|
@@ -162,7 +165,7 @@ declare class GenkitMcpHost {
|
|
|
162
165
|
* @returns A Promise that resolves to an array of `ToolAction` from all
|
|
163
166
|
* active MCP clients.
|
|
164
167
|
*/
|
|
165
|
-
getActiveTools(ai: Genkit): Promise<ToolAction[]>;
|
|
168
|
+
getActiveTools(ai: Genkit): Promise<(Multipart extends true ? MultipartToolAction : ToolAction)[]>;
|
|
166
169
|
/**
|
|
167
170
|
* Retrieves all resources from all connected and enabled MCP clients managed by
|
|
168
171
|
* this instance. This method waits for the host to be ready (all initial
|
|
@@ -211,11 +214,11 @@ declare class GenkitMcpHost {
|
|
|
211
214
|
/**
|
|
212
215
|
* Returns an array of all active clients.
|
|
213
216
|
*/
|
|
214
|
-
get activeClients(): GenkitMcpClient[];
|
|
217
|
+
get activeClients(): GenkitMcpClient<Multipart>[];
|
|
215
218
|
/**
|
|
216
219
|
* Returns the client by name.
|
|
217
220
|
*/
|
|
218
|
-
getClient(name: string): GenkitMcpClient
|
|
221
|
+
getClient(name: string): GenkitMcpClient<Multipart>;
|
|
219
222
|
}
|
|
220
223
|
|
|
221
224
|
export { GenkitMcpHost, type McpHostOptions, type McpHostOptionsWithCache };
|
package/lib/client/host.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import '@modelcontextprotocol/sdk/client/stdio.js';
|
|
|
3
3
|
import '@modelcontextprotocol/sdk/shared/transport.js';
|
|
4
4
|
import { McpServerConfig, GenkitMcpClient } from './client.js';
|
|
5
5
|
import { Root } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
-
import { DynamicActionProviderAction, Genkit, ToolAction, DynamicResourceAction, ExecutablePrompt, PromptGenerateOptions } from 'genkit';
|
|
6
|
+
import { DynamicActionProviderAction, Genkit, MultipartToolAction, ToolAction, DynamicResourceAction, ExecutablePrompt, PromptGenerateOptions } from 'genkit';
|
|
7
7
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
8
8
|
import '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
9
9
|
|
|
@@ -23,7 +23,7 @@ import '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
|
23
23
|
* limitations under the License.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
interface McpHostOptions {
|
|
26
|
+
interface McpHostOptions<M extends boolean = false> {
|
|
27
27
|
/**
|
|
28
28
|
* An optional client name for this MCP host. This name is advertised to MCP Servers
|
|
29
29
|
* as the connecting client name. Defaults to 'genkit-mcp'.
|
|
@@ -47,12 +47,14 @@ interface McpHostOptions {
|
|
|
47
47
|
* simplified for better compatibility with Genkit's typical data structures.
|
|
48
48
|
*/
|
|
49
49
|
rawToolResponses?: boolean;
|
|
50
|
+
/** If true, tools will be registered as multipart tool.v2 actions. */
|
|
51
|
+
multipart?: M;
|
|
50
52
|
/**
|
|
51
53
|
* 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
54
|
*/
|
|
53
55
|
roots?: Root[];
|
|
54
56
|
}
|
|
55
|
-
type McpHostOptionsWithCache = Omit<McpHostOptions
|
|
57
|
+
type McpHostOptionsWithCache<M extends boolean = false> = Omit<McpHostOptions<M>, 'name'> & {
|
|
56
58
|
/**
|
|
57
59
|
* A client name for this MCP host. This name is advertised to MCP Servers
|
|
58
60
|
* as the connecting client name.
|
|
@@ -76,7 +78,7 @@ type McpHostOptionsWithCache = Omit<McpHostOptions, 'name'> & {
|
|
|
76
78
|
* It allows for dynamic registration of tools from all connected and enabled MCP servers
|
|
77
79
|
* into a Genkit instance.
|
|
78
80
|
*/
|
|
79
|
-
declare class GenkitMcpHost {
|
|
81
|
+
declare class GenkitMcpHost<Multipart extends boolean = false> {
|
|
80
82
|
name: string;
|
|
81
83
|
private _clients;
|
|
82
84
|
private _clientStates;
|
|
@@ -85,7 +87,8 @@ declare class GenkitMcpHost {
|
|
|
85
87
|
private _dynamicActionProvider;
|
|
86
88
|
private roots;
|
|
87
89
|
rawToolResponses?: boolean;
|
|
88
|
-
|
|
90
|
+
multipart?: Multipart;
|
|
91
|
+
constructor(options: McpHostOptions<Multipart>);
|
|
89
92
|
set dynamicActionProvider(dap: DynamicActionProviderAction);
|
|
90
93
|
_invalidateCache(): void;
|
|
91
94
|
/**
|
|
@@ -162,7 +165,7 @@ declare class GenkitMcpHost {
|
|
|
162
165
|
* @returns A Promise that resolves to an array of `ToolAction` from all
|
|
163
166
|
* active MCP clients.
|
|
164
167
|
*/
|
|
165
|
-
getActiveTools(ai: Genkit): Promise<ToolAction[]>;
|
|
168
|
+
getActiveTools(ai: Genkit): Promise<(Multipart extends true ? MultipartToolAction : ToolAction)[]>;
|
|
166
169
|
/**
|
|
167
170
|
* Retrieves all resources from all connected and enabled MCP clients managed by
|
|
168
171
|
* this instance. This method waits for the host to be ready (all initial
|
|
@@ -211,11 +214,11 @@ declare class GenkitMcpHost {
|
|
|
211
214
|
/**
|
|
212
215
|
* Returns an array of all active clients.
|
|
213
216
|
*/
|
|
214
|
-
get activeClients(): GenkitMcpClient[];
|
|
217
|
+
get activeClients(): GenkitMcpClient<Multipart>[];
|
|
215
218
|
/**
|
|
216
219
|
* Returns the client by name.
|
|
217
220
|
*/
|
|
218
|
-
getClient(name: string): GenkitMcpClient
|
|
221
|
+
getClient(name: string): GenkitMcpClient<Multipart>;
|
|
219
222
|
}
|
|
220
223
|
|
|
221
224
|
export { GenkitMcpHost, type McpHostOptions, type McpHostOptionsWithCache };
|
package/lib/client/host.js
CHANGED
|
@@ -32,9 +32,11 @@ class GenkitMcpHost {
|
|
|
32
32
|
_dynamicActionProvider;
|
|
33
33
|
roots;
|
|
34
34
|
rawToolResponses;
|
|
35
|
+
multipart;
|
|
35
36
|
constructor(options) {
|
|
36
37
|
this.name = options.name || "genkit-mcp";
|
|
37
38
|
this.rawToolResponses = options.rawToolResponses;
|
|
39
|
+
this.multipart = options.multipart;
|
|
38
40
|
this.roots = options.roots;
|
|
39
41
|
if (options.mcpServers) {
|
|
40
42
|
this.updateServers(options.mcpServers);
|
|
@@ -90,7 +92,8 @@ class GenkitMcpHost {
|
|
|
90
92
|
name: this.name,
|
|
91
93
|
serverName,
|
|
92
94
|
mcpServer: { ...config, roots: config.roots || this.roots },
|
|
93
|
-
rawToolResponses: this.rawToolResponses
|
|
95
|
+
rawToolResponses: this.rawToolResponses,
|
|
96
|
+
multipart: this.multipart
|
|
94
97
|
});
|
|
95
98
|
this._clients[serverName] = client;
|
|
96
99
|
} catch (e) {
|