@contractspec/lib.ai-agent 2.6.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.
- package/README.md +33 -2
- package/dist/agent/agent-factory.d.ts +5 -0
- package/dist/agent/agent-factory.js +221 -11
- package/dist/agent/contract-spec-agent.d.ts +8 -0
- package/dist/agent/contract-spec-agent.js +210 -10
- package/dist/agent/index.js +334 -39
- package/dist/agent/json-runner.js +210 -10
- package/dist/agent/unified-agent.d.ts +4 -0
- package/dist/agent/unified-agent.js +334 -39
- package/dist/exporters/claude-agent-exporter.d.ts +1 -0
- package/dist/exporters/claude-agent-exporter.js +11 -1
- package/dist/exporters/index.js +11 -1
- package/dist/exporters/types.d.ts +3 -10
- package/dist/node/agent/agent-factory.js +221 -11
- package/dist/node/agent/contract-spec-agent.js +210 -10
- package/dist/node/agent/index.js +334 -39
- package/dist/node/agent/json-runner.js +210 -10
- package/dist/node/agent/unified-agent.js +334 -39
- package/dist/node/exporters/claude-agent-exporter.js +11 -1
- package/dist/node/exporters/index.js +11 -1
- package/dist/node/providers/claude-agent-sdk/adapter.js +260 -23
- package/dist/node/providers/claude-agent-sdk/index.js +260 -23
- package/dist/node/providers/index.js +260 -23
- package/dist/node/tools/index.js +154 -18
- package/dist/node/tools/mcp-client-helpers.js +106 -0
- package/dist/node/tools/mcp-client.js +155 -18
- package/dist/providers/claude-agent-sdk/adapter.d.ts +4 -0
- package/dist/providers/claude-agent-sdk/adapter.js +260 -23
- package/dist/providers/claude-agent-sdk/index.d.ts +8 -0
- package/dist/providers/claude-agent-sdk/index.js +260 -23
- package/dist/providers/index.js +260 -23
- package/dist/providers/types.d.ts +1 -1
- package/dist/tools/index.js +154 -18
- package/dist/tools/mcp-client-helpers.d.ts +12 -0
- package/dist/tools/mcp-client-helpers.js +106 -0
- package/dist/tools/mcp-client.d.ts +55 -3
- package/dist/tools/mcp-client.js +155 -18
- package/dist/tools/mcp-client.test.d.ts +1 -0
- 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
|
-
*
|
|
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
|
-
|
|
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 {};
|
package/dist/tools/mcp-client.js
CHANGED
|
@@ -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 {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
32
|
-
const
|
|
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
|
-
|
|
35
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
36
|
+
"ai": "6.0.97",
|
|
37
37
|
"@ai-sdk/mcp": "1.0.21",
|
|
38
|
-
"@ai-sdk/anthropic": "3.0.
|
|
39
|
-
"@ai-sdk/google": "3.0.
|
|
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.
|
|
42
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
43
|
-
"@posthog/react": "^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.
|
|
46
|
-
"@contractspec/lib.ai-providers": "2.
|
|
47
|
-
"@contractspec/lib.knowledge": "2.
|
|
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.
|
|
71
|
+
"@contractspec/tool.typescript": "2.7.0",
|
|
72
72
|
"typescript": "^5.9.3",
|
|
73
|
-
"@contractspec/tool.bun": "2.
|
|
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",
|