@akira-tl/forgerelay 1.1.0 → 1.1.1

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 (150) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +4 -2
  3. package/dist/activity/runtime/mcp-query-tools.js +16 -10
  4. package/dist/cli/mcp/external-mcp.js +481 -0
  5. package/dist/cli/mcp/status.js +295 -0
  6. package/dist/cli.js +14 -1
  7. package/dist/lsp/test-support/server-fixture.js +1 -2
  8. package/dist/mcp/oauth/auth-protocol.js +375 -0
  9. package/dist/mcp/oauth/oauth-provider.js +11 -12
  10. package/dist/mcp/oauth/oauth-store.js +2 -2
  11. package/dist/mcp/oauth/router.js +2 -6
  12. package/dist/mcp/operations/batch/executor.js +1 -1
  13. package/dist/mcp/operations/external-mcp/external-mcp-oauth.js +387 -0
  14. package/dist/mcp/operations/external-mcp/external-mcp-runtime.js +23 -6
  15. package/dist/mcp/operations/external-mcp/external-mcp.js +178 -23
  16. package/dist/mcp/operations/native-bulk-mutations.js +1 -1
  17. package/dist/mcp/process/tools.js +19 -15
  18. package/dist/mcp/request-context.js +18 -0
  19. package/dist/mcp/request-meta.js +28 -3
  20. package/dist/mcp/server/core/capabilities.js +1 -4
  21. package/dist/mcp/server/operations/runtime/filesystem-tools.js +35 -28
  22. package/dist/mcp/server/operations/runtime/operation-runtime.js +7 -7
  23. package/dist/mcp/server/transport/http-server.js +41 -20
  24. package/dist/mcp/server/workspace/runtime/workspace-open.js +13 -9
  25. package/dist/mcp/server/workspace/runtime/workspace-tools.js +29 -25
  26. package/dist/runtime/config/external-mcp-auth-store.js +225 -0
  27. package/dist/runtime/config/external-mcp-config.js +76 -22
  28. package/dist/runtime/config/external-mcp-registry.js +165 -0
  29. package/dist/runtime/testing/server-fixture.js +4 -4
  30. package/dist/server.js +15 -9
  31. package/dist/ui/.vite/manifest.json +297 -298
  32. package/dist/ui/activity-panel-app.html +1 -1
  33. package/dist/ui/assets/activity-panel-app-Bw7ZFX2g.js +114 -0
  34. package/dist/ui/assets/angular-html-DeUNP12X.js +1 -0
  35. package/dist/ui/assets/{angular-ts-BearSZDb.js → angular-ts-B3v8FKi_.js} +1 -1
  36. package/dist/ui/assets/{apl-CYQtr-y6.js → apl-Bs3iQm4P.js} +1 -1
  37. package/dist/ui/assets/{astro-DDzqKIjK.js → astro-D6GHecBY.js} +1 -1
  38. package/dist/ui/assets/{blade-DkwEyHvQ.js → blade-BMNbVOHv.js} +1 -1
  39. package/dist/ui/assets/c-BquuA6bv.js +1 -0
  40. package/dist/ui/assets/{cobol-xBn5JxHE.js → cobol-BuZ6kfps.js} +1 -1
  41. package/dist/ui/assets/{coffee-BaXXvoJw.js → coffee-DgC5uBzL.js} +1 -1
  42. package/dist/ui/assets/cpp-BdvWqCaB.js +1 -0
  43. package/dist/ui/assets/{crystal-DjOpXVU1.js → crystal-0Q5qBvNI.js} +1 -1
  44. package/dist/ui/assets/css-Be_T8idh.js +1 -0
  45. package/dist/ui/assets/{edge-DNaRizoR.js → edge-DaGLdgh_.js} +1 -1
  46. package/dist/ui/assets/{elixir-CwBMwZmy.js → elixir-CMgiFIzB.js} +1 -1
  47. package/dist/ui/assets/{elm-gOUD2CW3.js → elm-B-ufMlMC.js} +1 -1
  48. package/dist/ui/assets/{erb-BcR-fjUp.js → erb-CaGiOZM-.js} +1 -1
  49. package/dist/ui/assets/{git-rebase-BAQPKHF6.js → git-rebase-CpwUWCzK.js} +1 -1
  50. package/dist/ui/assets/{glimmer-js-P_wOfSz_.js → glimmer-js-BRxccvnE.js} +1 -1
  51. package/dist/ui/assets/{glimmer-ts-B44aY1fZ.js → glimmer-ts-CgQbPzlT.js} +1 -1
  52. package/dist/ui/assets/glsl-D7JmHFr0.js +1 -0
  53. package/dist/ui/assets/graphql-C8n0eUBK.js +1 -0
  54. package/dist/ui/assets/{hack-ddU2k0nt.js → hack-lVN7KVQv.js} +1 -1
  55. package/dist/ui/assets/haml-h18lG0pS.js +1 -0
  56. package/dist/ui/assets/{handlebars-BpzaUpmz.js → handlebars-lRFjRPfj.js} +1 -1
  57. package/dist/ui/assets/heavy-payload-Cqx9MOkH.js +290 -0
  58. package/dist/ui/assets/html-DtILqTE1.js +1 -0
  59. package/dist/ui/assets/{html-derivative-B2beVdmA.js → html-derivative-CSTSmPup.js} +1 -1
  60. package/dist/ui/assets/{http-iEskZy8U.js → http-DNI8fsbY.js} +1 -1
  61. package/dist/ui/assets/{hurl-BuUsLSKv.js → hurl-DgRi60JG.js} +1 -1
  62. package/dist/ui/assets/java-CW9pZ5bh.js +1 -0
  63. package/dist/ui/assets/javascript-Cvg2UrWL.js +1 -0
  64. package/dist/ui/assets/{jinja-CRpkWwrH.js → jinja-CZw_S1FB.js} +1 -1
  65. package/dist/ui/assets/{jison-BYfSnuHj.js → jison-C56u_FZv.js} +1 -1
  66. package/dist/ui/assets/json-DW2UTv1q.js +1 -0
  67. package/dist/ui/assets/jsx-Zj5gobdD.js +1 -0
  68. package/dist/ui/assets/{julia-B8Rxy7vD.js → julia-Cvcrre-L.js} +1 -1
  69. package/dist/ui/assets/{just-DzhIWpFP.js → just-8CZ2u6Tj.js} +1 -1
  70. package/dist/ui/assets/{latex-CUNjUUL-.js → latex-D289AXWG.js} +1 -1
  71. package/dist/ui/assets/{liquid-hUg7nC61.js → liquid-CFEX3SkZ.js} +1 -1
  72. package/dist/ui/assets/lua-BKpJ0ybO.js +1 -0
  73. package/dist/ui/assets/{marko-CQmIkwMF.js → marko-D9maZ0a6.js} +1 -1
  74. package/dist/ui/assets/{mdc-CB-6dHYa.js → mdc-rM9l0qWR.js} +1 -1
  75. package/dist/ui/assets/{nginx-CQORo_Bt.js → nginx-C9w6p2C9.js} +1 -1
  76. package/dist/ui/assets/{nim-BNwBNzdn.js → nim-BRePHk0J.js} +1 -1
  77. package/dist/ui/assets/{perl-Cnz14fAJ.js → perl-CskTmiPQ.js} +1 -1
  78. package/dist/ui/assets/{php-YywDo63b.js → php-DCU_FvNI.js} +1 -1
  79. package/dist/ui/assets/{pug-BwbJp4cM.js → pug-XLaVxTvv.js} +1 -1
  80. package/dist/ui/assets/{qml-D2DY6dMH.js → qml-CaONKSl-.js} +1 -1
  81. package/dist/ui/assets/r-BCVR0ZE3.js +1 -0
  82. package/dist/ui/assets/{razor-pMTG7k41.js → razor-DDnGXxnU.js} +1 -1
  83. package/dist/ui/assets/regexp-DWGTYYVx.js +1 -0
  84. package/dist/ui/assets/{rst-CO_ndDm4.js → rst-Dz3GWvQm.js} +1 -1
  85. package/dist/ui/assets/{ruby-xzRn9gTh.js → ruby-DC3jGtMY.js} +1 -1
  86. package/dist/ui/assets/{sas-CBdtFKLA.js → sas-7mNpvsjZ.js} +1 -1
  87. package/dist/ui/assets/scss-uBsoCJVy.js +1 -0
  88. package/dist/ui/assets/shellscript-BCN9N_Jf.js +1 -0
  89. package/dist/ui/assets/{shellsession-BaZnm5rZ.js → shellsession-Hsw46VXV.js} +1 -1
  90. package/dist/ui/assets/{soy-IouG3xdB.js → soy-D6KV69HU.js} +1 -1
  91. package/dist/ui/assets/sql-CVzVQkJh.js +1 -0
  92. package/dist/ui/assets/{stata-dgbkIZHP.js → stata-BwUjXNhI.js} +1 -1
  93. package/dist/ui/assets/{surrealql-CBROnw_p.js → surrealql-CgloWqRa.js} +1 -1
  94. package/dist/ui/assets/{svelte-6r6BpX4-.js → svelte-DcC3n6IC.js} +1 -1
  95. package/dist/ui/assets/{templ-BKD_PsbL.js → templ-DOFfnWTJ.js} +1 -1
  96. package/dist/ui/assets/{tex-CKY1bwHb.js → tex-ln89VPaX.js} +1 -1
  97. package/dist/ui/assets/{ts-tags-BiYP5N_C.js → ts-tags-CWMzCstH.js} +1 -1
  98. package/dist/ui/assets/tsx-DgzfiGeK.js +1 -0
  99. package/dist/ui/assets/{twig-BTe1oPFW.js → twig-Bi2itZL9.js} +1 -1
  100. package/dist/ui/assets/typescript-CQ24f4zW.js +1 -0
  101. package/dist/ui/assets/{vue-CT0IiySh.js → vue-BS8jE5u6.js} +1 -1
  102. package/dist/ui/assets/{vue-html-B-tXcbat.js → vue-html-o38xqhyB.js} +1 -1
  103. package/dist/ui/assets/{vue-vine-C5ZyDCrs.js → vue-vine-D2NvKv50.js} +1 -1
  104. package/dist/ui/assets/xml-_44rx9_2.js +1 -0
  105. package/dist/ui/assets/{xsl-DvDSndNI.js → xsl-B5QWQPoi.js} +1 -1
  106. package/dist/ui/assets/yaml-CKL2pEWe.js +1 -0
  107. package/dist/workspaces/relay/auth/remote-auth.js +3 -5
  108. package/dist/workspaces/relay/tests/test-support.js +7 -4
  109. package/dist/workspaces/relay/workspace-relay.js +14 -8
  110. package/docs/configuration.md +154 -4
  111. package/docs/debugging.md +8 -5
  112. package/docs/roadmap.md +64 -3
  113. package/docs/security.md +18 -0
  114. package/package.json +11 -4
  115. package/scripts/debug/accept/bootstrap.mjs +2 -0
  116. package/scripts/debug/accept/harness.mjs +9 -2
  117. package/scripts/debug/accept/modern-http.mjs +169 -0
  118. package/scripts/debug/accept/support.mjs +10 -6
  119. package/scripts/debug/accept.mjs +1 -0
  120. package/scripts/debug/runtime.mjs +4 -1
  121. package/scripts/debug/runtime.test.mjs +9 -0
  122. package/scripts/release/parity-sandbox.mjs +35 -0
  123. package/scripts/release/release-gate.test.mjs +42 -1
  124. package/scripts/release-parity.mjs +3 -22
  125. package/scripts/release-proof.mjs +24 -4
  126. package/scripts/release-proof.test.mjs +12 -4
  127. package/dist/ui/assets/activity-panel-app-XlqSanXT.js +0 -115
  128. package/dist/ui/assets/angular-html-tB9EchbM.js +0 -1
  129. package/dist/ui/assets/c-Dv-N5hjn.js +0 -1
  130. package/dist/ui/assets/cpp-C3unXX-3.js +0 -1
  131. package/dist/ui/assets/css-8Xr4kNNH.js +0 -1
  132. package/dist/ui/assets/glsl-BvCQg9MI.js +0 -1
  133. package/dist/ui/assets/graphql-C9S90gn_.js +0 -1
  134. package/dist/ui/assets/haml-Bb1w9rMG.js +0 -1
  135. package/dist/ui/assets/heavy-payload-CJKqi8Ac.js +0 -290
  136. package/dist/ui/assets/html-dUOs5pA9.js +0 -1
  137. package/dist/ui/assets/java-BFZCrORY.js +0 -1
  138. package/dist/ui/assets/javascript-DaIQ0Zqj.js +0 -1
  139. package/dist/ui/assets/json-BQC_Yp48.js +0 -1
  140. package/dist/ui/assets/jsx-Dd-CJRf9.js +0 -1
  141. package/dist/ui/assets/lua-BoZTiL2I.js +0 -1
  142. package/dist/ui/assets/r-B5nYsy-M.js +0 -1
  143. package/dist/ui/assets/regexp-oP0lbks_.js +0 -1
  144. package/dist/ui/assets/scss-CEqgKQNf.js +0 -1
  145. package/dist/ui/assets/shellscript-DzJJiWQC.js +0 -1
  146. package/dist/ui/assets/sql-DC2rdTzV.js +0 -1
  147. package/dist/ui/assets/tsx-D2OMiPNF.js +0 -1
  148. package/dist/ui/assets/typescript-BGIABksB.js +0 -1
  149. package/dist/ui/assets/xml-CfeBNlMP.js +0 -1
  150. package/dist/ui/assets/yaml-umbj2r1g.js +0 -1
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
3
3
  import { isAbsolute } from "node:path";
4
4
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
5
5
  import * as z from "zod/v4";
6
+ import { mcpHandlerRequestContext } from "../../../request-context.js";
6
7
  import { applyPatch } from "../../../filesystem/apply-patch.js";
7
8
  import { readFileTool } from "../../../filesystem/filesystem-tools.js";
8
9
  import { createMediaBudget } from "../../../operations/media-content.js";
@@ -85,6 +86,7 @@ export function registerFilesystemTools(options) {
85
86
  _meta: {},
86
87
  annotations: { readOnlyHint: true },
87
88
  }, async ({ workspaceId, member, path, paths, offset, limit }, extra) => {
89
+ const requestContext = mcpHandlerRequestContext(extra);
88
90
  if ((path === undefined) === (paths === undefined)) {
89
91
  throw new Error("read requires exactly one of path or paths.");
90
92
  }
@@ -101,7 +103,7 @@ export function registerFilesystemTools(options) {
101
103
  const mediaBudget = createMediaBudget(config.mediaMaxBytes);
102
104
  const execution = await executeBulkRead({
103
105
  paths: requestedPaths,
104
- signal: extra.signal,
106
+ signal: requestContext.signal,
105
107
  run: (requestedPath) => readFileTool({ path: requestedPath, offset, limit }, {
106
108
  cwd: process.cwd(),
107
109
  root: config.allowedRoots[0] ?? process.cwd(),
@@ -181,20 +183,20 @@ export function registerFilesystemTools(options) {
181
183
  }
182
184
  const target = resolveExecutionTarget(workspaceId, member);
183
185
  const executionWorkspaceId = target.executionWorkspaceId;
184
- const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
186
+ const executionContext = await prepareExecutionContext(target, requestContext);
185
187
  if (remoteWorkspaces.has(executionWorkspaceId)) {
186
- return presentSemanticWorkResult(await remoteWorkspaces.read(executionWorkspaceId, { path, paths, offset, limit }, hostScopeIdFor(extra._meta, extra.sessionId)), target, hostScopeIdFor(extra._meta, extra.sessionId));
188
+ return presentSemanticWorkResult(await remoteWorkspaces.read(executionWorkspaceId, { path, paths, offset, limit }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
187
189
  }
188
190
  if (path !== undefined) {
189
- return presentSemanticWorkResult(await coreOperations.read({ workspaceId: executionWorkspaceId, path, offset, limit }, executionContext), target, hostScopeIdFor(extra._meta, extra.sessionId));
191
+ return presentSemanticWorkResult(await coreOperations.read({ workspaceId: executionWorkspaceId, path, offset, limit }, executionContext), target, hostScopeIdFor(requestContext));
190
192
  }
191
193
  const workspace = workspaces.getWorkspace(executionWorkspaceId);
192
194
  let response;
193
- await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(extra._meta, extra.sessionId), toolNames.read, activityRequestFor({ workspaceId: executionWorkspaceId, paths, offset, limit }, executionContext), async (parentContext) => {
195
+ await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(requestContext), toolNames.read, activityRequestFor({ workspaceId: executionWorkspaceId, paths, offset, limit }, executionContext), async (parentContext) => {
194
196
  const mediaBudget = createMediaBudget(config.mediaMaxBytes);
195
197
  const execution = await executeBulkRead({
196
198
  paths: paths,
197
- signal: extra.signal,
199
+ signal: requestContext.signal,
198
200
  run: (childPath) => coreOperations.read({ workspaceId: executionWorkspaceId, path: childPath, offset, limit }, {
199
201
  ...executionContext,
200
202
  parentActivityId: parentContext.activityId,
@@ -247,7 +249,7 @@ export function registerFilesystemTools(options) {
247
249
  : { type: "succeeded" }, activityRelationFor(executionContext));
248
250
  if (!response)
249
251
  throw new Error("Bulk Read completed without a response.");
250
- return presentSemanticWorkResult(response, target, hostScopeIdFor(extra._meta, extra.sessionId));
252
+ return presentSemanticWorkResult(response, target, hostScopeIdFor(requestContext));
251
253
  });
252
254
  if (config.toolMode !== "codex") {
253
255
  registerAppTool(server, toolNames.write, {
@@ -267,13 +269,14 @@ export function registerFilesystemTools(options) {
267
269
  _meta: {},
268
270
  annotations: WRITE_TOOL_ANNOTATIONS,
269
271
  }, async ({ workspaceId, member, ...input }, extra) => {
272
+ const requestContext = mcpHandlerRequestContext(extra);
270
273
  const target = resolveExecutionTarget(workspaceId, member);
271
274
  const executionWorkspaceId = target.executionWorkspaceId;
272
- const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
275
+ const executionContext = await prepareExecutionContext(target, requestContext);
273
276
  if (remoteWorkspaces.has(executionWorkspaceId)) {
274
- return presentSemanticWorkResult(await remoteWorkspaces.write(executionWorkspaceId, input, hostScopeIdFor(extra._meta, extra.sessionId)), target, hostScopeIdFor(extra._meta, extra.sessionId));
277
+ return presentSemanticWorkResult(await remoteWorkspaces.write(executionWorkspaceId, input, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
275
278
  }
276
- return presentSemanticWorkResult(await coreOperations.write({ workspaceId: executionWorkspaceId, ...input }, executionContext), target, hostScopeIdFor(extra._meta, extra.sessionId));
279
+ return presentSemanticWorkResult(await coreOperations.write({ workspaceId: executionWorkspaceId, ...input }, executionContext), target, hostScopeIdFor(requestContext));
277
280
  });
278
281
  registerAppTool(server, toolNames.edit, {
279
282
  title: "Edit file",
@@ -317,19 +320,20 @@ export function registerFilesystemTools(options) {
317
320
  _meta: {},
318
321
  annotations: EDIT_TOOL_ANNOTATIONS,
319
322
  }, async ({ workspaceId, member, path, paths, edits }, extra) => {
323
+ const requestContext = mcpHandlerRequestContext(extra);
320
324
  if ((path === undefined) === (paths === undefined)) {
321
325
  throw new Error("edit requires exactly one of path or paths.");
322
326
  }
323
327
  const target = resolveExecutionTarget(workspaceId, member);
324
328
  const executionWorkspaceId = target.executionWorkspaceId;
325
- const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
329
+ const executionContext = await prepareExecutionContext(target, requestContext);
326
330
  if (remoteWorkspaces.has(executionWorkspaceId)) {
327
- return presentSemanticWorkResult(await remoteWorkspaces.edit(executionWorkspaceId, { path, paths, edits }, hostScopeIdFor(extra._meta, extra.sessionId)), target, hostScopeIdFor(extra._meta, extra.sessionId));
331
+ return presentSemanticWorkResult(await remoteWorkspaces.edit(executionWorkspaceId, { path, paths, edits }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
328
332
  }
329
333
  if (path !== undefined) {
330
- return presentSemanticWorkResult(await coreOperations.edit({ workspaceId: executionWorkspaceId, path, edits }, executionContext), target, hostScopeIdFor(extra._meta, extra.sessionId));
334
+ return presentSemanticWorkResult(await coreOperations.edit({ workspaceId: executionWorkspaceId, path, edits }, executionContext), target, hostScopeIdFor(requestContext));
331
335
  }
332
- return presentSemanticWorkResult(await nativeBulkMutations.edit({ workspaceId: executionWorkspaceId, paths: paths, edits }, executionContext), target, hostScopeIdFor(extra._meta, extra.sessionId));
336
+ return presentSemanticWorkResult(await nativeBulkMutations.edit({ workspaceId: executionWorkspaceId, paths: paths, edits }, executionContext), target, hostScopeIdFor(requestContext));
333
337
  });
334
338
  }
335
339
  registerAppTool(server, toolNames.rename, {
@@ -349,13 +353,14 @@ export function registerFilesystemTools(options) {
349
353
  _meta: {},
350
354
  annotations: EDIT_TOOL_ANNOTATIONS,
351
355
  }, async ({ workspaceId, member, path, newPath }, extra) => {
356
+ const requestContext = mcpHandlerRequestContext(extra);
352
357
  const target = resolveExecutionTarget(workspaceId, member);
353
358
  const executionWorkspaceId = target.executionWorkspaceId;
354
- const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
359
+ const executionContext = await prepareExecutionContext(target, requestContext);
355
360
  if (remoteWorkspaces.has(executionWorkspaceId)) {
356
- return presentSemanticWorkResult(await remoteWorkspaces.rename(executionWorkspaceId, { path, newPath }, hostScopeIdFor(extra._meta, extra.sessionId)), target, hostScopeIdFor(extra._meta, extra.sessionId));
361
+ return presentSemanticWorkResult(await remoteWorkspaces.rename(executionWorkspaceId, { path, newPath }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
357
362
  }
358
- return presentSemanticWorkResult(await coreOperations.rename({ workspaceId: executionWorkspaceId, path, newPath }, executionContext), target, hostScopeIdFor(extra._meta, extra.sessionId));
363
+ return presentSemanticWorkResult(await coreOperations.rename({ workspaceId: executionWorkspaceId, path, newPath }, executionContext), target, hostScopeIdFor(requestContext));
359
364
  });
360
365
  registerAppTool(server, toolNames.delete, {
361
366
  title: "Delete path",
@@ -389,19 +394,20 @@ export function registerFilesystemTools(options) {
389
394
  _meta: {},
390
395
  annotations: EDIT_TOOL_ANNOTATIONS,
391
396
  }, async ({ workspaceId, member, path, paths, recursive }, extra) => {
397
+ const requestContext = mcpHandlerRequestContext(extra);
392
398
  if ((path === undefined) === (paths === undefined)) {
393
399
  throw new Error("delete requires exactly one of path or paths.");
394
400
  }
395
401
  const target = resolveExecutionTarget(workspaceId, member);
396
402
  const executionWorkspaceId = target.executionWorkspaceId;
397
- const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
403
+ const executionContext = await prepareExecutionContext(target, requestContext);
398
404
  if (remoteWorkspaces.has(executionWorkspaceId)) {
399
- return presentSemanticWorkResult(await remoteWorkspaces.delete(executionWorkspaceId, { path, paths, recursive }, hostScopeIdFor(extra._meta, extra.sessionId)), target, hostScopeIdFor(extra._meta, extra.sessionId));
405
+ return presentSemanticWorkResult(await remoteWorkspaces.delete(executionWorkspaceId, { path, paths, recursive }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
400
406
  }
401
407
  if (path !== undefined) {
402
- return presentSemanticWorkResult(await coreOperations.delete({ workspaceId: executionWorkspaceId, path, recursive }, executionContext), target, hostScopeIdFor(extra._meta, extra.sessionId));
408
+ return presentSemanticWorkResult(await coreOperations.delete({ workspaceId: executionWorkspaceId, path, recursive }, executionContext), target, hostScopeIdFor(requestContext));
403
409
  }
404
- return presentSemanticWorkResult(await nativeBulkMutations.delete({ workspaceId: executionWorkspaceId, paths: paths, recursive }, executionContext), target, hostScopeIdFor(extra._meta, extra.sessionId));
410
+ return presentSemanticWorkResult(await nativeBulkMutations.delete({ workspaceId: executionWorkspaceId, paths: paths, recursive }, executionContext), target, hostScopeIdFor(requestContext));
405
411
  });
406
412
  if (config.toolMode === "codex") {
407
413
  registerAppTool(server, "apply_patch", {
@@ -428,15 +434,16 @@ export function registerFilesystemTools(options) {
428
434
  _meta: {},
429
435
  annotations: EDIT_TOOL_ANNOTATIONS,
430
436
  }, async ({ workspaceId, member, patch }, extra) => {
437
+ const requestContext = mcpHandlerRequestContext(extra);
431
438
  const target = resolveExecutionTarget(workspaceId, member);
432
439
  const executionWorkspaceId = target.executionWorkspaceId;
433
- const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
440
+ const executionContext = await prepareExecutionContext(target, requestContext);
434
441
  if (remoteWorkspaces.has(executionWorkspaceId)) {
435
- return presentSemanticWorkResult(await remoteWorkspaces.applyPatch(executionWorkspaceId, { patch }, hostScopeIdFor(extra._meta, extra.sessionId)), target, hostScopeIdFor(extra._meta, extra.sessionId));
442
+ return presentSemanticWorkResult(await remoteWorkspaces.applyPatch(executionWorkspaceId, { patch }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
436
443
  }
437
444
  const workspace = workspaces.getWorkspace(executionWorkspaceId);
438
- return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(extra._meta, extra.sessionId), activityRequestFor({ workspaceId: executionWorkspaceId, patch }, executionContext), {
439
- signal: extra.signal,
445
+ return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(requestContext), activityRequestFor({ workspaceId: executionWorkspaceId, patch }, executionContext), {
446
+ signal: requestContext.signal,
440
447
  tool: "apply_patch",
441
448
  invocation: workspaceHookInvocation(workspace),
442
449
  payload: { patchBytes: Buffer.byteLength(patch) },
@@ -456,7 +463,7 @@ export function registerFilesystemTools(options) {
456
463
  .map((file) => file.path);
457
464
  logToolCall(config, {
458
465
  tool: "apply_patch",
459
- ...workspaceLogContext(workspace, extra.sessionId),
466
+ ...workspaceLogContext(workspace, requestContext.transportSessionId),
460
467
  path: displayPath,
461
468
  success: true,
462
469
  durationMs: Math.round(performance.now() - startedAt),
@@ -483,9 +490,9 @@ export function registerFilesystemTools(options) {
483
490
  removals: applied.removals,
484
491
  files: applied.files,
485
492
  },
486
- }, codeIntelligence, workspace.root, diagnosticPaths, extra.signal);
493
+ }, codeIntelligence, workspace.root, diagnosticPaths, requestContext.signal);
487
494
  },
488
- }, activityRelationFor(executionContext)).then((result) => presentSemanticWorkResult(result, target, hostScopeIdFor(extra._meta, extra.sessionId)));
495
+ }, activityRelationFor(executionContext)).then((result) => presentSemanticWorkResult(result, target, hostScopeIdFor(requestContext)));
489
496
  });
490
497
  }
491
498
  }
@@ -20,7 +20,7 @@ export function createOperationRuntime(options) {
20
20
  read: async (input, context) => {
21
21
  const { workspaceId, ...readInput } = input;
22
22
  const workspace = workspaces.getWorkspace(workspaceId);
23
- return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context.requestMeta, context.sessionId), activityRequestFor(input, context), {
23
+ return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
24
24
  signal: context.signal,
25
25
  tool: toolNames.read,
26
26
  invocation: workspaceHookInvocation(workspace),
@@ -96,7 +96,7 @@ export function createOperationRuntime(options) {
96
96
  write: async (input, context) => {
97
97
  const { workspaceId, ...writeInput } = input;
98
98
  const workspace = workspaces.getWorkspace(workspaceId);
99
- return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context.requestMeta, context.sessionId), activityRequestFor(input, context), {
99
+ return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
100
100
  signal: context.signal,
101
101
  tool: toolNames.write,
102
102
  invocation: workspaceHookInvocation(workspace),
@@ -157,7 +157,7 @@ export function createOperationRuntime(options) {
157
157
  edit: async (input, context) => {
158
158
  const { workspaceId, ...editInput } = input;
159
159
  const workspace = workspaces.getWorkspace(workspaceId);
160
- return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context.requestMeta, context.sessionId), activityRequestFor(input, context), {
160
+ return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
161
161
  signal: context.signal,
162
162
  tool: toolNames.edit,
163
163
  invocation: workspaceHookInvocation(workspace),
@@ -219,7 +219,7 @@ export function createOperationRuntime(options) {
219
219
  rename: async (input, context) => {
220
220
  const { workspaceId, path, newPath } = input;
221
221
  const workspace = workspaces.getWorkspace(workspaceId);
222
- return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context.requestMeta, context.sessionId), activityRequestFor(input, context), {
222
+ return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
223
223
  signal: context.signal,
224
224
  tool: toolNames.rename,
225
225
  invocation: workspaceHookInvocation(workspace),
@@ -278,7 +278,7 @@ export function createOperationRuntime(options) {
278
278
  delete: async (input, context) => {
279
279
  const { workspaceId, path, recursive } = input;
280
280
  const workspace = workspaces.getWorkspace(workspaceId);
281
- return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context.requestMeta, context.sessionId), activityRequestFor(input, context), {
281
+ return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
282
282
  signal: context.signal,
283
283
  tool: toolNames.delete,
284
284
  invocation: workspaceHookInvocation(workspace),
@@ -362,7 +362,7 @@ export function createOperationRuntime(options) {
362
362
  maxOutputTokens,
363
363
  };
364
364
  let undeliveredProcessId;
365
- const activityResult = await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context.requestMeta, context.sessionId), surface, activityRequestFor(activityRequest, context), async (activityContext) => {
365
+ const activityResult = await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context), surface, activityRequestFor(activityRequest, context), async (activityContext) => {
366
366
  try {
367
367
  const result = await runToolWithHooks(hooks, {
368
368
  signal: context.signal,
@@ -488,7 +488,7 @@ export function createOperationRuntime(options) {
488
488
  }
489
489
  const workspace = workspaces.getWorkspace(workspaceId);
490
490
  let changedPaths = [];
491
- return runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context.requestMeta, context.sessionId), toolNames.capability, activityRequestFor(capabilityActivityAuditRequest(input), context), (activityContext) => runToolWithHooks(hooks, {
491
+ return runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context), toolNames.capability, activityRequestFor(capabilityActivityAuditRequest(input), context), (activityContext) => runToolWithHooks(hooks, {
492
492
  signal: context.signal,
493
493
  tool: toolNames.capability,
494
494
  invocation: workspaceHookInvocation(workspace),
@@ -1,10 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
3
- import { getOAuthProtectedResourceMetadataUrl } from "@modelcontextprotocol/sdk/server/auth/router.js";
4
- import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
5
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
6
- import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
7
- import { checkResourceAllowed, resourceUrlFromServerUrl } from "@modelcontextprotocol/sdk/shared/auth-utils.js";
2
+ import { checkResourceAllowed, createMcpHandler, isInitializeRequest, isLegacyRequest, resourceUrlFromServerUrl, } from "@modelcontextprotocol/server";
3
+ import { createMcpExpressApp, getOAuthProtectedResourceMetadataUrl, requireBearerAuth, } from "@modelcontextprotocol/express";
4
+ import { NodeStreamableHTTPServerTransport, toNodeHandler, toWebRequest, } from "@modelcontextprotocol/node";
8
5
  import express from "express";
9
6
  import { ActivityAuditStore } from "../../../activity/history/audit-store.js";
10
7
  import { BashOutputStore } from "../../../activity/history/bash-output-store.js";
@@ -79,6 +76,26 @@ export function createHttpServer(config, options, createMcpServer) {
79
76
  const subagentProviders = config.subagents
80
77
  ? getSubagentProviderAvailabilitySnapshot()
81
78
  : [];
79
+ const buildMcpServer = () => createMcpServer(config, workspaces, reviewCheckpoints, processSessions, subagentProviders, incomingArtifactAdapters, codeIntelligence, activityLifecycle, bashOutputStore, activityQueries, {
80
+ taskReminders: sharedTaskReminders,
81
+ remoteWorkspaces: sharedRemoteWorkspaces,
82
+ compositeWorkspaces: sharedCompositeWorkspaces,
83
+ });
84
+ const modernMcp = createMcpHandler(() => buildMcpServer(), {
85
+ legacy: "reject",
86
+ onerror: (error) => {
87
+ logEvent(config.logging, "error", "mcp_modern_handler_error", {
88
+ error: error.message,
89
+ });
90
+ },
91
+ });
92
+ const modernNodeHandler = toNodeHandler(modernMcp, {
93
+ onerror: (error) => {
94
+ logEvent(config.logging, "error", "mcp_modern_adapter_error", {
95
+ error: error.message,
96
+ });
97
+ },
98
+ });
82
99
  const logTransportCloseResults = (reason, results) => {
83
100
  let closedCount = 0;
84
101
  for (const result of results) {
@@ -219,15 +236,22 @@ export function createHttpServer(config, options, createMcpServer) {
219
236
  sendJsonRpcError(res, 401, -32001, "Unauthorized");
220
237
  return;
221
238
  }
222
- logEvent(config.logging, "debug", "mcp_request", {
223
- requestId,
224
- httpMethod: req.method,
225
- transportSessionIdPresent: Boolean(transportSessionId),
226
- transportSessionIdPrefix: transportSessionIdPrefix(transportSessionId),
227
- isInitialize: initializeRequest,
228
- ...mcpRequestDebugFields(req.body),
229
- });
230
239
  try {
240
+ const webRequest = await toWebRequest(req, req.body);
241
+ const legacyRequest = await isLegacyRequest(webRequest, req.body);
242
+ logEvent(config.logging, "debug", "mcp_request", {
243
+ requestId,
244
+ httpMethod: req.method,
245
+ protocolEra: legacyRequest ? "legacy" : "modern",
246
+ transportSessionIdPresent: Boolean(transportSessionId),
247
+ transportSessionIdPrefix: transportSessionIdPrefix(transportSessionId),
248
+ isInitialize: initializeRequest,
249
+ ...mcpRequestDebugFields(req.body),
250
+ });
251
+ if (!legacyRequest) {
252
+ await modernNodeHandler(req, res, req.body);
253
+ return;
254
+ }
231
255
  let transport;
232
256
  if (transportSessionId) {
233
257
  transport = transports.get(transportSessionId);
@@ -237,7 +261,7 @@ export function createHttpServer(config, options, createMcpServer) {
237
261
  }
238
262
  }
239
263
  else if (initializeRequest) {
240
- transport = new StreamableHTTPServerTransport({
264
+ transport = new NodeStreamableHTTPServerTransport({
241
265
  sessionIdGenerator: () => randomUUID(),
242
266
  onsessioninitialized: (newTransportSessionId) => {
243
267
  if (transport) {
@@ -261,11 +285,7 @@ export function createHttpServer(config, options, createMcpServer) {
261
285
  });
262
286
  }
263
287
  };
264
- const server = createMcpServer(config, workspaces, reviewCheckpoints, processSessions, subagentProviders, incomingArtifactAdapters, codeIntelligence, activityLifecycle, bashOutputStore, activityQueries, {
265
- taskReminders: sharedTaskReminders,
266
- remoteWorkspaces: sharedRemoteWorkspaces,
267
- compositeWorkspaces: sharedCompositeWorkspaces,
268
- });
288
+ const server = buildMcpServer();
269
289
  await server.connect(transport);
270
290
  }
271
291
  else {
@@ -294,6 +314,7 @@ export function createHttpServer(config, options, createMcpServer) {
294
314
  clearInterval(transportCleanupTimer);
295
315
  const results = await transports.closeAll();
296
316
  logTransportCloseResults("server_shutdown", results);
317
+ await modernMcp.close();
297
318
  await sharedRemoteWorkspaces.shutdown();
298
319
  processSessions.shutdown();
299
320
  await codeIntelligence.shutdown();
@@ -1,5 +1,5 @@
1
1
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
2
- import { openAiConversationScopeId } from "../../../request-meta.js";
2
+ import { mcpHandlerRequestContext } from "../../../request-context.js";
3
3
  import { formatPathForPrompt } from "../../../../workspaces/resources/skills.js";
4
4
  import { compositeCapabilityContext } from "../../core/capability-support.js";
5
5
  import { compositeWorkspaceLogContext, logToolCall, textBlock } from "../../core/tool-support.js";
@@ -7,14 +7,13 @@ import { openWorkspaceToolDefinition } from "./workspace-open-schema.js";
7
7
  import { presentLocalWorkspaceOpen, workspaceTaskUsageInstruction, } from "./workspace-open-presentation.js";
8
8
  export function registerOpenWorkspaceTool(options) {
9
9
  const { server } = options;
10
- registerAppTool(server, "open_workspace", openWorkspaceToolDefinition, (args, extra) => handleOpenWorkspace(options, args, extra));
10
+ registerAppTool(server, "open_workspace", openWorkspaceToolDefinition, (args, extra) => handleOpenWorkspace(options, args, mcpHandlerRequestContext(extra)));
11
11
  }
12
- async function handleOpenWorkspace(options, input, extra) {
13
- const { config, workspaces, remoteWorkspaces, compositeWorkspaces, workspaceTasks, processSessions, capabilityRegistry, compositeTaskGuides, loadCompositeMemberContext, rememberWorkspacePanelState, hostScopeIdFor, presentation, } = options;
12
+ async function handleOpenWorkspace(options, input, requestContext) {
13
+ const { config, workspaces, remoteWorkspaces, compositeWorkspaces, workspaceTasks, processSessions, capabilityRegistry, compositeTaskGuides, loadCompositeMemberContext, rememberWorkspacePanelState, hostScopeIdFor, contextDeliveryScopeIdFor, presentation, } = options;
14
14
  const { action = "open", memberAction, member, kind, name, memberName, path, relay, workspaceId, mode, baseRef, newWorktree, newWorkspace, context, root, status, state, staleOnly, offset, limit, } = input;
15
- const { _meta, sessionId } = extra;
16
15
  const startedAt = performance.now();
17
- const conversationScopeId = openAiConversationScopeId(_meta);
16
+ const conversationScopeId = contextDeliveryScopeIdFor(requestContext);
18
17
  const protectedWorkspaceIds = processSessions.activeWorkspaceIds();
19
18
  const inspectTaskSummary = (targetWorkspaceId) => {
20
19
  try {
@@ -469,7 +468,7 @@ async function handleOpenWorkspace(options, input, extra) {
469
468
  newWorktree !== undefined || newWorkspace !== undefined) {
470
469
  throw new Error("Resuming a relayed Workspace by workspaceId accepts context only.");
471
470
  }
472
- const resumed = await remoteWorkspaces.resumeWorkspace(workspaceId, context ?? "auto", hostScopeIdFor(_meta, sessionId));
471
+ const resumed = await remoteWorkspaces.resumeWorkspace(workspaceId, context ?? "auto", hostScopeIdFor(requestContext));
473
472
  rememberWorkspacePanelState(workspaceId, resumed);
474
473
  return resumed;
475
474
  }
@@ -483,7 +482,7 @@ async function handleOpenWorkspace(options, input, extra) {
483
482
  newWorktree,
484
483
  newWorkspace,
485
484
  context,
486
- }, hostScopeIdFor(_meta, sessionId));
485
+ }, hostScopeIdFor(requestContext));
487
486
  const relayedSkills = Array.isArray(opened.skills)
488
487
  ? opened.skills
489
488
  : [];
@@ -568,5 +567,10 @@ async function handleOpenWorkspace(options, input, extra) {
568
567
  rememberWorkspacePanelState(opened.workspaceId, response);
569
568
  return response;
570
569
  }
571
- return presentLocalWorkspaceOpen(presentation, input, { conversationScopeId, protectedWorkspaceIds, startedAt, sessionId });
570
+ return presentLocalWorkspaceOpen(presentation, input, {
571
+ conversationScopeId,
572
+ protectedWorkspaceIds,
573
+ startedAt,
574
+ sessionId: requestContext.transportSessionId,
575
+ });
572
576
  }
@@ -1,5 +1,6 @@
1
1
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
2
2
  import * as z from "zod/v4";
3
+ import { mcpHandlerRequestContext } from "../../../request-context.js";
3
4
  import { CapabilityError } from "../../core/capability-registry.js";
4
5
  import { attachHookReports, runToolWithHooks } from "../../../hooks/hooks.js";
5
6
  import { toolNames } from "../../../server-instructions.js";
@@ -36,8 +37,9 @@ export function registerWorkspaceAuxiliaryTools(options) {
36
37
  openWorldHint: false,
37
38
  },
38
39
  }, async ({ workspaceId, path }, extra) => {
40
+ const requestContext = mcpHandlerRequestContext(extra);
39
41
  if (remoteWorkspaces.has(workspaceId)) {
40
- return remoteWorkspaces.workspaceInstruction(workspaceId, path, hostScopeIdFor(extra._meta, extra.sessionId));
42
+ return remoteWorkspaces.workspaceInstruction(workspaceId, path, hostScopeIdFor(requestContext));
41
43
  }
42
44
  if (compositeWorkspaces.has(workspaceId)) {
43
45
  throw new Error("Composite Workspace instructions belong to a selected member; open that member context before viewing its instruction files.");
@@ -91,6 +93,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
91
93
  openWorldHint: true,
92
94
  },
93
95
  }, async ({ workspaceId, member, name, action, arguments: capabilityArguments, file }, extra) => {
96
+ const requestContext = mcpHandlerRequestContext(extra);
94
97
  if (name === "workspace.tasks" && compositeWorkspaces.has(workspaceId)) {
95
98
  if (member !== undefined) {
96
99
  throw new Error(`workspace.tasks belongs to Composite Workspace ${workspaceId} itself and does not accept member.`);
@@ -105,9 +108,9 @@ export function registerWorkspaceAuxiliaryTools(options) {
105
108
  if (action === "run") {
106
109
  const execution = await capabilityRegistry.run(name, capabilityArguments ?? {}, context, {
107
110
  nativeFile: file,
108
- signal: extra.signal,
109
- requestMeta: extra._meta,
110
- sessionId: extra.sessionId,
111
+ signal: requestContext.signal,
112
+ requestMeta: requestContext.requestMeta,
113
+ sessionId: requestContext.transportSessionId,
111
114
  });
112
115
  const result = {
113
116
  content: [textBlock(`Capability ${name} completed.\n${JSON.stringify(execution.value, null, 2)}`)],
@@ -146,7 +149,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
146
149
  return result;
147
150
  }
148
151
  catch (error) {
149
- if (extra.signal.aborted)
152
+ if (requestContext.signal.aborted)
150
153
  throw error;
151
154
  const capabilityError = error instanceof CapabilityError
152
155
  ? error
@@ -171,16 +174,16 @@ export function registerWorkspaceAuxiliaryTools(options) {
171
174
  }
172
175
  const target = resolveExecutionTarget(workspaceId, member);
173
176
  const executionWorkspaceId = target.executionWorkspaceId;
174
- const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
177
+ const executionContext = await prepareExecutionContext(target, requestContext);
175
178
  if (remoteWorkspaces.has(executionWorkspaceId)) {
176
179
  const response = await remoteWorkspaces.capability(executionWorkspaceId, {
177
180
  name,
178
181
  action,
179
182
  ...(capabilityArguments !== undefined ? { arguments: capabilityArguments } : {}),
180
183
  ...(file !== undefined ? { file } : {}),
181
- }, hostScopeIdFor(extra._meta, extra.sessionId));
184
+ }, hostScopeIdFor(requestContext));
182
185
  return action === "run" && name !== "workspace.tasks"
183
- ? presentSemanticWorkResult(response, target, hostScopeIdFor(extra._meta, extra.sessionId))
186
+ ? presentSemanticWorkResult(response, target, hostScopeIdFor(requestContext))
184
187
  : presentExecutionResult(response, target);
185
188
  }
186
189
  if (action === "run" && name === "batch.execute") {
@@ -189,9 +192,9 @@ export function registerWorkspaceAuxiliaryTools(options) {
189
192
  try {
190
193
  const execution = await capabilityRegistry.run(name, capabilityArguments ?? {}, capabilityContextFor(workspace), {
191
194
  nativeFile: file,
192
- signal: extra.signal,
193
- requestMeta: extra._meta,
194
- sessionId: extra.sessionId,
195
+ signal: requestContext.signal,
196
+ requestMeta: requestContext.requestMeta,
197
+ sessionId: requestContext.transportSessionId,
195
198
  });
196
199
  const result = {
197
200
  content: [textBlock(`Capability ${name} completed.\n${JSON.stringify(execution.value, null, 2)}`)],
@@ -199,16 +202,16 @@ export function registerWorkspaceAuxiliaryTools(options) {
199
202
  };
200
203
  logToolCall(config, {
201
204
  tool: toolNames.capability,
202
- ...workspaceLogContext(workspace, extra.sessionId),
205
+ ...workspaceLogContext(workspace, requestContext.transportSessionId),
203
206
  capability: name,
204
207
  action,
205
208
  success: true,
206
209
  durationMs: Math.round(performance.now() - startedAt),
207
210
  });
208
- return presentSemanticWorkResult(result, target, hostScopeIdFor(extra._meta, extra.sessionId));
211
+ return presentSemanticWorkResult(result, target, hostScopeIdFor(requestContext));
209
212
  }
210
213
  catch (error) {
211
- if (extra.signal.aborted)
214
+ if (requestContext.signal.aborted)
212
215
  throw error;
213
216
  const capabilityError = error instanceof CapabilityError
214
217
  ? error
@@ -224,7 +227,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
224
227
  };
225
228
  logFailedToolResponse(config, {
226
229
  tool: toolNames.capability,
227
- ...workspaceLogContext(workspace, extra.sessionId),
230
+ ...workspaceLogContext(workspace, requestContext.transportSessionId),
228
231
  capability: name,
229
232
  action,
230
233
  }, result.content, startedAt);
@@ -235,11 +238,11 @@ export function registerWorkspaceAuxiliaryTools(options) {
235
238
  const response = await coreOperations.capabilityRun({ workspaceId: executionWorkspaceId, name, arguments: capabilityArguments, file }, executionContext);
236
239
  return name === "workspace.tasks"
237
240
  ? presentExecutionResult(response, target)
238
- : presentSemanticWorkResult(response, target, hostScopeIdFor(extra._meta, extra.sessionId));
241
+ : presentSemanticWorkResult(response, target, hostScopeIdFor(requestContext));
239
242
  }
240
243
  const workspace = workspaces.getWorkspace(executionWorkspaceId);
241
- return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(extra._meta, extra.sessionId), activityRequestFor({ workspaceId: executionWorkspaceId, name, action, arguments: capabilityArguments, file }, executionContext), {
242
- signal: extra.signal,
244
+ return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(requestContext), activityRequestFor({ workspaceId: executionWorkspaceId, name, action, arguments: capabilityArguments, file }, executionContext), {
245
+ signal: requestContext.signal,
243
246
  tool: toolNames.capability,
244
247
  invocation: workspaceHookInvocation(workspace),
245
248
  payload: { name, action },
@@ -332,6 +335,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
332
335
  _meta: {},
333
336
  annotations: WRITE_TOOL_ANNOTATIONS,
334
337
  }, async ({ workspaceId, action = "close", commitMessage }, extra) => {
338
+ const requestContext = mcpHandlerRequestContext(extra);
335
339
  if (compositeWorkspaces.has(workspaceId)) {
336
340
  const startedAt = performance.now();
337
341
  if (commitMessage !== undefined) {
@@ -392,7 +396,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
392
396
  };
393
397
  }
394
398
  if (remoteWorkspaces.has(workspaceId)) {
395
- const response = await remoteWorkspaces.closeWorkspace(workspaceId, { action, ...(commitMessage !== undefined ? { commitMessage } : {}) }, hostScopeIdFor(extra._meta, extra.sessionId));
399
+ const response = await remoteWorkspaces.closeWorkspace(workspaceId, { action, ...(commitMessage !== undefined ? { commitMessage } : {}) }, hostScopeIdFor(requestContext));
396
400
  if (action === "delete") {
397
401
  activityQueries.deleteWorkspaceHistory(config.stateDir, workspaceId);
398
402
  }
@@ -409,7 +413,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
409
413
  throw new Error(`Workspace ${session.id} still owns a running process. Poll, interrupt, or wait for it before deleting this Workspace.`);
410
414
  }
411
415
  const response = await runToolWithHooks(hooks, {
412
- signal: extra.signal,
416
+ signal: requestContext.signal,
413
417
  tool: toolNames.closeWorkspace,
414
418
  invocation: {
415
419
  workspaceId: session.id,
@@ -428,7 +432,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
428
432
  const result = `Deleted ForgeRelay Workspace ${session.id}. Physical project files were not removed.`;
429
433
  logToolCall(config, {
430
434
  tool: toolNames.closeWorkspace,
431
- ...workspaceLogContext(session, extra.sessionId),
435
+ ...workspaceLogContext(session, requestContext.transportSessionId),
432
436
  action: "delete",
433
437
  path: session.root,
434
438
  success: true,
@@ -463,7 +467,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
463
467
  }
464
468
  const hookRoot = session.sourceRoot ?? session.root;
465
469
  const response = await runToolWithHooks(hooks, {
466
- signal: extra.signal,
470
+ signal: requestContext.signal,
467
471
  tool: toolNames.closeWorkspace,
468
472
  invocation: {
469
473
  workspaceId: session.id,
@@ -509,7 +513,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
509
513
  }
510
514
  const workspace = workspaces.getWorkspace(session.id);
511
515
  const response = await runToolWithHooks(hooks, {
512
- signal: extra.signal,
516
+ signal: requestContext.signal,
513
517
  tool: toolNames.closeWorkspace,
514
518
  invocation: workspaceHookInvocation(workspace),
515
519
  payload: { workspaceId: workspace.id, action, commitMessage, mode: workspace.mode },
@@ -558,7 +562,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
558
562
  ].join("\n");
559
563
  logToolCall(config, {
560
564
  tool: toolNames.closeWorkspace,
561
- ...workspaceLogContext(workspace, extra.sessionId),
565
+ ...workspaceLogContext(workspace, requestContext.transportSessionId),
562
566
  action,
563
567
  path: closed.sourceRoot,
564
568
  success: true,
@@ -610,7 +614,7 @@ export function registerWorkspaceAuxiliaryTools(options) {
610
614
  const result = `Closed checkout-backed Workspace ${checkoutWorkspaceId}; its ForgeRelay identity was preserved for later reopen. Physical project files were not removed.`;
611
615
  logToolCall(config, {
612
616
  tool: toolNames.closeWorkspace,
613
- ...workspaceLogContext(workspace, extra.sessionId),
617
+ ...workspaceLogContext(workspace, requestContext.transportSessionId),
614
618
  action: "close",
615
619
  path: workspace.root,
616
620
  success: true,