@contractspec/lib.ai-agent 2.5.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +33 -2
  2. package/dist/agent/agent-factory.d.ts +5 -0
  3. package/dist/agent/agent-factory.js +221 -11
  4. package/dist/agent/contract-spec-agent.d.ts +8 -0
  5. package/dist/agent/contract-spec-agent.js +210 -10
  6. package/dist/agent/index.js +334 -39
  7. package/dist/agent/json-runner.js +210 -10
  8. package/dist/agent/unified-agent.d.ts +4 -0
  9. package/dist/agent/unified-agent.js +334 -39
  10. package/dist/exporters/claude-agent-exporter.d.ts +1 -0
  11. package/dist/exporters/claude-agent-exporter.js +11 -1
  12. package/dist/exporters/index.js +11 -1
  13. package/dist/exporters/types.d.ts +3 -10
  14. package/dist/node/agent/agent-factory.js +221 -11
  15. package/dist/node/agent/contract-spec-agent.js +210 -10
  16. package/dist/node/agent/index.js +334 -39
  17. package/dist/node/agent/json-runner.js +210 -10
  18. package/dist/node/agent/unified-agent.js +334 -39
  19. package/dist/node/exporters/claude-agent-exporter.js +11 -1
  20. package/dist/node/exporters/index.js +11 -1
  21. package/dist/node/providers/claude-agent-sdk/adapter.js +260 -23
  22. package/dist/node/providers/claude-agent-sdk/index.js +260 -23
  23. package/dist/node/providers/index.js +260 -23
  24. package/dist/node/tools/index.js +154 -18
  25. package/dist/node/tools/mcp-client-helpers.js +106 -0
  26. package/dist/node/tools/mcp-client.js +155 -18
  27. package/dist/providers/claude-agent-sdk/adapter.d.ts +4 -0
  28. package/dist/providers/claude-agent-sdk/adapter.js +260 -23
  29. package/dist/providers/claude-agent-sdk/index.d.ts +8 -0
  30. package/dist/providers/claude-agent-sdk/index.js +260 -23
  31. package/dist/providers/index.js +260 -23
  32. package/dist/providers/types.d.ts +1 -1
  33. package/dist/tools/index.js +154 -18
  34. package/dist/tools/mcp-client-helpers.d.ts +12 -0
  35. package/dist/tools/mcp-client-helpers.js +106 -0
  36. package/dist/tools/mcp-client.d.ts +55 -3
  37. package/dist/tools/mcp-client.js +155 -18
  38. package/dist/tools/mcp-client.test.d.ts +1 -0
  39. package/package.json +24 -12
@@ -1,17 +1,58 @@
1
+ import { type OAuthClientProvider } from '@ai-sdk/mcp';
1
2
  import type { Tool } from 'ai';
2
3
  /**
3
- * Configuration for connecting to an MCP server.
4
+ * Supported transport types for MCP clients.
5
+ */
6
+ export type McpTransportType = 'stdio' | 'sse' | 'http';
7
+ /**
8
+ * Shared configuration for all MCP server transports.
4
9
  */
5
- export interface McpClientConfig {
10
+ interface McpClientBaseConfig {
6
11
  /** Display name for the MCP server */
7
12
  name: string;
13
+ /** Optional prefix applied to every imported tool name */
14
+ toolPrefix?: string;
15
+ /** Optional MCP client name override */
16
+ clientName?: string;
17
+ /** Optional MCP client version override */
18
+ clientVersion?: string;
19
+ }
20
+ /**
21
+ * Configuration for stdio MCP servers.
22
+ */
23
+ export interface McpStdioClientConfig extends McpClientBaseConfig {
24
+ /** Transport type (defaults to "stdio" when omitted) */
25
+ transport?: 'stdio';
8
26
  /** Command to spawn the MCP server process */
9
27
  command: string;
10
28
  /** Arguments to pass to the command */
11
29
  args?: string[];
12
30
  /** Environment variables for the process */
13
31
  env?: Record<string, string>;
32
+ /** Working directory for spawned process */
33
+ cwd?: string;
14
34
  }
35
+ /**
36
+ * Configuration for remote MCP servers (SSE / Streamable HTTP).
37
+ */
38
+ export interface McpRemoteClientConfig extends McpClientBaseConfig {
39
+ /** Transport type */
40
+ transport: 'sse' | 'http';
41
+ /** MCP endpoint URL */
42
+ url: string;
43
+ /** Optional static headers */
44
+ headers?: Record<string, string>;
45
+ /** Optional OAuth provider for MCP auth flow */
46
+ authProvider?: OAuthClientProvider;
47
+ /** Optional bearer token injected into Authorization header */
48
+ accessToken?: string;
49
+ /** Optional env var name containing bearer token */
50
+ accessTokenEnvVar?: string;
51
+ }
52
+ /**
53
+ * Configuration for connecting to an MCP server.
54
+ */
55
+ export type McpClientConfig = McpStdioClientConfig | McpRemoteClientConfig;
15
56
  /**
16
57
  * Result of creating an MCP client with tools.
17
58
  */
@@ -20,6 +61,15 @@ export interface McpClientResult {
20
61
  tools: Record<string, Tool<unknown, unknown>>;
21
62
  /** Cleanup function to close the connection */
22
63
  cleanup: () => Promise<void>;
64
+ /** Tool names grouped by source server name */
65
+ serverToolNames: Record<string, string[]>;
66
+ }
67
+ /**
68
+ * Options for combining multiple MCP toolsets.
69
+ */
70
+ export interface CreateMcpToolsetsOptions {
71
+ /** Strategy used when two MCP servers expose the same tool name */
72
+ onNameCollision?: 'overwrite' | 'error';
23
73
  }
24
74
  /**
25
75
  * Create AI SDK tools from an MCP server.
@@ -48,6 +98,8 @@ export declare function mcpServerToTools(config: McpClientConfig): Promise<McpCl
48
98
  * Create multiple MCP tool sets from configurations.
49
99
  *
50
100
  * @param configs - Array of MCP server configurations
101
+ * @param options - Merge options for conflicts
51
102
  * @returns Combined tools and cleanup function
52
103
  */
53
- export declare function createMcpToolsets(configs: McpClientConfig[]): Promise<McpClientResult>;
104
+ export declare function createMcpToolsets(configs: McpClientConfig[], options?: CreateMcpToolsetsOptions): Promise<McpClientResult>;
105
+ export {};
@@ -12,35 +12,172 @@ var __export = (target, all) => {
12
12
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
13
  var __require = import.meta.require;
14
14
 
15
- // src/tools/mcp-client.ts
16
- import { experimental_createMCPClient } from "@ai-sdk/mcp";
17
- import { Experimental_StdioMCPTransport as StdioClientTransport } from "@ai-sdk/mcp/mcp-stdio";
18
- async function mcpServerToTools(config) {
19
- const transport = new StdioClientTransport({
20
- command: config.command,
21
- args: config.args,
22
- env: config.env
23
- });
24
- const client = await experimental_createMCPClient({ transport });
25
- const tools = await client.tools();
15
+ // src/tools/mcp-client-helpers.ts
16
+ import {
17
+ Experimental_StdioMCPTransport as StdioClientTransport
18
+ } from "@ai-sdk/mcp/mcp-stdio";
19
+ function buildMcpTransport(config) {
20
+ const transport = resolveTransportType(config);
21
+ if (transport === "stdio") {
22
+ const stdioConfig = resolveStdioConfig(config);
23
+ return new StdioClientTransport(stdioConfig);
24
+ }
25
+ const remoteConfig = config;
26
+ const headers = resolveRemoteHeaders(remoteConfig);
27
+ const remoteTransport = {
28
+ type: transport,
29
+ url: requireNonEmptyString(remoteConfig.url, "url", config.name)
30
+ };
31
+ if (headers) {
32
+ remoteTransport.headers = headers;
33
+ }
34
+ if (remoteConfig.authProvider) {
35
+ remoteTransport.authProvider = remoteConfig.authProvider;
36
+ }
37
+ return remoteTransport;
38
+ }
39
+ function prefixToolNames(config, tools) {
40
+ const prefix = config.toolPrefix?.trim();
41
+ if (!prefix) {
42
+ return tools;
43
+ }
44
+ const prefixedTools = {};
45
+ for (const [toolName, tool] of Object.entries(tools)) {
46
+ prefixedTools[`${prefix}_${toolName}`] = tool;
47
+ }
48
+ return prefixedTools;
49
+ }
50
+ function getErrorMessage(error) {
51
+ if (error instanceof Error) {
52
+ return error.message;
53
+ }
54
+ return String(error);
55
+ }
56
+ function resolveTransportType(config) {
57
+ return config.transport ?? "stdio";
58
+ }
59
+ function resolveStdioConfig(config) {
60
+ const stdioConfig = config;
26
61
  return {
27
- tools,
28
- cleanup: () => client.close()
62
+ command: requireNonEmptyString(stdioConfig.command, "command", config.name),
63
+ args: stdioConfig.args,
64
+ env: stdioConfig.env,
65
+ cwd: stdioConfig.cwd
29
66
  };
30
67
  }
31
- async function createMcpToolsets(configs) {
32
- const results = await Promise.all(configs.map(mcpServerToTools));
68
+ function resolveRemoteHeaders(config) {
69
+ const headers = {
70
+ ...config.headers ?? {}
71
+ };
72
+ const accessToken = config.accessToken ?? resolveEnvToken(config.accessTokenEnvVar);
73
+ if (accessToken && headers.Authorization === undefined) {
74
+ headers.Authorization = `Bearer ${accessToken}`;
75
+ }
76
+ return Object.keys(headers).length > 0 ? headers : undefined;
77
+ }
78
+ function resolveEnvToken(envVarName) {
79
+ if (!envVarName) {
80
+ return;
81
+ }
82
+ const value = process.env[envVarName];
83
+ if (!value) {
84
+ return;
85
+ }
86
+ const trimmed = value.trim();
87
+ return trimmed.length > 0 ? trimmed : undefined;
88
+ }
89
+ function requireNonEmptyString(value, field, serverName) {
90
+ if (!value) {
91
+ throw new Error(`MCP server "${serverName}" is missing required "${field}".`);
92
+ }
93
+ const trimmed = value.trim();
94
+ if (trimmed.length === 0) {
95
+ throw new Error(`MCP server "${serverName}" has an empty "${field}".`);
96
+ }
97
+ return trimmed;
98
+ }
99
+ var init_mcp_client_helpers = () => {};
100
+
101
+ // src/tools/mcp-client.ts
102
+ import {
103
+ experimental_createMCPClient
104
+ } from "@ai-sdk/mcp";
105
+ async function mcpServerToTools(config) {
106
+ let client = null;
107
+ try {
108
+ const transport = buildMcpTransport(config);
109
+ client = await experimental_createMCPClient({
110
+ transport,
111
+ name: config.clientName,
112
+ version: config.clientVersion
113
+ });
114
+ const tools = await client.tools();
115
+ const prefixedTools = prefixToolNames(config, tools);
116
+ const connectedClient = client;
117
+ return {
118
+ tools: prefixedTools,
119
+ cleanup: () => connectedClient.close(),
120
+ serverToolNames: {
121
+ [config.name]: Object.keys(prefixedTools)
122
+ }
123
+ };
124
+ } catch (error) {
125
+ if (client) {
126
+ await client.close().catch(() => {
127
+ return;
128
+ });
129
+ }
130
+ throw new Error(`[MCP:${config.name}] Failed to connect tools: ${getErrorMessage(error)}`);
131
+ }
132
+ }
133
+ async function createMcpToolsets(configs, options = {}) {
134
+ const connected = [];
135
+ try {
136
+ for (const config of configs) {
137
+ const result = await mcpServerToTools(config);
138
+ connected.push(result);
139
+ }
140
+ } catch (error) {
141
+ await Promise.allSettled(connected.map((result) => result.cleanup()));
142
+ throw error;
143
+ }
33
144
  const combinedTools = {};
34
- for (const result of results) {
35
- Object.assign(combinedTools, result.tools);
145
+ const serverToolNames = {};
146
+ const collisionStrategy = options.onNameCollision ?? "overwrite";
147
+ try {
148
+ for (const result of connected) {
149
+ for (const [serverName, toolNames] of Object.entries(result.serverToolNames)) {
150
+ serverToolNames[serverName] = toolNames;
151
+ }
152
+ for (const [toolName, tool] of Object.entries(result.tools)) {
153
+ const hasCollision = combinedTools[toolName] !== undefined;
154
+ if (hasCollision && collisionStrategy === "error") {
155
+ throw new Error(`Duplicate MCP tool name "${toolName}" detected. Use "toolPrefix" or set onNameCollision to "overwrite".`);
156
+ }
157
+ combinedTools[toolName] = tool;
158
+ }
159
+ }
160
+ } catch (error) {
161
+ await Promise.allSettled(connected.map((result) => result.cleanup()));
162
+ throw error;
36
163
  }
37
164
  return {
38
165
  tools: combinedTools,
166
+ serverToolNames,
39
167
  cleanup: async () => {
40
- await Promise.all(results.map((r) => r.cleanup()));
168
+ const cleanupResults = await Promise.allSettled(connected.map((result) => result.cleanup()));
169
+ const failures = cleanupResults.filter((result) => result.status === "rejected");
170
+ if (failures.length > 0) {
171
+ throw new Error(`Failed to cleanup ${failures.length} MCP client connection(s).`);
172
+ }
41
173
  }
42
174
  };
43
175
  }
176
+ var init_mcp_client = __esm(() => {
177
+ init_mcp_client_helpers();
178
+ });
179
+ init_mcp_client();
180
+
44
181
  export {
45
182
  mcpServerToTools,
46
183
  createMcpToolsets
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.ai-agent",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "description": "AI agent orchestration with MCP and tool support",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -33,18 +33,18 @@
33
33
  "typecheck": "tsc --noEmit"
34
34
  },
35
35
  "dependencies": {
36
- "ai": "6.0.86",
36
+ "ai": "6.0.97",
37
37
  "@ai-sdk/mcp": "1.0.21",
38
- "@ai-sdk/anthropic": "3.0.44",
39
- "@ai-sdk/google": "3.0.29",
38
+ "@ai-sdk/anthropic": "3.0.46",
39
+ "@ai-sdk/google": "3.0.30",
40
40
  "@ai-sdk/mistral": "3.0.20",
41
- "@ai-sdk/openai": "3.0.29",
42
- "@modelcontextprotocol/sdk": "^1.26.0",
43
- "@posthog/react": "^1.7.1",
41
+ "@ai-sdk/openai": "3.0.31",
42
+ "@modelcontextprotocol/sdk": "^1.27.0",
43
+ "@posthog/react": "^1.8.0",
44
44
  "@posthog/ai": "latest",
45
- "@contractspec/lib.contracts-spec": "2.5.0",
46
- "@contractspec/lib.ai-providers": "2.5.0",
47
- "@contractspec/lib.knowledge": "2.5.0",
45
+ "@contractspec/lib.contracts-spec": "2.7.0",
46
+ "@contractspec/lib.ai-providers": "2.7.0",
47
+ "@contractspec/lib.knowledge": "2.7.0",
48
48
  "compare-versions": "^6.1.1",
49
49
  "zod": "^4.3.5"
50
50
  },
@@ -68,9 +68,9 @@
68
68
  }
69
69
  },
70
70
  "devDependencies": {
71
- "@contractspec/tool.typescript": "2.5.0",
71
+ "@contractspec/tool.typescript": "2.7.0",
72
72
  "typescript": "^5.9.3",
73
- "@contractspec/tool.bun": "2.5.0"
73
+ "@contractspec/tool.bun": "2.7.0"
74
74
  },
75
75
  "exports": {
76
76
  ".": {
@@ -499,6 +499,12 @@
499
499
  "node": "./dist/node/tools/mcp-client.js",
500
500
  "default": "./dist/tools/mcp-client.js"
501
501
  },
502
+ "./tools/mcp-client-helpers": {
503
+ "types": "./dist/tools/mcp-client-helpers.d.ts",
504
+ "bun": "./dist/tools/mcp-client-helpers.js",
505
+ "node": "./dist/node/tools/mcp-client-helpers.js",
506
+ "default": "./dist/tools/mcp-client-helpers.js"
507
+ },
502
508
  "./tools/mcp-server": {
503
509
  "types": "./dist/tools/mcp-server.d.ts",
504
510
  "bun": "./dist/tools/mcp-server.js",
@@ -947,6 +953,12 @@
947
953
  "node": "./dist/node/tools/mcp-client.js",
948
954
  "default": "./dist/tools/mcp-client.js"
949
955
  },
956
+ "./tools/mcp-client-helpers": {
957
+ "types": "./dist/tools/mcp-client-helpers.d.ts",
958
+ "bun": "./dist/tools/mcp-client-helpers.js",
959
+ "node": "./dist/node/tools/mcp-client-helpers.js",
960
+ "default": "./dist/tools/mcp-client-helpers.js"
961
+ },
950
962
  "./tools/mcp-server": {
951
963
  "types": "./dist/tools/mcp-server.d.ts",
952
964
  "bun": "./dist/tools/mcp-server.js",