@copilotkit/runtime 1.8.5-next.2 → 1.8.5-next.4

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 (47) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/{chunk-PJX3FQOX.mjs → chunk-574FKWP5.mjs} +2 -2
  3. package/dist/{chunk-FZJAYGIR.mjs → chunk-DNI7KA7Y.mjs} +2 -2
  4. package/dist/{chunk-A7E5UM7B.mjs → chunk-GGXHVDCG.mjs} +2 -2
  5. package/dist/{chunk-A4MGCX6X.mjs → chunk-PKO7BUPS.mjs} +186 -14
  6. package/dist/chunk-PKO7BUPS.mjs.map +1 -0
  7. package/dist/chunk-Q6JA6YY3.mjs +1 -0
  8. package/dist/{chunk-7VNWCLG4.mjs → chunk-WQZQTGHT.mjs} +2 -2
  9. package/dist/index.d.ts +8 -8
  10. package/dist/index.js +4042 -3862
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +10 -6
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/lib/index.d.ts +7 -7
  15. package/dist/lib/index.js +3890 -3710
  16. package/dist/lib/index.js.map +1 -1
  17. package/dist/lib/index.mjs +10 -6
  18. package/dist/lib/integrations/index.d.ts +4 -4
  19. package/dist/lib/integrations/index.js +1 -1
  20. package/dist/lib/integrations/index.js.map +1 -1
  21. package/dist/lib/integrations/index.mjs +5 -5
  22. package/dist/lib/integrations/nest/index.d.ts +3 -3
  23. package/dist/lib/integrations/nest/index.js +1 -1
  24. package/dist/lib/integrations/nest/index.js.map +1 -1
  25. package/dist/lib/integrations/nest/index.mjs +3 -3
  26. package/dist/lib/integrations/node-express/index.d.ts +3 -3
  27. package/dist/lib/integrations/node-express/index.js +1 -1
  28. package/dist/lib/integrations/node-express/index.js.map +1 -1
  29. package/dist/lib/integrations/node-express/index.mjs +3 -3
  30. package/dist/lib/integrations/node-http/index.d.ts +3 -3
  31. package/dist/lib/integrations/node-http/index.js +1 -1
  32. package/dist/lib/integrations/node-http/index.js.map +1 -1
  33. package/dist/lib/integrations/node-http/index.mjs +2 -2
  34. package/dist/service-adapters/index.mjs +1 -1
  35. package/dist/{copilot-runtime-9347bd66.d.ts → shared-86ec42e7.d.ts} +130 -45
  36. package/package.json +2 -2
  37. package/src/lib/index.ts +2 -1
  38. package/src/lib/runtime/copilot-runtime.ts +218 -11
  39. package/src/lib/runtime/mcp-tools-utils.ts +117 -0
  40. package/src/lib/runtime/remote-lg-action.ts +24 -2
  41. package/dist/chunk-A4MGCX6X.mjs.map +0 -1
  42. package/dist/chunk-PTC5JN3P.mjs +0 -1
  43. /package/dist/{chunk-PJX3FQOX.mjs.map → chunk-574FKWP5.mjs.map} +0 -0
  44. /package/dist/{chunk-FZJAYGIR.mjs.map → chunk-DNI7KA7Y.mjs.map} +0 -0
  45. /package/dist/{chunk-A7E5UM7B.mjs.map → chunk-GGXHVDCG.mjs.map} +0 -0
  46. /package/dist/{chunk-PTC5JN3P.mjs.map → chunk-Q6JA6YY3.mjs.map} +0 -0
  47. /package/dist/{chunk-7VNWCLG4.mjs.map → chunk-WQZQTGHT.mjs.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  copilotRuntimeNodeHttpEndpoint
3
- } from "../../../chunk-A4MGCX6X.mjs";
4
- import "../../../chunk-FZJAYGIR.mjs";
3
+ } from "../../../chunk-PKO7BUPS.mjs";
4
+ import "../../../chunk-DNI7KA7Y.mjs";
5
5
  import "../../../chunk-5BIEM2UU.mjs";
6
6
  import "../../../chunk-RTFJTJMA.mjs";
7
7
  import "../../../chunk-2OZAGFV3.mjs";
@@ -10,7 +10,7 @@ import {
10
10
  OpenAIAssistantAdapter,
11
11
  RemoteChain,
12
12
  UnifyAdapter
13
- } from "../chunk-FZJAYGIR.mjs";
13
+ } from "../chunk-DNI7KA7Y.mjs";
14
14
  import "../chunk-FHD4JECV.mjs";
15
15
  export {
16
16
  AnthropicAdapter,
@@ -1,52 +1,11 @@
1
- import { Parameter, Action } from '@copilotkit/shared';
2
- import { b as CopilotServiceAdapter, R as RemoteChainParameters, A as ActionInput, d as AgentSessionInput, e as AgentStateInput, F as ForwardedParametersInput, E as ExtensionsInput, f as RuntimeEventSource, g as ExtensionsResponse } from './langserve-6f7af8d3.js';
3
- import { M as MessageInput, a as Message } from './index-5bec5424.js';
4
1
  import * as graphql from 'graphql';
5
2
  import * as pino from 'pino';
6
3
  import { YogaInitialContext, createYoga } from 'graphql-yoga';
4
+ import { Parameter, Action } from '@copilotkit/shared';
5
+ import { b as CopilotServiceAdapter, A as ActionInput, d as AgentSessionInput, e as AgentStateInput, F as ForwardedParametersInput, E as ExtensionsInput, R as RemoteChainParameters, f as RuntimeEventSource, g as ExtensionsResponse } from './langserve-6f7af8d3.js';
6
+ import { M as MessageInput, a as Message } from './index-5bec5424.js';
7
7
  import { CopilotCloudOptions } from './lib/cloud/index.js';
8
8
 
9
- type LogLevel = "debug" | "info" | "warn" | "error";
10
- type CopilotRuntimeLogger = ReturnType<typeof createLogger>;
11
- declare function createLogger(options?: {
12
- level?: LogLevel;
13
- component?: string;
14
- }): pino.Logger<never>;
15
-
16
- declare const logger: pino.Logger<never>;
17
- declare const addCustomHeaderPlugin: {
18
- onResponse({ response }: {
19
- response: any;
20
- }): void;
21
- };
22
- type AnyPrimitive = string | boolean | number | null;
23
- type CopilotRequestContextProperties = Record<string, AnyPrimitive | Record<string, AnyPrimitive>>;
24
- type GraphQLContext = YogaInitialContext & {
25
- _copilotkit: CreateCopilotRuntimeServerOptions;
26
- properties: CopilotRequestContextProperties;
27
- logger: typeof logger;
28
- };
29
- interface CreateCopilotRuntimeServerOptions {
30
- runtime: CopilotRuntime<any>;
31
- serviceAdapter: CopilotServiceAdapter;
32
- endpoint: string;
33
- baseUrl?: string;
34
- cloud?: CopilotCloudOptions;
35
- properties?: CopilotRequestContextProperties;
36
- logLevel?: LogLevel;
37
- }
38
- declare function createContext(initialContext: YogaInitialContext, copilotKitContext: CreateCopilotRuntimeServerOptions, contextLogger: typeof logger, properties?: CopilotRequestContextProperties): Promise<Partial<GraphQLContext>>;
39
- declare function buildSchema(options?: {
40
- emitSchemaFile?: string;
41
- }): graphql.GraphQLSchema;
42
- type CommonConfig = {
43
- logging: typeof logger;
44
- schema: ReturnType<typeof buildSchema>;
45
- plugins: Parameters<typeof createYoga>[0]["plugins"];
46
- context: (ctx: YogaInitialContext) => Promise<Partial<GraphQLContext>>;
47
- };
48
- declare function getCommonConfig(options: CreateCopilotRuntimeServerOptions): CommonConfig;
49
-
50
9
  declare enum MetaEventName {
51
10
  LangGraphInterruptEvent = "LangGraphInterruptEvent",
52
11
  CopilotKitLangGraphInterruptEvent = "CopilotKitLangGraphInterruptEvent"
@@ -167,6 +126,53 @@ interface CopilotObservabilityConfig {
167
126
  hooks: CopilotObservabilityHooks;
168
127
  }
169
128
 
129
+ /**
130
+ * Represents a tool provided by an MCP server.
131
+ */
132
+ interface MCPTool {
133
+ description?: string;
134
+ /** Schema defining parameters, mirroring the MCP structure. */
135
+ schema?: {
136
+ parameters?: {
137
+ properties?: Record<string, any>;
138
+ required?: string[];
139
+ };
140
+ };
141
+ /** The function to call to execute the tool on the MCP server. */
142
+ execute(options: {
143
+ params: any;
144
+ }): Promise<any>;
145
+ }
146
+ /**
147
+ * Defines the contract for *any* MCP client implementation the user might provide.
148
+ */
149
+ interface MCPClient {
150
+ /** A method that returns a map of tool names to MCPTool objects available from the connected MCP server. */
151
+ tools(): Promise<Record<string, MCPTool>>;
152
+ /** An optional method for cleanup if the underlying client requires explicit disconnection. */
153
+ close?(): Promise<void>;
154
+ }
155
+ /**
156
+ * Configuration for connecting to an MCP endpoint.
157
+ */
158
+ interface MCPEndpointConfig {
159
+ endpoint: string;
160
+ apiKey?: string;
161
+ }
162
+ /**
163
+ * Extracts CopilotKit-compatible parameters from an MCP tool schema.
164
+ * @param toolSchema The schema object from an MCPTool.
165
+ * @returns An array of Parameter objects.
166
+ */
167
+ declare function extractParametersFromSchema(toolSchema?: MCPTool["schema"]): Parameter[];
168
+ /**
169
+ * Converts a map of MCPTools into an array of CopilotKit Actions.
170
+ * @param mcpTools A record mapping tool names to MCPTool objects.
171
+ * @param mcpEndpoint The endpoint URL from which these tools were fetched.
172
+ * @returns An array of Action<any> objects.
173
+ */
174
+ declare function convertMCPToolsToActions(mcpTools: Record<string, MCPTool>, mcpEndpoint: string): Action<any>[];
175
+
170
176
  /**
171
177
  * <Callout type="info">
172
178
  * This is the reference for the `CopilotRuntime` class. For more information and example code snippets, please see [Concept: Copilot Runtime](/concepts/copilot-runtime).
@@ -181,6 +187,7 @@ interface CopilotObservabilityConfig {
181
187
  * ```
182
188
  */
183
189
 
190
+ type CreateMCPClientFunction = (config: MCPEndpointConfig) => Promise<MCPClient>;
184
191
  interface CopilotRuntimeRequest {
185
192
  serviceAdapter: CopilotServiceAdapter;
186
193
  messages: MessageInput[];
@@ -290,6 +297,39 @@ interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []> {
290
297
  * ```
291
298
  */
292
299
  observability_c?: CopilotObservabilityConfig;
300
+ /**
301
+ * Configuration for connecting to Model Context Protocol (MCP) servers.
302
+ * Allows fetching and using tools defined on external MCP-compliant servers.
303
+ * Requires providing the `createMCPClient` function during instantiation.
304
+ * @experimental
305
+ */
306
+ mcpEndpoints?: MCPEndpointConfig[];
307
+ /**
308
+ * A function that creates an MCP client instance for a given endpoint configuration.
309
+ * This function is responsible for using the appropriate MCP client library
310
+ * (e.g., `@copilotkit/runtime`, `ai`) to establish a connection.
311
+ * Required if `mcpEndpoints` is provided.
312
+ *
313
+ * ```typescript
314
+ * import { experimental_createMCPClient } from "ai"; // Import from vercel ai library
315
+ * // ...
316
+ * const runtime = new CopilotRuntime({
317
+ * mcpEndpoints: [{ endpoint: "..." }],
318
+ * async createMCPClient(config) {
319
+ * return await experimental_createMCPClient({
320
+ * transport: {
321
+ * type: "sse",
322
+ * url: config.endpoint,
323
+ * headers: config.apiKey
324
+ * ? { Authorization: `Bearer ${config.apiKey}` }
325
+ * : undefined,
326
+ * },
327
+ * });
328
+ * }
329
+ * });
330
+ * ```
331
+ */
332
+ createMCPClient?: CreateMCPClientFunction;
293
333
  }
294
334
  declare class CopilotRuntime<const T extends Parameter[] | [] = []> {
295
335
  actions: ActionsConfiguration<T>;
@@ -300,7 +340,11 @@ declare class CopilotRuntime<const T extends Parameter[] | [] = []> {
300
340
  private delegateAgentProcessingToServiceAdapter;
301
341
  private observability?;
302
342
  private availableAgents;
343
+ private readonly mcpEndpointsConfig?;
344
+ private mcpActionCache;
345
+ private readonly createMCPClientImpl?;
303
346
  constructor(params?: CopilotRuntimeConstructorParams<T>);
347
+ private injectMCPToolInstructions;
304
348
  processRuntimeRequest(request: CopilotRuntimeRequest): Promise<CopilotRuntimeResponse>;
305
349
  discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]>;
306
350
  loadAgentState(graphqlContext: GraphQLContext, threadId: string, agentName: string): Promise<LoadAgentStateResponse>;
@@ -313,4 +357,45 @@ declare function copilotKitEndpoint(config: Omit<CopilotKitEndpoint, "type">): C
313
357
  declare function langGraphPlatformEndpoint(config: Omit<LangGraphPlatformEndpoint, "type">): LangGraphPlatformEndpoint;
314
358
  declare function resolveEndpointType(endpoint: EndpointDefinition): EndpointType;
315
359
 
316
- export { CopilotRuntimeConstructorParams as C, GraphQLContext as G, LogLevel as L, CopilotRuntime as a, addCustomHeaderPlugin as b, copilotKitEndpoint as c, CopilotRequestContextProperties as d, CreateCopilotRuntimeServerOptions as e, flattenToolCallsNoDuplicates as f, createContext as g, buildSchema as h, CommonConfig as i, getCommonConfig as j, CopilotRuntimeLogger as k, langGraphPlatformEndpoint as l, createLogger as m, resolveEndpointType as r };
360
+ type LogLevel = "debug" | "info" | "warn" | "error";
361
+ type CopilotRuntimeLogger = ReturnType<typeof createLogger>;
362
+ declare function createLogger(options?: {
363
+ level?: LogLevel;
364
+ component?: string;
365
+ }): pino.Logger<never>;
366
+
367
+ declare const logger: pino.Logger<never>;
368
+ declare const addCustomHeaderPlugin: {
369
+ onResponse({ response }: {
370
+ response: any;
371
+ }): void;
372
+ };
373
+ type AnyPrimitive = string | boolean | number | null;
374
+ type CopilotRequestContextProperties = Record<string, AnyPrimitive | Record<string, AnyPrimitive>>;
375
+ type GraphQLContext = YogaInitialContext & {
376
+ _copilotkit: CreateCopilotRuntimeServerOptions;
377
+ properties: CopilotRequestContextProperties;
378
+ logger: typeof logger;
379
+ };
380
+ interface CreateCopilotRuntimeServerOptions {
381
+ runtime: CopilotRuntime<any>;
382
+ serviceAdapter: CopilotServiceAdapter;
383
+ endpoint: string;
384
+ baseUrl?: string;
385
+ cloud?: CopilotCloudOptions;
386
+ properties?: CopilotRequestContextProperties;
387
+ logLevel?: LogLevel;
388
+ }
389
+ declare function createContext(initialContext: YogaInitialContext, copilotKitContext: CreateCopilotRuntimeServerOptions, contextLogger: typeof logger, properties?: CopilotRequestContextProperties): Promise<Partial<GraphQLContext>>;
390
+ declare function buildSchema(options?: {
391
+ emitSchemaFile?: string;
392
+ }): graphql.GraphQLSchema;
393
+ type CommonConfig = {
394
+ logging: typeof logger;
395
+ schema: ReturnType<typeof buildSchema>;
396
+ plugins: Parameters<typeof createYoga>[0]["plugins"];
397
+ context: (ctx: YogaInitialContext) => Promise<Partial<GraphQLContext>>;
398
+ };
399
+ declare function getCommonConfig(options: CreateCopilotRuntimeServerOptions): CommonConfig;
400
+
401
+ export { CopilotRequestContextProperties as C, GraphQLContext as G, LogLevel as L, MCPTool as M, addCustomHeaderPlugin as a, CreateCopilotRuntimeServerOptions as b, createContext as c, buildSchema as d, CommonConfig as e, CopilotRuntimeLogger as f, getCommonConfig as g, createLogger as h, CopilotRuntimeRequest as i, CopilotRuntimeConstructorParams as j, CopilotRuntime as k, flattenToolCallsNoDuplicates as l, copilotKitEndpoint as m, langGraphPlatformEndpoint as n, MCPClient as o, MCPEndpointConfig as p, extractParametersFromSchema as q, resolveEndpointType as r, convertMCPToolsToActions as s };
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.8.5-next.2",
12
+ "version": "1.8.5-next.4",
13
13
  "sideEffects": false,
14
14
  "main": "./dist/index.js",
15
15
  "module": "./dist/index.mjs",
@@ -59,7 +59,7 @@
59
59
  "rxjs": "^7.8.1",
60
60
  "type-graphql": "2.0.0-rc.1",
61
61
  "zod": "^3.23.3",
62
- "@copilotkit/shared": "1.8.5-next.2"
62
+ "@copilotkit/shared": "1.8.5-next.4"
63
63
  },
64
64
  "keywords": [
65
65
  "copilotkit",
package/src/lib/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from "./runtime/copilot-runtime";
2
1
  export * from "../service-adapters/openai/openai-adapter";
3
2
  export * from "../service-adapters/langchain/langchain-adapter";
4
3
  export * from "../service-adapters/google/google-genai-adapter";
@@ -7,3 +6,5 @@ export * from "../service-adapters/unify/unify-adapter";
7
6
  export * from "../service-adapters/groq/groq-adapter";
8
7
  export * from "./integrations";
9
8
  export * from "./logger";
9
+ export * from "./runtime/copilot-runtime";
10
+ export * from "./runtime/mcp-tools-utils";
@@ -67,8 +67,15 @@ import {
67
67
  LLMResponseData,
68
68
  LLMErrorData,
69
69
  } from "../observability";
70
+ import { MessageRole } from "../../graphql/types/enums";
70
71
 
71
- interface CopilotRuntimeRequest {
72
+ // +++ MCP Imports +++
73
+ import { MCPClient, MCPEndpointConfig, convertMCPToolsToActions } from "./mcp-tools-utils";
74
+ // Define the function type alias here or import if defined elsewhere
75
+ type CreateMCPClientFunction = (config: MCPEndpointConfig) => Promise<MCPClient>;
76
+ // --- MCP Imports ---
77
+
78
+ export interface CopilotRuntimeRequest {
72
79
  serviceAdapter: CopilotServiceAdapter;
73
80
  messages: MessageInput[];
74
81
  actions: ActionInput[];
@@ -208,6 +215,41 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
208
215
  * ```
209
216
  */
210
217
  observability_c?: CopilotObservabilityConfig;
218
+
219
+ /**
220
+ * Configuration for connecting to Model Context Protocol (MCP) servers.
221
+ * Allows fetching and using tools defined on external MCP-compliant servers.
222
+ * Requires providing the `createMCPClient` function during instantiation.
223
+ * @experimental
224
+ */
225
+ mcpEndpoints?: MCPEndpointConfig[];
226
+
227
+ /**
228
+ * A function that creates an MCP client instance for a given endpoint configuration.
229
+ * This function is responsible for using the appropriate MCP client library
230
+ * (e.g., `@copilotkit/runtime`, `ai`) to establish a connection.
231
+ * Required if `mcpEndpoints` is provided.
232
+ *
233
+ * ```typescript
234
+ * import { experimental_createMCPClient } from "ai"; // Import from vercel ai library
235
+ * // ...
236
+ * const runtime = new CopilotRuntime({
237
+ * mcpEndpoints: [{ endpoint: "..." }],
238
+ * async createMCPClient(config) {
239
+ * return await experimental_createMCPClient({
240
+ * transport: {
241
+ * type: "sse",
242
+ * url: config.endpoint,
243
+ * headers: config.apiKey
244
+ * ? { Authorization: `Bearer ${config.apiKey}` }
245
+ * : undefined,
246
+ * },
247
+ * });
248
+ * }
249
+ * });
250
+ * ```
251
+ */
252
+ createMCPClient?: CreateMCPClientFunction;
211
253
  }
212
254
 
213
255
  export class CopilotRuntime<const T extends Parameter[] | [] = []> {
@@ -220,6 +262,15 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
220
262
  private observability?: CopilotObservabilityConfig;
221
263
  private availableAgents: Pick<AgentWithEndpoint, "name" | "id">[];
222
264
 
265
+ // +++ MCP Properties +++
266
+ private readonly mcpEndpointsConfig?: MCPEndpointConfig[];
267
+ private mcpActionCache = new Map<string, Action<any>[]>();
268
+ // --- MCP Properties ---
269
+
270
+ // +++ MCP Client Factory +++
271
+ private readonly createMCPClientImpl?: CreateMCPClientFunction;
272
+ // --- MCP Client Factory ---
273
+
223
274
  constructor(params?: CopilotRuntimeConstructorParams<T>) {
224
275
  if (
225
276
  params?.actions &&
@@ -243,7 +294,98 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
243
294
  this.delegateAgentProcessingToServiceAdapter =
244
295
  params?.delegateAgentProcessingToServiceAdapter || false;
245
296
  this.observability = params?.observability_c;
297
+
298
+ // +++ MCP Initialization +++
299
+ this.mcpEndpointsConfig = params?.mcpEndpoints;
300
+ this.createMCPClientImpl = params?.createMCPClient;
301
+
302
+ // Validate: If mcpEndpoints are provided, createMCPClient must also be provided
303
+ if (
304
+ this.mcpEndpointsConfig &&
305
+ this.mcpEndpointsConfig.length > 0 &&
306
+ !this.createMCPClientImpl
307
+ ) {
308
+ throw new CopilotKitMisuseError({
309
+ message:
310
+ "MCP Integration Error: `mcpEndpoints` were provided, but the `createMCPClient` function was not passed to the CopilotRuntime constructor. " +
311
+ "Please provide an implementation for `createMCPClient`.",
312
+ });
313
+ }
314
+
315
+ // Warning if actions are defined alongside LangGraph platform (potentially MCP too?)
316
+ if (
317
+ params?.actions &&
318
+ (params?.remoteEndpoints?.some((e) => e.type === EndpointType.LangGraphPlatform) ||
319
+ this.mcpEndpointsConfig?.length)
320
+ ) {
321
+ console.warn(
322
+ "Local 'actions' defined in CopilotRuntime might not be available to remote agents (LangGraph, MCP). Consider defining actions closer to the agent implementation if needed.",
323
+ );
324
+ }
325
+ }
326
+
327
+ // +++ MCP Instruction Injection Method +++
328
+ private injectMCPToolInstructions(
329
+ messages: MessageInput[],
330
+ currentActions: Action<any>[],
331
+ ): MessageInput[] {
332
+ // Filter the *passed-in* actions for MCP tools
333
+ const mcpActionsForRequest = currentActions.filter((action) => (action as any)._isMCPTool);
334
+
335
+ if (!mcpActionsForRequest || mcpActionsForRequest.length === 0) {
336
+ return messages; // No MCP tools for this specific request
337
+ }
338
+
339
+ // Filter only MCP actions and format instructions
340
+ const mcpToolInstructions = mcpActionsForRequest
341
+ .map((action) => {
342
+ const paramsString =
343
+ action.parameters && action.parameters.length > 0
344
+ ? ` Parameters: ${action.parameters
345
+ .map((p) => `${p.name}${p.required ? "*" : ""}(${p.type})`)
346
+ .join(", ")}`
347
+ : "";
348
+ return `- ${action.name}:${paramsString} ${action.description || ""}`;
349
+ })
350
+ .join("\n");
351
+
352
+ if (!mcpToolInstructions) {
353
+ return messages; // No MCP tools to describe
354
+ }
355
+
356
+ const instructions =
357
+ "You have access to the following tools provided by external Model Context Protocol (MCP) servers:\n" +
358
+ mcpToolInstructions +
359
+ "\nUse them when appropriate to fulfill the user's request.";
360
+
361
+ const systemMessageIndex = messages.findIndex((msg) => msg.textMessage?.role === "system");
362
+
363
+ const newMessages = [...messages]; // Create a mutable copy
364
+
365
+ if (systemMessageIndex !== -1) {
366
+ const existingMsg = newMessages[systemMessageIndex];
367
+ if (existingMsg.textMessage) {
368
+ existingMsg.textMessage.content =
369
+ (existingMsg.textMessage.content ? existingMsg.textMessage.content + "\n\n" : "") +
370
+ instructions;
371
+ }
372
+ } else {
373
+ newMessages.unshift({
374
+ id: randomId(),
375
+ createdAt: new Date(),
376
+ textMessage: {
377
+ role: MessageRole.system,
378
+ content: instructions,
379
+ },
380
+ actionExecutionMessage: undefined,
381
+ resultMessage: undefined,
382
+ agentStateMessage: undefined,
383
+ });
384
+ }
385
+
386
+ return newMessages;
246
387
  }
388
+ // --- MCP Instruction Injection Method ---
247
389
 
248
390
  async processRuntimeRequest(request: CopilotRuntimeRequest): Promise<CopilotRuntimeResponse> {
249
391
  const {
@@ -280,9 +422,20 @@ please use an LLM adapter instead.`,
280
422
  });
281
423
  }
282
424
 
283
- const messages = rawMessages.filter((message) => !message.agentStateMessage);
284
- const inputMessages = convertGqlInputToMessages(messages);
425
+ // +++ Get Server Side Actions (including dynamic MCP) EARLY +++
285
426
  const serverSideActions = await this.getServerSideActions(request);
427
+ // --- Get Server Side Actions (including dynamic MCP) EARLY ---
428
+
429
+ // Filter raw messages *before* injection
430
+ const filteredRawMessages = rawMessages.filter((message) => !message.agentStateMessage);
431
+
432
+ // +++ Inject MCP Instructions based on current actions +++
433
+ const messagesWithInjectedInstructions = this.injectMCPToolInstructions(
434
+ filteredRawMessages,
435
+ serverSideActions,
436
+ );
437
+ const inputMessages = convertGqlInputToMessages(messagesWithInjectedInstructions);
438
+ // --- Inject MCP Instructions based on current actions ---
286
439
 
287
440
  // Log LLM request if logging is enabled
288
441
  if (this.observability?.enabled && publicApiKey) {
@@ -913,10 +1066,11 @@ please use an LLM adapter instead.`,
913
1066
  }
914
1067
 
915
1068
  private async getServerSideActions(request: CopilotRuntimeRequest): Promise<Action<any>[]> {
916
- const { messages: rawMessages, graphqlContext, agentStates, url } = request;
1069
+ const { graphqlContext, messages: rawMessages, agentStates, url } = request;
1070
+
1071
+ // --- Standard Action Fetching (unchanged) ---
917
1072
  const inputMessages = convertGqlInputToMessages(rawMessages);
918
1073
  const langserveFunctions: Action<any>[] = [];
919
-
920
1074
  for (const chainPromise of this.langserve) {
921
1075
  try {
922
1076
  const chain = await chainPromise;
@@ -927,11 +1081,7 @@ please use an LLM adapter instead.`,
927
1081
  }
928
1082
 
929
1083
  const remoteEndpointDefinitions = this.remoteEndpointDefinitions.map(
930
- (endpoint) =>
931
- ({
932
- ...endpoint,
933
- type: resolveEndpointType(endpoint),
934
- }) as EndpointDefinition,
1084
+ (endpoint) => ({ ...endpoint, type: resolveEndpointType(endpoint) }) as EndpointDefinition,
935
1085
  );
936
1086
 
937
1087
  const remoteActions = await setupRemoteActions({
@@ -946,8 +1096,65 @@ please use an LLM adapter instead.`,
946
1096
  typeof this.actions === "function"
947
1097
  ? this.actions({ properties: graphqlContext.properties, url })
948
1098
  : this.actions;
1099
+ // --- Standard Action Fetching (unchanged) ---
1100
+
1101
+ // +++ Dynamic MCP Action Fetching +++
1102
+ const requestSpecificMCPActions: Action<any>[] = [];
1103
+ if (this.createMCPClientImpl) {
1104
+ // 1. Determine effective MCP endpoints for this request
1105
+ const baseEndpoints = this.mcpEndpointsConfig || [];
1106
+ // Assuming frontend passes config via properties.mcpEndpoints
1107
+ const requestEndpoints = (graphqlContext.properties?.mcpEndpoints ||
1108
+ []) as MCPEndpointConfig[];
1109
+
1110
+ // Merge and deduplicate endpoints based on URL
1111
+ const effectiveEndpointsMap = new Map<string, MCPEndpointConfig>();
1112
+ [...baseEndpoints, ...requestEndpoints].forEach((ep) => {
1113
+ if (ep && ep.endpoint) {
1114
+ // Basic validation
1115
+ effectiveEndpointsMap.set(ep.endpoint, ep);
1116
+ }
1117
+ });
1118
+ const effectiveEndpoints = Array.from(effectiveEndpointsMap.values());
949
1119
 
950
- return [...configuredActions, ...langserveFunctions, ...remoteActions];
1120
+ // 2. Fetch/Cache actions for effective endpoints
1121
+ for (const config of effectiveEndpoints) {
1122
+ const endpointUrl = config.endpoint;
1123
+ let actionsForEndpoint: Action<any>[] | undefined = this.mcpActionCache.get(endpointUrl);
1124
+
1125
+ if (!actionsForEndpoint) {
1126
+ // Not cached, fetch now
1127
+ let client: MCPClient | null = null;
1128
+ try {
1129
+ console.log(`MCP: Cache miss. Fetching tools for endpoint: ${endpointUrl}`);
1130
+ client = await this.createMCPClientImpl(config);
1131
+ const tools = await client.tools();
1132
+ actionsForEndpoint = convertMCPToolsToActions(tools, endpointUrl);
1133
+ this.mcpActionCache.set(endpointUrl, actionsForEndpoint); // Store in cache
1134
+ console.log(
1135
+ `MCP: Fetched and cached ${actionsForEndpoint.length} tools for ${endpointUrl}`,
1136
+ );
1137
+ } catch (error) {
1138
+ console.error(
1139
+ `MCP: Failed to fetch tools from endpoint ${endpointUrl}. Skipping. Error:`,
1140
+ error,
1141
+ );
1142
+ actionsForEndpoint = []; // Assign empty array on error to prevent re-fetching constantly
1143
+ this.mcpActionCache.set(endpointUrl, actionsForEndpoint); // Cache the failure (empty array)
1144
+ }
1145
+ }
1146
+ requestSpecificMCPActions.push(...(actionsForEndpoint || []));
1147
+ }
1148
+ }
1149
+ // --- Dynamic MCP Action Fetching ---
1150
+
1151
+ // Combine all action sources, including the dynamically fetched MCP actions
1152
+ return [
1153
+ ...configuredActions,
1154
+ ...langserveFunctions,
1155
+ ...remoteActions,
1156
+ ...requestSpecificMCPActions,
1157
+ ];
951
1158
  }
952
1159
 
953
1160
  // Add helper method to detect provider
@@ -0,0 +1,117 @@
1
+ import { Action, Parameter } from "@copilotkit/shared";
2
+
3
+ /**
4
+ * Represents a tool provided by an MCP server.
5
+ */
6
+ export interface MCPTool {
7
+ description?: string;
8
+ /** Schema defining parameters, mirroring the MCP structure. */
9
+ schema?: {
10
+ parameters?: {
11
+ properties?: Record<string, any>;
12
+ required?: string[];
13
+ };
14
+ };
15
+ /** The function to call to execute the tool on the MCP server. */
16
+ execute(options: { params: any }): Promise<any>;
17
+ }
18
+
19
+ /**
20
+ * Defines the contract for *any* MCP client implementation the user might provide.
21
+ */
22
+ export interface MCPClient {
23
+ /** A method that returns a map of tool names to MCPTool objects available from the connected MCP server. */
24
+ tools(): Promise<Record<string, MCPTool>>;
25
+ /** An optional method for cleanup if the underlying client requires explicit disconnection. */
26
+ close?(): Promise<void>;
27
+ }
28
+
29
+ /**
30
+ * Configuration for connecting to an MCP endpoint.
31
+ */
32
+ export interface MCPEndpointConfig {
33
+ endpoint: string;
34
+ apiKey?: string;
35
+ }
36
+
37
+ /**
38
+ * Extracts CopilotKit-compatible parameters from an MCP tool schema.
39
+ * @param toolSchema The schema object from an MCPTool.
40
+ * @returns An array of Parameter objects.
41
+ */
42
+ export function extractParametersFromSchema(toolSchema?: MCPTool["schema"]): Parameter[] {
43
+ const parameters: Parameter[] = [];
44
+ const properties = toolSchema?.parameters?.properties;
45
+ const requiredParams = new Set(toolSchema?.parameters?.required || []);
46
+
47
+ if (!properties) {
48
+ return parameters;
49
+ }
50
+
51
+ for (const paramName in properties) {
52
+ if (Object.prototype.hasOwnProperty.call(properties, paramName)) {
53
+ const paramDef = properties[paramName];
54
+ parameters.push({
55
+ name: paramName,
56
+ // Infer type, default to string. MCP schemas might have more complex types.
57
+ // This might need refinement based on common MCP schema practices.
58
+ type: paramDef.type || "string",
59
+ description: paramDef.description,
60
+ required: requiredParams.has(paramName),
61
+ // Attributes might not directly map, handle if necessary
62
+ // attributes: paramDef.attributes || undefined,
63
+ });
64
+ }
65
+ }
66
+
67
+ return parameters;
68
+ }
69
+
70
+ /**
71
+ * Converts a map of MCPTools into an array of CopilotKit Actions.
72
+ * @param mcpTools A record mapping tool names to MCPTool objects.
73
+ * @param mcpEndpoint The endpoint URL from which these tools were fetched.
74
+ * @returns An array of Action<any> objects.
75
+ */
76
+ export function convertMCPToolsToActions(
77
+ mcpTools: Record<string, MCPTool>,
78
+ mcpEndpoint: string,
79
+ ): Action<any>[] {
80
+ const actions: Action<any>[] = [];
81
+
82
+ for (const [toolName, tool] of Object.entries(mcpTools)) {
83
+ const parameters = extractParametersFromSchema(tool.schema);
84
+
85
+ const handler = async (params: any): Promise<any> => {
86
+ try {
87
+ const result = await tool.execute({ params });
88
+ // Ensure the result is a string or stringify it, as required by many LLMs.
89
+ // This might need adjustment depending on how different LLMs handle tool results.
90
+ return typeof result === "string" ? result : JSON.stringify(result);
91
+ } catch (error) {
92
+ console.error(
93
+ `Error executing MCP tool '${toolName}' from endpoint ${mcpEndpoint}:`,
94
+ error,
95
+ );
96
+ // Re-throw or format the error for the LLM
97
+ throw new Error(
98
+ `Execution failed for MCP tool '${toolName}': ${
99
+ error instanceof Error ? error.message : String(error)
100
+ }`,
101
+ );
102
+ }
103
+ };
104
+
105
+ actions.push({
106
+ name: toolName,
107
+ description: tool.description || `MCP tool: ${toolName} (from ${mcpEndpoint})`,
108
+ parameters: parameters,
109
+ handler: handler,
110
+ // Add metadata for easier identification/debugging
111
+ _isMCPTool: true,
112
+ _mcpEndpoint: mcpEndpoint,
113
+ } as Action<any> & { _isMCPTool: boolean; _mcpEndpoint: string }); // Type assertion for metadata
114
+ }
115
+
116
+ return actions;
117
+ }