@ai-sdk/harness-acp 1.0.39 → 1.0.41

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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @ai-sdk/harness-acp
2
2
 
3
+ ## 1.0.41
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [9e1d1b2]
8
+ - Updated dependencies [a495511]
9
+ - @ai-sdk/provider-utils@5.0.37
10
+ - @ai-sdk/harness@1.0.103
11
+
12
+ ## 1.0.40
13
+
14
+ ### Patch Changes
15
+
16
+ - ceb601c: fix(harness-acp): fix stream translator to match most appropriate tool based on input shape when no name is present and multiple candidates would match the required arguments
17
+ - 255cccf: feat(harness): add `writeInstructions` helper and support filesystem based `instructionsMapping` in ACP backed harness adapters
18
+ - 668b51d: fix(harness-acp): remove problematic condition that leads to errors when using `stopWhen`
19
+ - eeed977: feat(harness): allow passing arbitrary headers with inference requests via `headers` property in `HarnessAgentSettings`
20
+ - 1291df7: feat(harness-acp): support control over how host tools are exposed via `hostToolMcpTransport` config
21
+ - a39c8bf: chore(harness): clarify `writeSkills` helper intent to require materializing skills in HOME directory
22
+ - Updated dependencies [fe86f8f]
23
+ - Updated dependencies [255cccf]
24
+ - Updated dependencies [eeed977]
25
+ - Updated dependencies [a39c8bf]
26
+ - @ai-sdk/harness@1.0.102
27
+
3
28
  ## 1.0.39
4
29
 
5
30
  ### Patch Changes
package/README.md CHANGED
@@ -111,9 +111,10 @@ Use `instructionMapping` when the ACP implementation exposes a native system
111
111
  or developer prompt. A `session-meta` mapping writes `HarnessAgent`
112
112
  instructions below the ACP session request's `_meta` field. A
113
113
  `launch-env-json` mapping merges them into a JSON environment variable before
114
- the implementation starts. Without a mapping, the adapter preserves its
115
- backward-compatible behavior and prepends instructions to the first user
116
- prompt.
114
+ the implementation starts. A `filesystem` mapping writes instructions to a
115
+ markdown file at a relative path under the implementation's effective `$HOME`.
116
+ Without a mapping, the adapter preserves its backward-compatible behavior and
117
+ prepends instructions to the first user prompt.
117
118
 
118
119
  Skills are written to `.agents/skills` below the ACP implementation's effective
119
120
  `$HOME` and discovered natively by the implementation. Set `skillsDirectory`
@@ -12,7 +12,7 @@ import {
12
12
  ListToolsRequestSchema,
13
13
  McpError
14
14
  } from "@modelcontextprotocol/sdk/types.js";
15
- var VERSION = true ? "1.0.39" : "0.0.0-test";
15
+ var VERSION = true ? "1.0.41" : "0.0.0-test";
16
16
  function createHostToolMCPServer({
17
17
  tools: tools2,
18
18
  revision = 1,
@@ -664,7 +664,6 @@ function serialiseError(err) {
664
664
  import * as acp5 from "@agentclientprotocol/sdk";
665
665
  import { spawn } from "child_process";
666
666
  import { readFile, writeFile as writeFile2 } from "fs/promises";
667
- import { fileURLToPath } from "url";
668
667
  import { Readable, Writable } from "stream";
669
668
  import { argv, env as processEnv } from "process";
670
669
 
@@ -695,6 +694,10 @@ var profileValueSchema = z.lazy(
695
694
  z.record(z.string(), profileValueSchema)
696
695
  ])
697
696
  );
697
+ var hostToolMcpTransportSchema = z.enum([
698
+ "stdio",
699
+ "http"
700
+ ]);
698
701
  var serializableRecordSchema = z.record(z.string(), serializableValueSchema);
699
702
  var profileRecordSchema = z.record(z.string(), profileValueSchema);
700
703
  var authenticationSchema = z.object({
@@ -715,7 +718,8 @@ var bridgeConfigurationSchema = z.object({
715
718
  providerEnvironment: z.record(z.string(), z.string()).optional(),
716
719
  sessionMeta: serializableRecordSchema.optional(),
717
720
  clientCapabilities: serializableRecordSchema.optional(),
718
- askUserQuestionsRequestMethod: z.string().optional()
721
+ askUserQuestionsRequestMethod: z.string().optional(),
722
+ hostToolMcpTransport: hostToolMcpTransportSchema.optional()
719
723
  });
720
724
  async function readACPBridgeEnvironment({
721
725
  env
@@ -1417,7 +1421,24 @@ function resolveBuiltinTool({
1417
1421
  const schemaMatches = builtinTools.filter(
1418
1422
  (tool) => matchesBuiltinToolInput({ rawInput, inputSchema: tool.inputSchema })
1419
1423
  );
1420
- return schemaMatches.length === 1 ? schemaMatches[0] : void 0;
1424
+ if (schemaMatches.length <= 1) return schemaMatches[0];
1425
+ return findMostSpecificSchemaMatch({ rawInput, schemaMatches });
1426
+ }
1427
+ function findMostSpecificSchemaMatch({
1428
+ rawInput,
1429
+ schemaMatches
1430
+ }) {
1431
+ if (!isRecord3(rawInput)) return void 0;
1432
+ const rawInputKeys = Object.keys(rawInput);
1433
+ const coverageOf = (tool) => {
1434
+ const properties = isRecord3(tool.inputSchema) ? isRecord3(tool.inputSchema.properties) ? tool.inputSchema.properties : {} : {};
1435
+ return rawInputKeys.filter((key) => key in properties).length;
1436
+ };
1437
+ const highestCoverage = Math.max(...schemaMatches.map(coverageOf));
1438
+ const mostSpecificMatches = schemaMatches.filter(
1439
+ (tool) => coverageOf(tool) === highestCoverage
1440
+ );
1441
+ return mostSpecificMatches.length === 1 ? mostSpecificMatches[0] : void 0;
1421
1442
  }
1422
1443
  function findBuiltinToolByTitle({
1423
1444
  title,
@@ -2300,6 +2321,14 @@ async function resolveACPInstructionConfiguration({
2300
2321
  if (instructionMapping == null || instructions == null || instructions.length === 0) {
2301
2322
  return { sessionMeta, environment: resolvedEnvironment };
2302
2323
  }
2324
+ if (instructionMapping.type === "filesystem") {
2325
+ if (typeof instructionMapping.path !== "string" || instructionMapping.path.trim().length === 0) {
2326
+ throw new Error(
2327
+ "ACP instruction mapping filesystem path must be a non-empty string."
2328
+ );
2329
+ }
2330
+ return { sessionMeta, environment: resolvedEnvironment };
2331
+ }
2303
2332
  assertSafePath({ path: instructionMapping.path });
2304
2333
  if (instructionMapping.type === "session-meta") {
2305
2334
  return {
@@ -2371,11 +2400,263 @@ function isRecord5(value) {
2371
2400
  }
2372
2401
 
2373
2402
  // src/v1/bridge/host-tool-relay.ts
2374
- import { randomBytes, timingSafeEqual } from "crypto";
2403
+ import { randomBytes, randomUUID as randomUUID3, timingSafeEqual } from "crypto";
2375
2404
  import { createServer } from "http";
2405
+
2406
+ // src/v1/bridge/host-tool-mcp-http.ts
2407
+ import { randomUUID as randomUUID2 } from "crypto";
2408
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
2409
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
2410
+
2411
+ // src/v1/bridge/host-tool-mcp-server.ts
2412
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2413
+ import {
2414
+ CallToolRequestSchema,
2415
+ ErrorCode,
2416
+ ListToolsRequestSchema,
2417
+ McpError
2418
+ } from "@modelcontextprotocol/sdk/types.js";
2419
+ var VERSION = true ? "1.0.41" : "0.0.0-test";
2420
+ function createHostToolMCPServer({
2421
+ tools,
2422
+ revision = 1,
2423
+ invoke,
2424
+ onListTools
2425
+ }) {
2426
+ let catalog = createCatalog({ revision, tools });
2427
+ let catalogAcknowledgmentError;
2428
+ const server = new Server(
2429
+ {
2430
+ name: "@ai-sdk/harness-acp-host-tools",
2431
+ version: VERSION
2432
+ },
2433
+ { capabilities: { tools: { listChanged: true } } }
2434
+ );
2435
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
2436
+ if (catalogAcknowledgmentError != null) {
2437
+ throw catalogAcknowledgmentError;
2438
+ }
2439
+ const current = catalog;
2440
+ if (onListTools != null) {
2441
+ setImmediate(() => {
2442
+ void onListTools({ revision: current.revision }).catch((error) => {
2443
+ catalogAcknowledgmentError = error;
2444
+ });
2445
+ });
2446
+ }
2447
+ return { tools: current.tools.map(toMCPTool) };
2448
+ });
2449
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2450
+ const current = catalog;
2451
+ const tool = current.byName.get(request.params.name);
2452
+ if (tool == null) {
2453
+ throw new McpError(
2454
+ ErrorCode.InvalidParams,
2455
+ `Unknown host tool: ${request.params.name}`
2456
+ );
2457
+ }
2458
+ const input = request.params.arguments ?? {};
2459
+ const result = await invoke({
2460
+ toolName: tool.name,
2461
+ input,
2462
+ catalogRevision: current.revision
2463
+ });
2464
+ return toCallToolResult({ result });
2465
+ });
2466
+ return {
2467
+ server,
2468
+ updateCatalog: async ({ revision: nextRevision, tools: nextTools }) => {
2469
+ catalog = createCatalog({
2470
+ revision: nextRevision,
2471
+ tools: nextTools
2472
+ });
2473
+ await server.sendToolListChanged();
2474
+ }
2475
+ };
2476
+ }
2477
+ function createCatalog({
2478
+ revision,
2479
+ tools
2480
+ }) {
2481
+ return {
2482
+ revision,
2483
+ tools: [...tools],
2484
+ byName: new Map(tools.map((tool) => [tool.name, tool]))
2485
+ };
2486
+ }
2487
+ function toMCPTool(tool) {
2488
+ return {
2489
+ name: tool.name,
2490
+ ...tool.description == null ? {} : { description: tool.description },
2491
+ inputSchema: requireObjectSchema({
2492
+ toolName: tool.name,
2493
+ schema: tool.inputSchema ?? { type: "object" }
2494
+ })
2495
+ };
2496
+ }
2497
+ function requireObjectSchema({
2498
+ toolName,
2499
+ schema
2500
+ }) {
2501
+ if (schema == null || typeof schema !== "object" || Array.isArray(schema) || Reflect.get(schema, "type") !== void 0 && Reflect.get(schema, "type") !== "object") {
2502
+ throw new Error(
2503
+ `Host tool ${toolName} must use an object JSON Schema for MCP.`
2504
+ );
2505
+ }
2506
+ return schema;
2507
+ }
2508
+ function toCallToolResult({
2509
+ result
2510
+ }) {
2511
+ return {
2512
+ content: [
2513
+ {
2514
+ type: "text",
2515
+ text: stringifyOutput({ output: result.output })
2516
+ }
2517
+ ],
2518
+ ...result.isError ? { isError: true } : {},
2519
+ _meta: {
2520
+ "ai-sdk-harness-acp-correlation": result.correlationToken
2521
+ }
2522
+ };
2523
+ }
2524
+ function stringifyOutput({ output }) {
2525
+ if (output === void 0) return "null";
2526
+ try {
2527
+ return JSON.stringify(output);
2528
+ } catch {
2529
+ return JSON.stringify({
2530
+ error: "Host tool output could not be serialized as JSON."
2531
+ });
2532
+ }
2533
+ }
2534
+
2535
+ // src/v1/bridge/host-tool-mcp-http.ts
2536
+ var HOST_TOOL_MCP_ENDPOINT_PATH = "/mcp";
2537
+ function createHostToolMCPHttpEndpoint({
2538
+ tools,
2539
+ revision,
2540
+ invoke,
2541
+ onListTools
2542
+ }) {
2543
+ let catalog = { revision, tools: [...tools] };
2544
+ const sessions = /* @__PURE__ */ new Map();
2545
+ let closed = false;
2546
+ async function openSession({
2547
+ request,
2548
+ response,
2549
+ body
2550
+ }) {
2551
+ const hostToolServer = createHostToolMCPServer({
2552
+ tools: catalog.tools,
2553
+ revision: catalog.revision,
2554
+ invoke,
2555
+ onListTools
2556
+ });
2557
+ const transport = new StreamableHTTPServerTransport({
2558
+ sessionIdGenerator: () => randomUUID2(),
2559
+ onsessioninitialized: (sessionId) => {
2560
+ sessions.set(sessionId, { transport, hostToolServer });
2561
+ },
2562
+ onsessionclosed: (sessionId) => {
2563
+ sessions.delete(sessionId);
2564
+ }
2565
+ });
2566
+ transport.onclose = () => {
2567
+ const { sessionId } = transport;
2568
+ if (sessionId != null) sessions.delete(sessionId);
2569
+ };
2570
+ await hostToolServer.server.connect(transport);
2571
+ await transport.handleRequest(request, response, body);
2572
+ }
2573
+ return {
2574
+ handleRequest: async ({ request, response, body }) => {
2575
+ if (closed) {
2576
+ respondWithJSONRPCError({
2577
+ response,
2578
+ status: 503,
2579
+ code: -32e3,
2580
+ message: "The host tool MCP endpoint is closed."
2581
+ });
2582
+ return;
2583
+ }
2584
+ const sessionId = readSessionId({ request });
2585
+ if (sessionId != null) {
2586
+ const session2 = sessions.get(sessionId);
2587
+ if (session2 == null) {
2588
+ respondWithJSONRPCError({
2589
+ response,
2590
+ status: 404,
2591
+ code: -32001,
2592
+ message: "Unknown host tool MCP session."
2593
+ });
2594
+ return;
2595
+ }
2596
+ await session2.transport.handleRequest(request, response, body);
2597
+ return;
2598
+ }
2599
+ if (request.method !== "POST" || !isInitializeRequest(body)) {
2600
+ respondWithJSONRPCError({
2601
+ response,
2602
+ status: 400,
2603
+ code: -32e3,
2604
+ message: "Host tool MCP requests without a session id must be an initialize request."
2605
+ });
2606
+ return;
2607
+ }
2608
+ await openSession({ request, response, body });
2609
+ },
2610
+ updateCatalog: async ({ revision: nextRevision, tools: nextTools }) => {
2611
+ catalog = { revision: nextRevision, tools: [...nextTools] };
2612
+ await Promise.all(
2613
+ [...sessions.values()].map(
2614
+ (session2) => session2.hostToolServer.updateCatalog({
2615
+ revision: nextRevision,
2616
+ tools: nextTools
2617
+ })
2618
+ )
2619
+ );
2620
+ },
2621
+ close: async () => {
2622
+ if (closed) return;
2623
+ closed = true;
2624
+ const live = [...sessions.values()];
2625
+ sessions.clear();
2626
+ await Promise.all(
2627
+ live.map((session2) => session2.hostToolServer.server.close())
2628
+ );
2629
+ }
2630
+ };
2631
+ }
2632
+ function readSessionId({
2633
+ request
2634
+ }) {
2635
+ const value = request.headers["mcp-session-id"];
2636
+ const sessionId = Array.isArray(value) ? value[0] : value;
2637
+ return sessionId == null || sessionId.length === 0 ? void 0 : sessionId;
2638
+ }
2639
+ function respondWithJSONRPCError({
2640
+ response,
2641
+ status,
2642
+ code,
2643
+ message
2644
+ }) {
2645
+ response.writeHead(status, { "content-type": "application/json" });
2646
+ response.end(
2647
+ JSON.stringify({
2648
+ jsonrpc: "2.0",
2649
+ error: { code, message },
2650
+ id: null
2651
+ })
2652
+ );
2653
+ }
2654
+
2655
+ // src/v1/bridge/host-tool-relay.ts
2376
2656
  async function startHostToolRelay({
2377
2657
  tools,
2378
- serverName
2658
+ serverName,
2659
+ mcpTransport = "stdio"
2379
2660
  }) {
2380
2661
  const state = {
2381
2662
  tools: [...tools],
@@ -2390,8 +2671,44 @@ async function startHostToolRelay({
2390
2671
  let activeTurn;
2391
2672
  let invocationOrder = 0;
2392
2673
  let closePromise;
2674
+ const mcpEndpoint = mcpTransport === "http" ? createHostToolMCPHttpEndpoint({
2675
+ tools: state.tools,
2676
+ revision: state.revision,
2677
+ invoke: ({ toolName, input, catalogRevision }) => handleInvocation({
2678
+ body: {
2679
+ requestId: randomUUID3(),
2680
+ toolName,
2681
+ input,
2682
+ catalogRevision
2683
+ },
2684
+ state,
2685
+ serverName,
2686
+ turn: activeTurn,
2687
+ nextInvocationOrder: () => ++invocationOrder
2688
+ }),
2689
+ onListTools: async ({ revision }) => {
2690
+ acknowledgeCatalog({ state, revision });
2691
+ }
2692
+ }) : void 0;
2393
2693
  const server = createServer(async (request, response) => {
2394
2694
  try {
2695
+ if (mcpEndpoint != null && request.url === HOST_TOOL_MCP_ENDPOINT_PATH) {
2696
+ if (!credentialsMatch({
2697
+ expected: credential,
2698
+ actual: request.headers.authorization
2699
+ })) {
2700
+ throw new RelayRequestError({
2701
+ status: 401,
2702
+ message: "Invalid host tool relay credential."
2703
+ });
2704
+ }
2705
+ await mcpEndpoint.handleRequest({
2706
+ request,
2707
+ response,
2708
+ ...request.method === "POST" ? { body: await readJSONBody({ request }) } : {}
2709
+ });
2710
+ return;
2711
+ }
2395
2712
  const result = await handleRequest({
2396
2713
  request,
2397
2714
  credential,
@@ -2403,6 +2720,10 @@ async function startHostToolRelay({
2403
2720
  response.writeHead(200, { "content-type": "application/json" });
2404
2721
  response.end(JSON.stringify(result));
2405
2722
  } catch (error) {
2723
+ if (response.headersSent) {
2724
+ response.end();
2725
+ return;
2726
+ }
2406
2727
  const status = error instanceof RelayRequestError ? error.status : 500;
2407
2728
  response.writeHead(status, { "content-type": "application/json" });
2408
2729
  response.end(
@@ -2416,6 +2737,9 @@ async function startHostToolRelay({
2416
2737
  const address = server.address();
2417
2738
  return {
2418
2739
  url: `http://127.0.0.1:${address.port}/invoke`,
2740
+ ...mcpEndpoint == null ? {} : {
2741
+ mcpUrl: `http://127.0.0.1:${address.port}${HOST_TOOL_MCP_ENDPOINT_PATH}`
2742
+ },
2419
2743
  credential,
2420
2744
  bindTurn: ({ turn }) => {
2421
2745
  if (activeTurn != null && activeTurn !== turn) {
@@ -2435,6 +2759,10 @@ async function startHostToolRelay({
2435
2759
  state.fingerprint = fingerprint;
2436
2760
  state.revision += 1;
2437
2761
  resolveCatalogChanges({ state });
2762
+ void mcpEndpoint?.updateCatalog({
2763
+ revision: state.revision,
2764
+ tools: state.tools
2765
+ });
2438
2766
  return { changed: true, revision: state.revision };
2439
2767
  },
2440
2768
  waitForCatalogRefresh: ({ revision, timeoutMs }) => waitForCatalogRefresh({ state, revision, timeoutMs }),
@@ -2443,7 +2771,10 @@ async function startHostToolRelay({
2443
2771
  state.closed = true;
2444
2772
  resolveCatalogChanges({ state });
2445
2773
  resolveRefreshWaiters({ state, closing: true });
2446
- closePromise = closeServer({ server });
2774
+ closePromise = (async () => {
2775
+ await mcpEndpoint?.close();
2776
+ await closeServer({ server });
2777
+ })();
2447
2778
  return closePromise;
2448
2779
  }
2449
2780
  };
@@ -2521,13 +2852,16 @@ function handleCatalogSeen({
2521
2852
  message: "Invalid host tool catalog acknowledgment."
2522
2853
  });
2523
2854
  }
2524
- state.servedRevision = Math.max(
2525
- state.servedRevision,
2526
- body.revision
2527
- );
2528
- resolveRefreshWaiters({ state, closing: false });
2855
+ acknowledgeCatalog({ state, revision: body.revision });
2529
2856
  return { acknowledged: true };
2530
2857
  }
2858
+ function acknowledgeCatalog({
2859
+ state,
2860
+ revision
2861
+ }) {
2862
+ state.servedRevision = Math.max(state.servedRevision, revision);
2863
+ resolveRefreshWaiters({ state, closing: false });
2864
+ }
2531
2865
  async function handleInvocation({
2532
2866
  body,
2533
2867
  state,
@@ -2726,6 +3060,55 @@ var RelayRequestError = class extends Error {
2726
3060
  }
2727
3061
  };
2728
3062
 
3063
+ // src/v1/bridge/host-tool-mcp-definition.ts
3064
+ import { fileURLToPath } from "url";
3065
+ import { execPath } from "process";
3066
+ function createHostToolMcpServerDefinition({
3067
+ mcpTransport,
3068
+ relay,
3069
+ serverName,
3070
+ catalogPath,
3071
+ initialization,
3072
+ harnessId
3073
+ }) {
3074
+ if (mcpTransport === "stdio") {
3075
+ return {
3076
+ name: serverName,
3077
+ command: execPath,
3078
+ args: [fileURLToPath(new URL("./host-tool-mcp.mjs", import.meta.url))],
3079
+ env: [
3080
+ {
3081
+ name: "AI_SDK_ACP_HOST_TOOLS_FILE",
3082
+ value: catalogPath
3083
+ },
3084
+ {
3085
+ name: "AI_SDK_ACP_HOST_TOOL_RELAY_URL",
3086
+ value: relay.url
3087
+ },
3088
+ {
3089
+ name: "AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL",
3090
+ value: relay.credential
3091
+ }
3092
+ ]
3093
+ };
3094
+ }
3095
+ if (initialization.agentCapabilities?.mcpCapabilities?.http !== true) {
3096
+ throw new HarnessBridgeCapabilityUnsupportedError({
3097
+ harnessId,
3098
+ message: "This harness exposes host tools through an HTTP MCP server, but the ACP agent does not advertise support for HTTP MCP servers."
3099
+ });
3100
+ }
3101
+ if (relay.mcpUrl == null) {
3102
+ throw new Error("The host tool MCP HTTP endpoint is unavailable.");
3103
+ }
3104
+ return {
3105
+ type: "http",
3106
+ name: serverName,
3107
+ url: relay.mcpUrl,
3108
+ headers: [{ name: "Authorization", value: `Bearer ${relay.credential}` }]
3109
+ };
3110
+ }
3111
+
2729
3112
  // src/v1/bridge/refresh-host-tool-catalog.ts
2730
3113
  async function promptAndRefreshInitialHostToolCatalog({
2731
3114
  startPrompt,
@@ -3654,33 +4037,26 @@ async function ensureSession({
3654
4037
  initialization
3655
4038
  });
3656
4039
  const tools = start.tools ?? [];
4040
+ const mcpTransport = bridgeConfiguration.hostToolMcpTransport ?? "stdio";
3657
4041
  const catalogPath = `${bridgeStateDir}/host-tools.json`;
3658
- await writeFile2(catalogPath, JSON.stringify(tools), { mode: 384 });
4042
+ if (mcpTransport === "stdio") {
4043
+ await writeFile2(catalogPath, JSON.stringify(tools), { mode: 384 });
4044
+ }
3659
4045
  hostToolRelay = await startHostToolRelay({
3660
4046
  tools,
3661
- serverName: HOST_TOOL_MCP_SERVER_NAME
4047
+ serverName: HOST_TOOL_MCP_SERVER_NAME,
4048
+ mcpTransport
3662
4049
  });
3663
4050
  const mcpServers = [
3664
4051
  ...externalMcpServers,
3665
- {
3666
- name: HOST_TOOL_MCP_SERVER_NAME,
3667
- command: process.execPath,
3668
- args: [fileURLToPath(new URL("./host-tool-mcp.mjs", import.meta.url))],
3669
- env: [
3670
- {
3671
- name: "AI_SDK_ACP_HOST_TOOLS_FILE",
3672
- value: catalogPath
3673
- },
3674
- {
3675
- name: "AI_SDK_ACP_HOST_TOOL_RELAY_URL",
3676
- value: hostToolRelay.url
3677
- },
3678
- {
3679
- name: "AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL",
3680
- value: hostToolRelay.credential
3681
- }
3682
- ]
3683
- }
4052
+ createHostToolMcpServerDefinition({
4053
+ mcpTransport,
4054
+ relay: hostToolRelay,
4055
+ serverName: HOST_TOOL_MCP_SERVER_NAME,
4056
+ catalogPath,
4057
+ initialization,
4058
+ harnessId: bridgeType
4059
+ })
3684
4060
  ];
3685
4061
  let createdSession;
3686
4062
  if (start.recoveryMode?.type === "lossy-rerun") {