@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
@@ -2400,6 +2400,171 @@ var init_knowledge_tool = __esm(() => {
2400
2400
  init_i18n();
2401
2401
  });
2402
2402
 
2403
+ // src/tools/mcp-client-helpers.ts
2404
+ import {
2405
+ Experimental_StdioMCPTransport as StdioClientTransport
2406
+ } from "@ai-sdk/mcp/mcp-stdio";
2407
+ function buildMcpTransport(config) {
2408
+ const transport = resolveTransportType(config);
2409
+ if (transport === "stdio") {
2410
+ const stdioConfig = resolveStdioConfig(config);
2411
+ return new StdioClientTransport(stdioConfig);
2412
+ }
2413
+ const remoteConfig = config;
2414
+ const headers = resolveRemoteHeaders(remoteConfig);
2415
+ const remoteTransport = {
2416
+ type: transport,
2417
+ url: requireNonEmptyString(remoteConfig.url, "url", config.name)
2418
+ };
2419
+ if (headers) {
2420
+ remoteTransport.headers = headers;
2421
+ }
2422
+ if (remoteConfig.authProvider) {
2423
+ remoteTransport.authProvider = remoteConfig.authProvider;
2424
+ }
2425
+ return remoteTransport;
2426
+ }
2427
+ function prefixToolNames(config, tools) {
2428
+ const prefix = config.toolPrefix?.trim();
2429
+ if (!prefix) {
2430
+ return tools;
2431
+ }
2432
+ const prefixedTools = {};
2433
+ for (const [toolName, tool3] of Object.entries(tools)) {
2434
+ prefixedTools[`${prefix}_${toolName}`] = tool3;
2435
+ }
2436
+ return prefixedTools;
2437
+ }
2438
+ function getErrorMessage(error) {
2439
+ if (error instanceof Error) {
2440
+ return error.message;
2441
+ }
2442
+ return String(error);
2443
+ }
2444
+ function resolveTransportType(config) {
2445
+ return config.transport ?? "stdio";
2446
+ }
2447
+ function resolveStdioConfig(config) {
2448
+ const stdioConfig = config;
2449
+ return {
2450
+ command: requireNonEmptyString(stdioConfig.command, "command", config.name),
2451
+ args: stdioConfig.args,
2452
+ env: stdioConfig.env,
2453
+ cwd: stdioConfig.cwd
2454
+ };
2455
+ }
2456
+ function resolveRemoteHeaders(config) {
2457
+ const headers = {
2458
+ ...config.headers ?? {}
2459
+ };
2460
+ const accessToken = config.accessToken ?? resolveEnvToken(config.accessTokenEnvVar);
2461
+ if (accessToken && headers.Authorization === undefined) {
2462
+ headers.Authorization = `Bearer ${accessToken}`;
2463
+ }
2464
+ return Object.keys(headers).length > 0 ? headers : undefined;
2465
+ }
2466
+ function resolveEnvToken(envVarName) {
2467
+ if (!envVarName) {
2468
+ return;
2469
+ }
2470
+ const value = process.env[envVarName];
2471
+ if (!value) {
2472
+ return;
2473
+ }
2474
+ const trimmed = value.trim();
2475
+ return trimmed.length > 0 ? trimmed : undefined;
2476
+ }
2477
+ function requireNonEmptyString(value, field, serverName) {
2478
+ if (!value) {
2479
+ throw new Error(`MCP server "${serverName}" is missing required "${field}".`);
2480
+ }
2481
+ const trimmed = value.trim();
2482
+ if (trimmed.length === 0) {
2483
+ throw new Error(`MCP server "${serverName}" has an empty "${field}".`);
2484
+ }
2485
+ return trimmed;
2486
+ }
2487
+ var init_mcp_client_helpers = () => {};
2488
+
2489
+ // src/tools/mcp-client.ts
2490
+ import {
2491
+ experimental_createMCPClient
2492
+ } from "@ai-sdk/mcp";
2493
+ async function mcpServerToTools(config) {
2494
+ let client = null;
2495
+ try {
2496
+ const transport = buildMcpTransport(config);
2497
+ client = await experimental_createMCPClient({
2498
+ transport,
2499
+ name: config.clientName,
2500
+ version: config.clientVersion
2501
+ });
2502
+ const tools = await client.tools();
2503
+ const prefixedTools = prefixToolNames(config, tools);
2504
+ const connectedClient = client;
2505
+ return {
2506
+ tools: prefixedTools,
2507
+ cleanup: () => connectedClient.close(),
2508
+ serverToolNames: {
2509
+ [config.name]: Object.keys(prefixedTools)
2510
+ }
2511
+ };
2512
+ } catch (error) {
2513
+ if (client) {
2514
+ await client.close().catch(() => {
2515
+ return;
2516
+ });
2517
+ }
2518
+ throw new Error(`[MCP:${config.name}] Failed to connect tools: ${getErrorMessage(error)}`);
2519
+ }
2520
+ }
2521
+ async function createMcpToolsets(configs, options = {}) {
2522
+ const connected = [];
2523
+ try {
2524
+ for (const config of configs) {
2525
+ const result = await mcpServerToTools(config);
2526
+ connected.push(result);
2527
+ }
2528
+ } catch (error) {
2529
+ await Promise.allSettled(connected.map((result) => result.cleanup()));
2530
+ throw error;
2531
+ }
2532
+ const combinedTools = {};
2533
+ const serverToolNames = {};
2534
+ const collisionStrategy = options.onNameCollision ?? "overwrite";
2535
+ try {
2536
+ for (const result of connected) {
2537
+ for (const [serverName, toolNames] of Object.entries(result.serverToolNames)) {
2538
+ serverToolNames[serverName] = toolNames;
2539
+ }
2540
+ for (const [toolName, tool3] of Object.entries(result.tools)) {
2541
+ const hasCollision = combinedTools[toolName] !== undefined;
2542
+ if (hasCollision && collisionStrategy === "error") {
2543
+ throw new Error(`Duplicate MCP tool name "${toolName}" detected. Use "toolPrefix" or set onNameCollision to "overwrite".`);
2544
+ }
2545
+ combinedTools[toolName] = tool3;
2546
+ }
2547
+ }
2548
+ } catch (error) {
2549
+ await Promise.allSettled(connected.map((result) => result.cleanup()));
2550
+ throw error;
2551
+ }
2552
+ return {
2553
+ tools: combinedTools,
2554
+ serverToolNames,
2555
+ cleanup: async () => {
2556
+ const cleanupResults = await Promise.allSettled(connected.map((result) => result.cleanup()));
2557
+ const failures = cleanupResults.filter((result) => result.status === "rejected");
2558
+ if (failures.length > 0) {
2559
+ throw new Error(`Failed to cleanup ${failures.length} MCP client connection(s).`);
2560
+ }
2561
+ }
2562
+ };
2563
+ }
2564
+ var init_mcp_client = __esm(() => {
2565
+ init_mcp_client_helpers();
2566
+ });
2567
+
2403
2568
  // src/knowledge/injector.ts
2404
2569
  async function injectStaticKnowledge(instructions, knowledgeRefs, retriever, locale) {
2405
2570
  if (!retriever)
@@ -2909,25 +3074,59 @@ class ContractSpecAgent {
2909
3074
  tools;
2910
3075
  config;
2911
3076
  instructions;
3077
+ mcpCleanup;
2912
3078
  activeStepContexts = new Map;
2913
- constructor(config, instructions, tools) {
3079
+ constructor(config, instructions, tools, mcpCleanup) {
2914
3080
  this.config = config;
2915
3081
  this.spec = config.spec;
2916
3082
  this.id = agentKey(config.spec.meta);
2917
3083
  this.tools = tools;
2918
3084
  this.instructions = instructions;
3085
+ this.mcpCleanup = mcpCleanup;
2919
3086
  }
2920
3087
  static async create(config) {
2921
3088
  const effectiveConfig = config;
2922
- const instructions = await injectStaticKnowledge(effectiveConfig.spec.instructions, effectiveConfig.spec.knowledge ?? [], effectiveConfig.knowledgeRetriever);
2923
- const specTools = specToolsToAISDKTools(effectiveConfig.spec.tools, effectiveConfig.toolHandlers, { agentId: agentKey(effectiveConfig.spec.meta) });
2924
- const knowledgeTool = effectiveConfig.knowledgeRetriever ? createKnowledgeQueryTool(effectiveConfig.knowledgeRetriever, effectiveConfig.spec.knowledge ?? []) : null;
2925
- const tools = {
2926
- ...specTools,
2927
- ...knowledgeTool ? { query_knowledge: knowledgeTool } : {},
2928
- ...effectiveConfig.additionalTools ?? {}
2929
- };
2930
- return new ContractSpecAgent(effectiveConfig, instructions, tools);
3089
+ let mcpToolset = null;
3090
+ if ((effectiveConfig.mcpServers?.length ?? 0) > 0) {
3091
+ mcpToolset = await createMcpToolsets(effectiveConfig.mcpServers ?? [], {
3092
+ onNameCollision: "error"
3093
+ });
3094
+ }
3095
+ try {
3096
+ const instructions = await injectStaticKnowledge(effectiveConfig.spec.instructions, effectiveConfig.spec.knowledge ?? [], effectiveConfig.knowledgeRetriever);
3097
+ const specTools = specToolsToAISDKTools(effectiveConfig.spec.tools, effectiveConfig.toolHandlers, { agentId: agentKey(effectiveConfig.spec.meta) });
3098
+ const knowledgeTool = effectiveConfig.knowledgeRetriever ? createKnowledgeQueryTool(effectiveConfig.knowledgeRetriever, effectiveConfig.spec.knowledge ?? []) : null;
3099
+ const reservedToolNames = new Set(Object.keys(specTools));
3100
+ if (knowledgeTool) {
3101
+ reservedToolNames.add("query_knowledge");
3102
+ }
3103
+ const conflictingMcpTools = Object.keys(mcpToolset?.tools ?? {}).filter((toolName) => reservedToolNames.has(toolName));
3104
+ if (conflictingMcpTools.length > 0) {
3105
+ throw new Error(`MCP tools conflict with agent tools: ${conflictingMcpTools.join(", ")}. Configure MCP toolPrefix values to avoid collisions.`);
3106
+ }
3107
+ const tools = {
3108
+ ...specTools,
3109
+ ...knowledgeTool ? { query_knowledge: knowledgeTool } : {},
3110
+ ...mcpToolset?.tools ?? {},
3111
+ ...effectiveConfig.additionalTools ?? {}
3112
+ };
3113
+ return new ContractSpecAgent(effectiveConfig, instructions, tools, mcpToolset?.cleanup);
3114
+ } catch (error) {
3115
+ if (mcpToolset) {
3116
+ await mcpToolset.cleanup().catch(() => {
3117
+ return;
3118
+ });
3119
+ }
3120
+ throw error;
3121
+ }
3122
+ }
3123
+ async cleanup() {
3124
+ if (!this.mcpCleanup) {
3125
+ return;
3126
+ }
3127
+ const cleanup = this.mcpCleanup;
3128
+ this.mcpCleanup = undefined;
3129
+ await cleanup();
2931
3130
  }
2932
3131
  async generate(params) {
2933
3132
  const sessionId = params.options?.sessionId ?? generateSessionId();
@@ -3102,6 +3301,7 @@ var init_contract_spec_agent = __esm(() => {
3102
3301
  init_spec();
3103
3302
  init_tool_adapter();
3104
3303
  init_knowledge_tool();
3304
+ init_mcp_client();
3105
3305
  init_injector();
3106
3306
  init_adapter();
3107
3307
  ContractSpecCallOptionsSchema = z3.object({
@@ -3375,6 +3575,8 @@ function summarizeSession(session) {
3375
3575
  }
3376
3576
 
3377
3577
  // src/providers/claude-agent-sdk/adapter.ts
3578
+ import { randomUUID as randomUUID2 } from "node:crypto";
3579
+
3378
3580
  class ClaudeAgentSDKProvider {
3379
3581
  name = "claude-agent-sdk";
3380
3582
  version = "1.0.0";
@@ -3407,11 +3609,23 @@ class ClaudeAgentSDKProvider {
3407
3609
  if (!this.isAvailable()) {
3408
3610
  throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.sdkNotConfigured"));
3409
3611
  }
3612
+ let mcpToolset = null;
3410
3613
  try {
3411
3614
  const toolSet = {};
3412
3615
  for (const tool3 of spec.tools) {
3413
3616
  toolSet[tool3.name] = specToolToExternalTool(tool3);
3414
3617
  }
3618
+ if ((this.config.mcpServers?.length ?? 0) > 0) {
3619
+ mcpToolset = await createMcpToolsets(this.config.mcpServers ?? [], {
3620
+ onNameCollision: "error"
3621
+ });
3622
+ for (const [toolName, mcpTool] of Object.entries(mcpToolset.tools)) {
3623
+ if (toolSet[toolName]) {
3624
+ throw new Error(`MCP tool "${toolName}" collides with a ContractSpec tool. Configure MCP toolPrefix values to avoid collisions.`);
3625
+ }
3626
+ toolSet[toolName] = this.mcpToolToExternalTool(toolName, mcpTool);
3627
+ }
3628
+ }
3415
3629
  const instructions = await injectStaticKnowledge(spec.instructions, spec.knowledge ?? [], undefined);
3416
3630
  const contextId = `claude-${agentKey(spec.meta)}-${Date.now()}`;
3417
3631
  const metadata = {
@@ -3419,6 +3633,7 @@ class ClaudeAgentSDKProvider {
3419
3633
  extendedThinkingEnabled: this.config.extendedThinking ?? false,
3420
3634
  mcpServerIds: this.config.mcpServers?.map((s) => s.name) ?? []
3421
3635
  };
3636
+ const cleanupMcp = mcpToolset?.cleanup;
3422
3637
  return {
3423
3638
  id: contextId,
3424
3639
  spec: {
@@ -3427,9 +3642,18 @@ class ClaudeAgentSDKProvider {
3427
3642
  },
3428
3643
  tools: toolSet,
3429
3644
  metadata,
3430
- cleanup: async () => {}
3645
+ cleanup: async () => {
3646
+ if (cleanupMcp) {
3647
+ await cleanupMcp();
3648
+ }
3649
+ }
3431
3650
  };
3432
3651
  } catch (error) {
3652
+ if (mcpToolset) {
3653
+ await mcpToolset.cleanup().catch(() => {
3654
+ return;
3655
+ });
3656
+ }
3433
3657
  throw new ContextCreationError(this.name, createAgentI18n(this.config.locale).t("error.provider.contextCreation", {
3434
3658
  error: error instanceof Error ? error.message : String(error)
3435
3659
  }), error instanceof Error ? error : undefined);
@@ -3444,7 +3668,7 @@ ${params.systemOverride}` : context.spec.instructions;
3444
3668
  const claudeContext = buildClaudeAgentContext(params.options);
3445
3669
  let session = createEmptyClaudeSession();
3446
3670
  session = appendUserMessage(session, params.prompt);
3447
- const claudeTools = this.prepareToolsForSDK(context, params);
3671
+ const claudeTools = this.prepareToolsForSDK(context);
3448
3672
  const rawResponse = await sdk.execute({
3449
3673
  model: this.config.model,
3450
3674
  system: systemPrompt,
@@ -3500,7 +3724,7 @@ ${params.systemOverride}` : context.spec.instructions;
3500
3724
 
3501
3725
  ${params.systemOverride}` : context.spec.instructions;
3502
3726
  const claudeContext = buildClaudeAgentContext(params.options);
3503
- const claudeTools = this.prepareToolsForSDK(context, params);
3727
+ const claudeTools = this.prepareToolsForSDK(context);
3504
3728
  const stream = await sdk.stream({
3505
3729
  model: this.config.model,
3506
3730
  system: systemPrompt,
@@ -3583,30 +3807,77 @@ ${params.systemOverride}` : context.spec.instructions;
3583
3807
  throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.claudeSdkMissing"));
3584
3808
  }
3585
3809
  }
3586
- prepareToolsForSDK(context, params) {
3587
- const handlers = new Map;
3588
- for (const tool3 of context.spec.tools) {
3589
- const externalTool = context.tools[tool3.name];
3590
- if (externalTool?.execute) {
3591
- handlers.set(tool3.name, async (input) => {
3592
- if (!externalTool.execute) {
3593
- throw new Error(createAgentI18n(this.config.locale).t("error.toolNoExecuteHandler", {
3594
- name: tool3.name
3595
- }));
3596
- }
3597
- const result = await externalTool.execute(input);
3810
+ prepareToolsForSDK(context) {
3811
+ const i18n = createAgentI18n(this.config.locale);
3812
+ const toolsForSdk = [];
3813
+ for (const [toolName, externalTool] of Object.entries(context.tools)) {
3814
+ if (!externalTool.execute) {
3815
+ continue;
3816
+ }
3817
+ toolsForSdk.push({
3818
+ name: toolName,
3819
+ description: externalTool.description ?? i18n.t("tool.fallbackDescription", { name: toolName }),
3820
+ input_schema: this.normalizeToolSchemaForClaude(externalTool.inputSchema),
3821
+ requires_confirmation: externalTool.requiresApproval,
3822
+ execute: async (input) => {
3823
+ const result = await externalTool.execute?.(input);
3598
3824
  return typeof result === "string" ? result : JSON.stringify(result);
3825
+ }
3826
+ });
3827
+ }
3828
+ return toolsForSdk;
3829
+ }
3830
+ mcpToolToExternalTool(toolName, tool3) {
3831
+ return {
3832
+ name: toolName,
3833
+ description: tool3.description ?? createAgentI18n(this.config.locale).t("tool.fallbackDescription", {
3834
+ name: toolName
3835
+ }),
3836
+ inputSchema: this.normalizeExternalInputSchema(tool3.inputSchema),
3837
+ execute: async (input) => {
3838
+ if (!tool3.execute) {
3839
+ throw new Error(createAgentI18n(this.config.locale).t("error.toolNoExecuteHandler", {
3840
+ name: toolName
3841
+ }));
3842
+ }
3843
+ return tool3.execute(input, {
3844
+ toolCallId: `mcp-${randomUUID2()}`,
3845
+ messages: []
3599
3846
  });
3600
3847
  }
3848
+ };
3849
+ }
3850
+ normalizeExternalInputSchema(schema) {
3851
+ if (this.isRecord(schema)) {
3852
+ const type = schema["type"];
3853
+ if (type === "object" || schema["properties"]) {
3854
+ return schema;
3855
+ }
3601
3856
  }
3602
- return specToolsToClaudeAgentTools(context.spec.tools, handlers, {
3603
- agentId: context.id,
3604
- sessionId: params.options?.sessionId,
3605
- tenantId: params.options?.tenantId,
3606
- actorId: params.options?.actorId,
3607
- metadata: params.options?.metadata,
3608
- signal: params.signal
3609
- });
3857
+ return {
3858
+ type: "object",
3859
+ properties: {}
3860
+ };
3861
+ }
3862
+ normalizeToolSchemaForClaude(schema) {
3863
+ if (schema.type === "object") {
3864
+ return {
3865
+ type: "object",
3866
+ properties: schema.properties,
3867
+ required: schema.required,
3868
+ additionalProperties: schema.additionalProperties
3869
+ };
3870
+ }
3871
+ return {
3872
+ type: "object",
3873
+ properties: {
3874
+ value: schema
3875
+ },
3876
+ required: ["value"]
3877
+ };
3878
+ }
3879
+ isRecord(value) {
3880
+ return typeof value === "object" && value !== null;
3610
3881
  }
3611
3882
  async executeTool(toolCall, context, _params) {
3612
3883
  const tool3 = context.tools[toolCall.toolName];
@@ -3662,6 +3933,7 @@ var init_adapter2 = __esm(() => {
3662
3933
  init_types();
3663
3934
  init_tool_bridge();
3664
3935
  init_injector();
3936
+ init_mcp_client();
3665
3937
  init_i18n();
3666
3938
  });
3667
3939
 
@@ -4320,6 +4592,7 @@ class UnifiedAgent {
4320
4592
  } catch (error) {
4321
4593
  this.state.lastError = error instanceof Error ? error : new Error(String(error));
4322
4594
  if (this.config.fallbackBackend && this.config.fallbackBackend !== backend) {
4595
+ await this.cleanupProviderContext();
4323
4596
  console.warn(this.i18n().t("log.unifiedAgent.fallback", {
4324
4597
  backend: String(backend),
4325
4598
  fallback: String(this.config.fallbackBackend)
@@ -4390,16 +4663,24 @@ class UnifiedAgent {
4390
4663
  }
4391
4664
  async runWithAISDK(message, options) {
4392
4665
  const { ContractSpecAgent: ContractSpecAgent2 } = await Promise.resolve().then(() => (init_contract_spec_agent(), exports_contract_spec_agent));
4666
+ const backendConfig = this.getAISDKConfig();
4393
4667
  const model = await this.resolveAISDKModel();
4394
4668
  const agent = await ContractSpecAgent2.create({
4395
4669
  spec: this.spec,
4396
4670
  model,
4397
- toolHandlers: this.tools
4398
- });
4399
- return await agent.generate({
4400
- prompt: message,
4401
- options
4671
+ toolHandlers: this.tools,
4672
+ mcpServers: backendConfig?.mcpServers
4402
4673
  });
4674
+ try {
4675
+ return await agent.generate({
4676
+ prompt: message,
4677
+ options
4678
+ });
4679
+ } finally {
4680
+ await agent.cleanup().catch(() => {
4681
+ return;
4682
+ });
4683
+ }
4403
4684
  }
4404
4685
  async runWithExternalProvider(message, options) {
4405
4686
  if (!this.provider || !this.context) {
@@ -4507,6 +4788,7 @@ class UnifiedAgent {
4507
4788
  if (backend === this.state.backend) {
4508
4789
  return;
4509
4790
  }
4791
+ await this.cleanupProviderContext();
4510
4792
  this.state.backend = backend;
4511
4793
  this.state.isReady = false;
4512
4794
  this.provider = undefined;
@@ -4517,8 +4799,20 @@ class UnifiedAgent {
4517
4799
  this.state.messageCount = 0;
4518
4800
  this.state.sessionId = undefined;
4519
4801
  this.state.lastError = undefined;
4802
+ this.cleanupProviderContext().catch(() => {
4803
+ return;
4804
+ });
4520
4805
  this.context = undefined;
4521
4806
  }
4807
+ async cleanupProviderContext() {
4808
+ const context = this.context;
4809
+ this.context = undefined;
4810
+ if (context) {
4811
+ await context.cleanup().catch(() => {
4812
+ return;
4813
+ });
4814
+ }
4815
+ }
4522
4816
  addTool(name, handler) {
4523
4817
  this.tools.set(name, handler);
4524
4818
  }
@@ -4538,7 +4832,8 @@ function createAISDKAgent(spec, options) {
4538
4832
  modelInstance: options?.modelInstance,
4539
4833
  provider: options?.provider,
4540
4834
  temperature: options?.temperature,
4541
- maxTokens: options?.maxTokens
4835
+ maxTokens: options?.maxTokens,
4836
+ mcpServers: options?.mcpServers
4542
4837
  }
4543
4838
  });
4544
4839
  }
@@ -2366,7 +2366,7 @@ class ClaudeAgentExporter {
2366
2366
  lines.push(i18n.t("export.mcpServers"));
2367
2367
  lines.push("");
2368
2368
  for (const server of options.mcpServers) {
2369
- lines.push(`- **${server.name}**: \`${server.command}${server.args ? " " + server.args.join(" ") : ""}\``);
2369
+ lines.push(`- **${server.name}**: \`${this.formatMcpServer(server)}\``);
2370
2370
  }
2371
2371
  lines.push("");
2372
2372
  }
@@ -2376,6 +2376,16 @@ class ClaudeAgentExporter {
2376
2376
  return lines.join(`
2377
2377
  `);
2378
2378
  }
2379
+ formatMcpServer(server) {
2380
+ if ("command" in server) {
2381
+ const args = server.args ? ` ${server.args.join(" ")}` : "";
2382
+ return `${server.command}${args}`;
2383
+ }
2384
+ if (server.transport === "http" || server.transport === "sse") {
2385
+ return `${server.transport} ${server.url}`;
2386
+ }
2387
+ return server.url;
2388
+ }
2379
2389
  }
2380
2390
  function exportToClaudeAgent(spec, options) {
2381
2391
  const exporter = new ClaudeAgentExporter;
@@ -2652,7 +2652,7 @@ class ClaudeAgentExporter {
2652
2652
  lines.push(i18n.t("export.mcpServers"));
2653
2653
  lines.push("");
2654
2654
  for (const server of options.mcpServers) {
2655
- lines.push(`- **${server.name}**: \`${server.command}${server.args ? " " + server.args.join(" ") : ""}\``);
2655
+ lines.push(`- **${server.name}**: \`${this.formatMcpServer(server)}\``);
2656
2656
  }
2657
2657
  lines.push("");
2658
2658
  }
@@ -2662,6 +2662,16 @@ class ClaudeAgentExporter {
2662
2662
  return lines.join(`
2663
2663
  `);
2664
2664
  }
2665
+ formatMcpServer(server) {
2666
+ if ("command" in server) {
2667
+ const args = server.args ? ` ${server.args.join(" ")}` : "";
2668
+ return `${server.command}${args}`;
2669
+ }
2670
+ if (server.transport === "http" || server.transport === "sse") {
2671
+ return `${server.transport} ${server.url}`;
2672
+ }
2673
+ return server.url;
2674
+ }
2665
2675
  }
2666
2676
  function exportToClaudeAgent(spec, options) {
2667
2677
  const exporter = new ClaudeAgentExporter;