@akira-tl/forgerelay 1.0.1 → 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.
- package/CHANGELOG.md +36 -0
- package/README.md +4 -0
- package/capabilities/host-integration/external-mcp/GUIDE.md +29 -0
- package/capabilities/lifecycle-hooks/GUIDE.md +13 -3
- package/dist/activity/runtime/mcp-query-tools.js +16 -10
- package/dist/cli/mcp/external-mcp.js +481 -0
- package/dist/cli/mcp/status.js +295 -0
- package/dist/cli.js +14 -1
- package/dist/lsp/test-support/server-fixture.js +1 -2
- package/dist/mcp/filesystem/filesystem-tools.js +7 -3
- package/dist/mcp/hooks/command-runner.js +12 -7
- package/dist/mcp/hooks/external-mcp-transform.js +224 -0
- package/dist/mcp/hooks/hook-cli.js +3 -0
- package/dist/mcp/hooks/hooks.js +49 -3
- package/dist/mcp/oauth/auth-protocol.js +375 -0
- package/dist/mcp/oauth/oauth-provider.js +11 -12
- package/dist/mcp/oauth/oauth-store.js +2 -2
- package/dist/mcp/oauth/router.js +2 -6
- package/dist/mcp/operations/batch/executor.js +1 -1
- package/dist/mcp/operations/bulk-read.js +7 -6
- package/dist/mcp/operations/external-mcp/external-mcp-oauth.js +387 -0
- package/dist/mcp/operations/external-mcp/external-mcp-runtime.js +59 -0
- package/dist/mcp/operations/external-mcp/external-mcp.js +382 -0
- package/dist/mcp/operations/media-content.js +28 -0
- package/dist/mcp/operations/native-bulk-mutations.js +1 -1
- package/dist/mcp/process/tools.js +19 -15
- package/dist/mcp/request-context.js +18 -0
- package/dist/mcp/request-meta.js +28 -3
- package/dist/mcp/server/core/activity-support.js +2 -2
- package/dist/mcp/server/core/capabilities/external-mcp.js +31 -0
- package/dist/mcp/server/core/capabilities.js +7 -0
- package/dist/mcp/server/core/capability-registry.js +2 -0
- package/dist/mcp/server/core/tool-support.js +29 -0
- package/dist/mcp/server/operations/runtime/filesystem-tools.js +91 -48
- package/dist/mcp/server/operations/runtime/operation-runtime.js +18 -11
- package/dist/mcp/server/transport/http-server.js +42 -21
- package/dist/mcp/server/workspace/runtime/workspace-open.js +13 -9
- package/dist/mcp/server/workspace/runtime/workspace-tools.js +29 -25
- package/dist/runtime/config/config.js +4 -0
- package/dist/runtime/config/external-mcp-auth-store.js +225 -0
- package/dist/runtime/config/external-mcp-config.js +146 -0
- package/dist/runtime/config/external-mcp-registry.js +165 -0
- package/dist/runtime/testing/server-fixture.js +10 -5
- package/dist/server.js +19 -10
- package/dist/subagents/sessions/mcp/audit.js +81 -0
- package/dist/ui/.vite/manifest.json +297 -298
- package/dist/ui/activity-panel-app.html +1 -1
- package/dist/ui/assets/activity-panel-app-Bw7ZFX2g.js +114 -0
- package/dist/ui/assets/angular-html-DeUNP12X.js +1 -0
- package/dist/ui/assets/{angular-ts-BearSZDb.js → angular-ts-B3v8FKi_.js} +1 -1
- package/dist/ui/assets/{apl-CYQtr-y6.js → apl-Bs3iQm4P.js} +1 -1
- package/dist/ui/assets/{astro-DDzqKIjK.js → astro-D6GHecBY.js} +1 -1
- package/dist/ui/assets/{blade-DkwEyHvQ.js → blade-BMNbVOHv.js} +1 -1
- package/dist/ui/assets/c-BquuA6bv.js +1 -0
- package/dist/ui/assets/{cobol-xBn5JxHE.js → cobol-BuZ6kfps.js} +1 -1
- package/dist/ui/assets/{coffee-BaXXvoJw.js → coffee-DgC5uBzL.js} +1 -1
- package/dist/ui/assets/cpp-BdvWqCaB.js +1 -0
- package/dist/ui/assets/{crystal-DjOpXVU1.js → crystal-0Q5qBvNI.js} +1 -1
- package/dist/ui/assets/css-Be_T8idh.js +1 -0
- package/dist/ui/assets/{edge-DNaRizoR.js → edge-DaGLdgh_.js} +1 -1
- package/dist/ui/assets/{elixir-CwBMwZmy.js → elixir-CMgiFIzB.js} +1 -1
- package/dist/ui/assets/{elm-gOUD2CW3.js → elm-B-ufMlMC.js} +1 -1
- package/dist/ui/assets/{erb-BcR-fjUp.js → erb-CaGiOZM-.js} +1 -1
- package/dist/ui/assets/{git-rebase-BAQPKHF6.js → git-rebase-CpwUWCzK.js} +1 -1
- package/dist/ui/assets/{glimmer-js-P_wOfSz_.js → glimmer-js-BRxccvnE.js} +1 -1
- package/dist/ui/assets/{glimmer-ts-B44aY1fZ.js → glimmer-ts-CgQbPzlT.js} +1 -1
- package/dist/ui/assets/glsl-D7JmHFr0.js +1 -0
- package/dist/ui/assets/graphql-C8n0eUBK.js +1 -0
- package/dist/ui/assets/{hack-ddU2k0nt.js → hack-lVN7KVQv.js} +1 -1
- package/dist/ui/assets/haml-h18lG0pS.js +1 -0
- package/dist/ui/assets/{handlebars-BpzaUpmz.js → handlebars-lRFjRPfj.js} +1 -1
- package/dist/ui/assets/heavy-payload-Cqx9MOkH.js +290 -0
- package/dist/ui/assets/html-DtILqTE1.js +1 -0
- package/dist/ui/assets/{html-derivative-B2beVdmA.js → html-derivative-CSTSmPup.js} +1 -1
- package/dist/ui/assets/{http-iEskZy8U.js → http-DNI8fsbY.js} +1 -1
- package/dist/ui/assets/{hurl-BuUsLSKv.js → hurl-DgRi60JG.js} +1 -1
- package/dist/ui/assets/java-CW9pZ5bh.js +1 -0
- package/dist/ui/assets/javascript-Cvg2UrWL.js +1 -0
- package/dist/ui/assets/{jinja-CRpkWwrH.js → jinja-CZw_S1FB.js} +1 -1
- package/dist/ui/assets/{jison-BYfSnuHj.js → jison-C56u_FZv.js} +1 -1
- package/dist/ui/assets/json-DW2UTv1q.js +1 -0
- package/dist/ui/assets/jsx-Zj5gobdD.js +1 -0
- package/dist/ui/assets/{julia-B8Rxy7vD.js → julia-Cvcrre-L.js} +1 -1
- package/dist/ui/assets/{just-DzhIWpFP.js → just-8CZ2u6Tj.js} +1 -1
- package/dist/ui/assets/{latex-CUNjUUL-.js → latex-D289AXWG.js} +1 -1
- package/dist/ui/assets/{liquid-hUg7nC61.js → liquid-CFEX3SkZ.js} +1 -1
- package/dist/ui/assets/lua-BKpJ0ybO.js +1 -0
- package/dist/ui/assets/{marko-CQmIkwMF.js → marko-D9maZ0a6.js} +1 -1
- package/dist/ui/assets/{mdc-CB-6dHYa.js → mdc-rM9l0qWR.js} +1 -1
- package/dist/ui/assets/{nginx-CQORo_Bt.js → nginx-C9w6p2C9.js} +1 -1
- package/dist/ui/assets/{nim-BNwBNzdn.js → nim-BRePHk0J.js} +1 -1
- package/dist/ui/assets/{perl-Cnz14fAJ.js → perl-CskTmiPQ.js} +1 -1
- package/dist/ui/assets/{php-YywDo63b.js → php-DCU_FvNI.js} +1 -1
- package/dist/ui/assets/{pug-BwbJp4cM.js → pug-XLaVxTvv.js} +1 -1
- package/dist/ui/assets/{qml-D2DY6dMH.js → qml-CaONKSl-.js} +1 -1
- package/dist/ui/assets/r-BCVR0ZE3.js +1 -0
- package/dist/ui/assets/{razor-pMTG7k41.js → razor-DDnGXxnU.js} +1 -1
- package/dist/ui/assets/regexp-DWGTYYVx.js +1 -0
- package/dist/ui/assets/{rst-CO_ndDm4.js → rst-Dz3GWvQm.js} +1 -1
- package/dist/ui/assets/{ruby-xzRn9gTh.js → ruby-DC3jGtMY.js} +1 -1
- package/dist/ui/assets/{sas-CBdtFKLA.js → sas-7mNpvsjZ.js} +1 -1
- package/dist/ui/assets/scss-uBsoCJVy.js +1 -0
- package/dist/ui/assets/shellscript-BCN9N_Jf.js +1 -0
- package/dist/ui/assets/{shellsession-BaZnm5rZ.js → shellsession-Hsw46VXV.js} +1 -1
- package/dist/ui/assets/{soy-IouG3xdB.js → soy-D6KV69HU.js} +1 -1
- package/dist/ui/assets/sql-CVzVQkJh.js +1 -0
- package/dist/ui/assets/{stata-dgbkIZHP.js → stata-BwUjXNhI.js} +1 -1
- package/dist/ui/assets/{surrealql-CBROnw_p.js → surrealql-CgloWqRa.js} +1 -1
- package/dist/ui/assets/{svelte-6r6BpX4-.js → svelte-DcC3n6IC.js} +1 -1
- package/dist/ui/assets/{templ-BKD_PsbL.js → templ-DOFfnWTJ.js} +1 -1
- package/dist/ui/assets/{tex-CKY1bwHb.js → tex-ln89VPaX.js} +1 -1
- package/dist/ui/assets/{ts-tags-BiYP5N_C.js → ts-tags-CWMzCstH.js} +1 -1
- package/dist/ui/assets/tsx-DgzfiGeK.js +1 -0
- package/dist/ui/assets/{twig-BTe1oPFW.js → twig-Bi2itZL9.js} +1 -1
- package/dist/ui/assets/typescript-CQ24f4zW.js +1 -0
- package/dist/ui/assets/{vue-CT0IiySh.js → vue-BS8jE5u6.js} +1 -1
- package/dist/ui/assets/{vue-html-B-tXcbat.js → vue-html-o38xqhyB.js} +1 -1
- package/dist/ui/assets/{vue-vine-C5ZyDCrs.js → vue-vine-D2NvKv50.js} +1 -1
- package/dist/ui/assets/xml-_44rx9_2.js +1 -0
- package/dist/ui/assets/{xsl-DvDSndNI.js → xsl-B5QWQPoi.js} +1 -1
- package/dist/ui/assets/yaml-CKL2pEWe.js +1 -0
- package/dist/workspaces/relay/auth/remote-auth.js +3 -5
- package/dist/workspaces/relay/result-support.js +19 -0
- package/dist/workspaces/relay/tests/test-support.js +10 -4
- package/dist/workspaces/relay/workspace-relay.js +20 -12
- package/docs/configuration.md +200 -2
- package/docs/debugging.md +8 -5
- package/docs/roadmap.md +64 -3
- package/docs/security.md +18 -0
- package/package.json +12 -4
- package/scripts/debug/accept/bootstrap.mjs +5 -0
- package/scripts/debug/accept/harness.mjs +10 -3
- package/scripts/debug/accept/media.mjs +335 -0
- package/scripts/debug/accept/modern-http.mjs +169 -0
- package/scripts/debug/accept/support.mjs +10 -6
- package/scripts/debug/accept.mjs +12 -1
- package/scripts/debug/relay-accept/support.mjs +40 -0
- package/scripts/debug/relay-accept.mjs +8 -9
- package/scripts/debug/runtime.mjs +4 -1
- package/scripts/debug/runtime.test.mjs +9 -0
- package/scripts/release/parity-sandbox.mjs +35 -0
- package/scripts/release/release-gate.test.mjs +42 -1
- package/scripts/release-parity.mjs +3 -22
- package/scripts/release-proof.mjs +24 -4
- package/scripts/release-proof.test.mjs +12 -4
- package/dist/ui/assets/activity-panel-app-XlqSanXT.js +0 -115
- package/dist/ui/assets/angular-html-tB9EchbM.js +0 -1
- package/dist/ui/assets/c-Dv-N5hjn.js +0 -1
- package/dist/ui/assets/cpp-C3unXX-3.js +0 -1
- package/dist/ui/assets/css-8Xr4kNNH.js +0 -1
- package/dist/ui/assets/glsl-BvCQg9MI.js +0 -1
- package/dist/ui/assets/graphql-C9S90gn_.js +0 -1
- package/dist/ui/assets/haml-Bb1w9rMG.js +0 -1
- package/dist/ui/assets/heavy-payload-CJKqi8Ac.js +0 -290
- package/dist/ui/assets/html-dUOs5pA9.js +0 -1
- package/dist/ui/assets/java-BFZCrORY.js +0 -1
- package/dist/ui/assets/javascript-DaIQ0Zqj.js +0 -1
- package/dist/ui/assets/json-BQC_Yp48.js +0 -1
- package/dist/ui/assets/jsx-Dd-CJRf9.js +0 -1
- package/dist/ui/assets/lua-BoZTiL2I.js +0 -1
- package/dist/ui/assets/r-B5nYsy-M.js +0 -1
- package/dist/ui/assets/regexp-oP0lbks_.js +0 -1
- package/dist/ui/assets/scss-CEqgKQNf.js +0 -1
- package/dist/ui/assets/shellscript-DzJJiWQC.js +0 -1
- package/dist/ui/assets/sql-DC2rdTzV.js +0 -1
- package/dist/ui/assets/tsx-D2OMiPNF.js +0 -1
- package/dist/ui/assets/typescript-BGIABksB.js +0 -1
- package/dist/ui/assets/xml-CfeBNlMP.js +0 -1
- package/dist/ui/assets/yaml-umbj2r1g.js +0 -1
|
@@ -40,6 +40,12 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
|
|
|
40
40
|
description: "Read-only semantic code navigation backed by external Language servers.",
|
|
41
41
|
whenToRead: "Read before using code.intelligence or configuring Language servers.",
|
|
42
42
|
},
|
|
43
|
+
{
|
|
44
|
+
name: "external-mcp",
|
|
45
|
+
directory: "host-integration/external-mcp",
|
|
46
|
+
description: "User-configured external MCP tool discovery and explicit forwarding through capability.",
|
|
47
|
+
whenToRead: "Read before discovering or calling a configured external MCP server.",
|
|
48
|
+
},
|
|
43
49
|
{
|
|
44
50
|
name: "workspace-tasks",
|
|
45
51
|
directory: "workspace/workspace-tasks",
|
|
@@ -110,6 +116,7 @@ export function buildCapabilityFingerprint(config, version, context = {}) {
|
|
|
110
116
|
if (config.subagents) {
|
|
111
117
|
capabilities.push("subagent.session");
|
|
112
118
|
}
|
|
119
|
+
capabilities.push("mcp.external");
|
|
113
120
|
if (config.artifactsEnabled && context.artifactDownloadSupported) {
|
|
114
121
|
capabilities.push("artifact.native-download");
|
|
115
122
|
}
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { MAX_CODE_INTELLIGENCE_RESULT_LIMIT, } from "../../../lsp/code-intelligence-types.js";
|
|
3
3
|
import { batchExecuteInputSchema, } from "../../operations/batch/types.js";
|
|
4
4
|
import { workspaceCheckpointInputSchema, } from "./capabilities/workspace-checkpoint.js";
|
|
5
|
+
import { externalMcpCapabilityDefinitions, } from "./capabilities/external-mcp.js";
|
|
5
6
|
export class CapabilityError extends Error {
|
|
6
7
|
code;
|
|
7
8
|
constructor(code, message) {
|
|
@@ -332,6 +333,7 @@ export function createCapabilityRegistry(dependencies) {
|
|
|
332
333
|
run: async (input, context, options) => dependencies.workspaceTasks.run(input, context, options),
|
|
333
334
|
}]
|
|
334
335
|
: []),
|
|
336
|
+
...externalMcpCapabilityDefinitions(dependencies.externalMcp),
|
|
335
337
|
...(dependencies.subagentSession
|
|
336
338
|
? [{
|
|
337
339
|
name: "subagent.session",
|
|
@@ -52,6 +52,35 @@ export function contentText(content) {
|
|
|
52
52
|
.map((item) => item.text)
|
|
53
53
|
.join("\n");
|
|
54
54
|
}
|
|
55
|
+
export function imageContentMetadata(content) {
|
|
56
|
+
const image = content.find((item) => item.type === "image");
|
|
57
|
+
return image
|
|
58
|
+
? {
|
|
59
|
+
type: "image",
|
|
60
|
+
mimeType: image.mimeType,
|
|
61
|
+
bytes: Buffer.byteLength(image.data, "base64"),
|
|
62
|
+
}
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
export function metadataSafeContent(content) {
|
|
66
|
+
return content.filter((item) => item.type === "text");
|
|
67
|
+
}
|
|
68
|
+
export function auditToolResultWithoutImageData(result) {
|
|
69
|
+
if (typeof result !== "object" || result === null)
|
|
70
|
+
return result;
|
|
71
|
+
const record = result;
|
|
72
|
+
const content = Array.isArray(record.content) ? record.content : undefined;
|
|
73
|
+
if (!content)
|
|
74
|
+
return result;
|
|
75
|
+
const media = imageContentMetadata(content);
|
|
76
|
+
if (!media)
|
|
77
|
+
return result;
|
|
78
|
+
return {
|
|
79
|
+
...record,
|
|
80
|
+
content: metadataSafeContent(content),
|
|
81
|
+
media,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
55
84
|
export function toolErrorPreview(content) {
|
|
56
85
|
const text = contentText(content).replace(/\s+/g, " ").trim();
|
|
57
86
|
if (!text)
|
|
@@ -3,15 +3,17 @@ 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";
|
|
9
|
+
import { createMediaBudget } from "../../../operations/media-content.js";
|
|
8
10
|
import { toolNames } from "../../../server-instructions.js";
|
|
9
11
|
import { executeBulkRead } from "../../../operations/bulk-read.js";
|
|
10
12
|
import { formatPathForPrompt } from "../../../../workspaces/resources/skills.js";
|
|
11
13
|
import { activityRelationFor, activityRequestFor, runActivityTool, runActivityToolWithHooks, } from "../../core/activity-support.js";
|
|
12
14
|
import { workspaceHookInvocation } from "../../core/capability-support.js";
|
|
13
15
|
import { resultOutputSchema, workspaceAgentsFileOutputSchema } from "../../core/schemas.js";
|
|
14
|
-
import { contentText, logToolCall, textBlock, toolResultAgentsFiles, toolResultContent, toolResultIsError, toolResultText, workspaceLogContext, } from "../../core/tool-support.js";
|
|
16
|
+
import { contentText, imageContentMetadata, logToolCall, textBlock, toolResultAgentsFiles, toolResultContent, toolResultIsError, toolResultText, workspaceLogContext, } from "../../core/tool-support.js";
|
|
15
17
|
import { appendAutomaticMutationDiagnostics } from "./mutation-diagnostics.js";
|
|
16
18
|
const WRITE_TOOL_ANNOTATIONS = {
|
|
17
19
|
readOnlyHint: false,
|
|
@@ -25,6 +27,11 @@ const EDIT_TOOL_ANNOTATIONS = {
|
|
|
25
27
|
idempotentHint: false,
|
|
26
28
|
openWorldHint: false,
|
|
27
29
|
};
|
|
30
|
+
const MEDIA_METADATA_OUTPUT_SCHEMA = z.object({
|
|
31
|
+
type: z.literal("image"),
|
|
32
|
+
mimeType: z.string(),
|
|
33
|
+
bytes: z.number().int().nonnegative(),
|
|
34
|
+
});
|
|
28
35
|
export function registerFilesystemTools(options) {
|
|
29
36
|
const { server, config, workspaces, compositeWorkspaces, compositeTaskGuides, remoteWorkspaces, coreOperations, nativeBulkMutations, activityLifecycle, codeIntelligence, hooks, toolDescriptions, resolveExecutionTarget, prepareExecutionContext, presentSemanticWorkResult, hostScopeIdFor, } = options;
|
|
30
37
|
registerAppTool(server, toolNames.read, {
|
|
@@ -66,10 +73,12 @@ export function registerFilesystemTools(options) {
|
|
|
66
73
|
},
|
|
67
74
|
outputSchema: resultOutputSchema({
|
|
68
75
|
agentsFiles: z.array(workspaceAgentsFileOutputSchema).optional(),
|
|
76
|
+
media: MEDIA_METADATA_OUTPUT_SCHEMA.optional(),
|
|
69
77
|
results: z.array(z.object({
|
|
70
78
|
path: z.string(),
|
|
71
79
|
status: z.enum(["done", "error"]),
|
|
72
80
|
result: z.string(),
|
|
81
|
+
media: MEDIA_METADATA_OUTPUT_SCHEMA.optional(),
|
|
73
82
|
})).optional(),
|
|
74
83
|
files: z.number().int().nonnegative().optional(),
|
|
75
84
|
failed: z.number().int().nonnegative().optional(),
|
|
@@ -77,6 +86,7 @@ export function registerFilesystemTools(options) {
|
|
|
77
86
|
_meta: {},
|
|
78
87
|
annotations: { readOnlyHint: true },
|
|
79
88
|
}, async ({ workspaceId, member, path, paths, offset, limit }, extra) => {
|
|
89
|
+
const requestContext = mcpHandlerRequestContext(extra);
|
|
80
90
|
if ((path === undefined) === (paths === undefined)) {
|
|
81
91
|
throw new Error("read requires exactly one of path or paths.");
|
|
82
92
|
}
|
|
@@ -90,23 +100,32 @@ export function registerFilesystemTools(options) {
|
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
const startedAt = performance.now();
|
|
93
|
-
const
|
|
94
|
-
|
|
103
|
+
const mediaBudget = createMediaBudget(config.mediaMaxBytes);
|
|
104
|
+
const execution = await executeBulkRead({
|
|
105
|
+
paths: requestedPaths,
|
|
106
|
+
signal: requestContext.signal,
|
|
107
|
+
run: (requestedPath) => readFileTool({ path: requestedPath, offset, limit }, {
|
|
95
108
|
cwd: process.cwd(),
|
|
96
109
|
root: config.allowedRoots[0] ?? process.cwd(),
|
|
97
110
|
readRoots: config.allowedRoots,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
mediaBudget,
|
|
112
|
+
}),
|
|
113
|
+
isError: (response) => response.isError === true,
|
|
114
|
+
resultText: (response) => contentText(response.content),
|
|
115
|
+
});
|
|
116
|
+
const children = execution.children;
|
|
117
|
+
const failed = execution.failed;
|
|
118
|
+
const content = children.flatMap((child) => {
|
|
119
|
+
const childContent = child.response
|
|
120
|
+
? child.response.content
|
|
121
|
+
: [textBlock(child.result)];
|
|
122
|
+
return requestedPaths.length === 1
|
|
123
|
+
? childContent
|
|
124
|
+
: [textBlock(`--- ${child.path} · ${child.status} ---`), ...childContent];
|
|
125
|
+
});
|
|
126
|
+
const singleMedia = requestedPaths.length === 1 && children[0]?.response
|
|
127
|
+
? imageContentMetadata(children[0].response.content)
|
|
128
|
+
: undefined;
|
|
110
129
|
logToolCall(config, {
|
|
111
130
|
tool: toolNames.read,
|
|
112
131
|
path: requestedPaths.length === 1 ? requestedPaths[0] : `${requestedPaths.length} unscoped files`,
|
|
@@ -118,9 +137,20 @@ export function registerFilesystemTools(options) {
|
|
|
118
137
|
...(failed > 0 ? { isError: true } : {}),
|
|
119
138
|
structuredContent: {
|
|
120
139
|
result: contentText(content),
|
|
140
|
+
...(singleMedia ? { media: singleMedia } : {}),
|
|
121
141
|
...(requestedPaths.length > 1
|
|
122
142
|
? {
|
|
123
|
-
results: children.map(({ path: childPath, status, result }) =>
|
|
143
|
+
results: children.map(({ path: childPath, status, result, response }) => {
|
|
144
|
+
const media = response
|
|
145
|
+
? imageContentMetadata(response.content)
|
|
146
|
+
: undefined;
|
|
147
|
+
return {
|
|
148
|
+
path: childPath,
|
|
149
|
+
status,
|
|
150
|
+
result,
|
|
151
|
+
...(media ? { media } : {}),
|
|
152
|
+
};
|
|
153
|
+
}),
|
|
124
154
|
files: children.length,
|
|
125
155
|
failed,
|
|
126
156
|
}
|
|
@@ -153,23 +183,25 @@ export function registerFilesystemTools(options) {
|
|
|
153
183
|
}
|
|
154
184
|
const target = resolveExecutionTarget(workspaceId, member);
|
|
155
185
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
156
|
-
const executionContext = await prepareExecutionContext(target,
|
|
186
|
+
const executionContext = await prepareExecutionContext(target, requestContext);
|
|
157
187
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
158
|
-
return presentSemanticWorkResult(await remoteWorkspaces.read(executionWorkspaceId, { path, paths, offset, limit }, hostScopeIdFor(
|
|
188
|
+
return presentSemanticWorkResult(await remoteWorkspaces.read(executionWorkspaceId, { path, paths, offset, limit }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
|
|
159
189
|
}
|
|
160
190
|
if (path !== undefined) {
|
|
161
|
-
return presentSemanticWorkResult(await coreOperations.read({ workspaceId: executionWorkspaceId, path, offset, limit }, executionContext), target, hostScopeIdFor(
|
|
191
|
+
return presentSemanticWorkResult(await coreOperations.read({ workspaceId: executionWorkspaceId, path, offset, limit }, executionContext), target, hostScopeIdFor(requestContext));
|
|
162
192
|
}
|
|
163
193
|
const workspace = workspaces.getWorkspace(executionWorkspaceId);
|
|
164
194
|
let response;
|
|
165
|
-
await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(
|
|
195
|
+
await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(requestContext), toolNames.read, activityRequestFor({ workspaceId: executionWorkspaceId, paths, offset, limit }, executionContext), async (parentContext) => {
|
|
196
|
+
const mediaBudget = createMediaBudget(config.mediaMaxBytes);
|
|
166
197
|
const execution = await executeBulkRead({
|
|
167
198
|
paths: paths,
|
|
168
|
-
signal:
|
|
199
|
+
signal: requestContext.signal,
|
|
169
200
|
run: (childPath) => coreOperations.read({ workspaceId: executionWorkspaceId, path: childPath, offset, limit }, {
|
|
170
201
|
...executionContext,
|
|
171
202
|
parentActivityId: parentContext.activityId,
|
|
172
203
|
turnId: parentContext.turnId,
|
|
204
|
+
mediaBudget,
|
|
173
205
|
}),
|
|
174
206
|
isError: toolResultIsError,
|
|
175
207
|
resultText: toolResultText,
|
|
@@ -191,11 +223,17 @@ export function registerFilesystemTools(options) {
|
|
|
191
223
|
content,
|
|
192
224
|
structuredContent: {
|
|
193
225
|
result: contentText(content),
|
|
194
|
-
results: execution.children.map(({ path: childPath, status, result }) =>
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
226
|
+
results: execution.children.map(({ path: childPath, status, result, response }) => {
|
|
227
|
+
const media = response
|
|
228
|
+
? imageContentMetadata(toolResultContent(response))
|
|
229
|
+
: undefined;
|
|
230
|
+
return {
|
|
231
|
+
path: childPath,
|
|
232
|
+
status,
|
|
233
|
+
result,
|
|
234
|
+
...(media ? { media } : {}),
|
|
235
|
+
};
|
|
236
|
+
}),
|
|
199
237
|
files: execution.children.length,
|
|
200
238
|
failed: execution.failed,
|
|
201
239
|
...(agentsFiles.length > 0 ? { agentsFiles } : {}),
|
|
@@ -211,7 +249,7 @@ export function registerFilesystemTools(options) {
|
|
|
211
249
|
: { type: "succeeded" }, activityRelationFor(executionContext));
|
|
212
250
|
if (!response)
|
|
213
251
|
throw new Error("Bulk Read completed without a response.");
|
|
214
|
-
return presentSemanticWorkResult(response, target, hostScopeIdFor(
|
|
252
|
+
return presentSemanticWorkResult(response, target, hostScopeIdFor(requestContext));
|
|
215
253
|
});
|
|
216
254
|
if (config.toolMode !== "codex") {
|
|
217
255
|
registerAppTool(server, toolNames.write, {
|
|
@@ -231,13 +269,14 @@ export function registerFilesystemTools(options) {
|
|
|
231
269
|
_meta: {},
|
|
232
270
|
annotations: WRITE_TOOL_ANNOTATIONS,
|
|
233
271
|
}, async ({ workspaceId, member, ...input }, extra) => {
|
|
272
|
+
const requestContext = mcpHandlerRequestContext(extra);
|
|
234
273
|
const target = resolveExecutionTarget(workspaceId, member);
|
|
235
274
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
236
|
-
const executionContext = await prepareExecutionContext(target,
|
|
275
|
+
const executionContext = await prepareExecutionContext(target, requestContext);
|
|
237
276
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
238
|
-
return presentSemanticWorkResult(await remoteWorkspaces.write(executionWorkspaceId, input, hostScopeIdFor(
|
|
277
|
+
return presentSemanticWorkResult(await remoteWorkspaces.write(executionWorkspaceId, input, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
|
|
239
278
|
}
|
|
240
|
-
return presentSemanticWorkResult(await coreOperations.write({ workspaceId: executionWorkspaceId, ...input }, executionContext), target, hostScopeIdFor(
|
|
279
|
+
return presentSemanticWorkResult(await coreOperations.write({ workspaceId: executionWorkspaceId, ...input }, executionContext), target, hostScopeIdFor(requestContext));
|
|
241
280
|
});
|
|
242
281
|
registerAppTool(server, toolNames.edit, {
|
|
243
282
|
title: "Edit file",
|
|
@@ -281,19 +320,20 @@ export function registerFilesystemTools(options) {
|
|
|
281
320
|
_meta: {},
|
|
282
321
|
annotations: EDIT_TOOL_ANNOTATIONS,
|
|
283
322
|
}, async ({ workspaceId, member, path, paths, edits }, extra) => {
|
|
323
|
+
const requestContext = mcpHandlerRequestContext(extra);
|
|
284
324
|
if ((path === undefined) === (paths === undefined)) {
|
|
285
325
|
throw new Error("edit requires exactly one of path or paths.");
|
|
286
326
|
}
|
|
287
327
|
const target = resolveExecutionTarget(workspaceId, member);
|
|
288
328
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
289
|
-
const executionContext = await prepareExecutionContext(target,
|
|
329
|
+
const executionContext = await prepareExecutionContext(target, requestContext);
|
|
290
330
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
291
|
-
return presentSemanticWorkResult(await remoteWorkspaces.edit(executionWorkspaceId, { path, paths, edits }, hostScopeIdFor(
|
|
331
|
+
return presentSemanticWorkResult(await remoteWorkspaces.edit(executionWorkspaceId, { path, paths, edits }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
|
|
292
332
|
}
|
|
293
333
|
if (path !== undefined) {
|
|
294
|
-
return presentSemanticWorkResult(await coreOperations.edit({ workspaceId: executionWorkspaceId, path, edits }, executionContext), target, hostScopeIdFor(
|
|
334
|
+
return presentSemanticWorkResult(await coreOperations.edit({ workspaceId: executionWorkspaceId, path, edits }, executionContext), target, hostScopeIdFor(requestContext));
|
|
295
335
|
}
|
|
296
|
-
return presentSemanticWorkResult(await nativeBulkMutations.edit({ workspaceId: executionWorkspaceId, paths: paths, edits }, executionContext), target, hostScopeIdFor(
|
|
336
|
+
return presentSemanticWorkResult(await nativeBulkMutations.edit({ workspaceId: executionWorkspaceId, paths: paths, edits }, executionContext), target, hostScopeIdFor(requestContext));
|
|
297
337
|
});
|
|
298
338
|
}
|
|
299
339
|
registerAppTool(server, toolNames.rename, {
|
|
@@ -313,13 +353,14 @@ export function registerFilesystemTools(options) {
|
|
|
313
353
|
_meta: {},
|
|
314
354
|
annotations: EDIT_TOOL_ANNOTATIONS,
|
|
315
355
|
}, async ({ workspaceId, member, path, newPath }, extra) => {
|
|
356
|
+
const requestContext = mcpHandlerRequestContext(extra);
|
|
316
357
|
const target = resolveExecutionTarget(workspaceId, member);
|
|
317
358
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
318
|
-
const executionContext = await prepareExecutionContext(target,
|
|
359
|
+
const executionContext = await prepareExecutionContext(target, requestContext);
|
|
319
360
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
320
|
-
return presentSemanticWorkResult(await remoteWorkspaces.rename(executionWorkspaceId, { path, newPath }, hostScopeIdFor(
|
|
361
|
+
return presentSemanticWorkResult(await remoteWorkspaces.rename(executionWorkspaceId, { path, newPath }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
|
|
321
362
|
}
|
|
322
|
-
return presentSemanticWorkResult(await coreOperations.rename({ workspaceId: executionWorkspaceId, path, newPath }, executionContext), target, hostScopeIdFor(
|
|
363
|
+
return presentSemanticWorkResult(await coreOperations.rename({ workspaceId: executionWorkspaceId, path, newPath }, executionContext), target, hostScopeIdFor(requestContext));
|
|
323
364
|
});
|
|
324
365
|
registerAppTool(server, toolNames.delete, {
|
|
325
366
|
title: "Delete path",
|
|
@@ -353,19 +394,20 @@ export function registerFilesystemTools(options) {
|
|
|
353
394
|
_meta: {},
|
|
354
395
|
annotations: EDIT_TOOL_ANNOTATIONS,
|
|
355
396
|
}, async ({ workspaceId, member, path, paths, recursive }, extra) => {
|
|
397
|
+
const requestContext = mcpHandlerRequestContext(extra);
|
|
356
398
|
if ((path === undefined) === (paths === undefined)) {
|
|
357
399
|
throw new Error("delete requires exactly one of path or paths.");
|
|
358
400
|
}
|
|
359
401
|
const target = resolveExecutionTarget(workspaceId, member);
|
|
360
402
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
361
|
-
const executionContext = await prepareExecutionContext(target,
|
|
403
|
+
const executionContext = await prepareExecutionContext(target, requestContext);
|
|
362
404
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
363
|
-
return presentSemanticWorkResult(await remoteWorkspaces.delete(executionWorkspaceId, { path, paths, recursive }, hostScopeIdFor(
|
|
405
|
+
return presentSemanticWorkResult(await remoteWorkspaces.delete(executionWorkspaceId, { path, paths, recursive }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
|
|
364
406
|
}
|
|
365
407
|
if (path !== undefined) {
|
|
366
|
-
return presentSemanticWorkResult(await coreOperations.delete({ workspaceId: executionWorkspaceId, path, recursive }, executionContext), target, hostScopeIdFor(
|
|
408
|
+
return presentSemanticWorkResult(await coreOperations.delete({ workspaceId: executionWorkspaceId, path, recursive }, executionContext), target, hostScopeIdFor(requestContext));
|
|
367
409
|
}
|
|
368
|
-
return presentSemanticWorkResult(await nativeBulkMutations.delete({ workspaceId: executionWorkspaceId, paths: paths, recursive }, executionContext), target, hostScopeIdFor(
|
|
410
|
+
return presentSemanticWorkResult(await nativeBulkMutations.delete({ workspaceId: executionWorkspaceId, paths: paths, recursive }, executionContext), target, hostScopeIdFor(requestContext));
|
|
369
411
|
});
|
|
370
412
|
if (config.toolMode === "codex") {
|
|
371
413
|
registerAppTool(server, "apply_patch", {
|
|
@@ -392,15 +434,16 @@ export function registerFilesystemTools(options) {
|
|
|
392
434
|
_meta: {},
|
|
393
435
|
annotations: EDIT_TOOL_ANNOTATIONS,
|
|
394
436
|
}, async ({ workspaceId, member, patch }, extra) => {
|
|
437
|
+
const requestContext = mcpHandlerRequestContext(extra);
|
|
395
438
|
const target = resolveExecutionTarget(workspaceId, member);
|
|
396
439
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
397
|
-
const executionContext = await prepareExecutionContext(target,
|
|
440
|
+
const executionContext = await prepareExecutionContext(target, requestContext);
|
|
398
441
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
399
|
-
return presentSemanticWorkResult(await remoteWorkspaces.applyPatch(executionWorkspaceId, { patch }, hostScopeIdFor(
|
|
442
|
+
return presentSemanticWorkResult(await remoteWorkspaces.applyPatch(executionWorkspaceId, { patch }, hostScopeIdFor(requestContext)), target, hostScopeIdFor(requestContext));
|
|
400
443
|
}
|
|
401
444
|
const workspace = workspaces.getWorkspace(executionWorkspaceId);
|
|
402
|
-
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(
|
|
403
|
-
signal:
|
|
445
|
+
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(requestContext), activityRequestFor({ workspaceId: executionWorkspaceId, patch }, executionContext), {
|
|
446
|
+
signal: requestContext.signal,
|
|
404
447
|
tool: "apply_patch",
|
|
405
448
|
invocation: workspaceHookInvocation(workspace),
|
|
406
449
|
payload: { patchBytes: Buffer.byteLength(patch) },
|
|
@@ -420,7 +463,7 @@ export function registerFilesystemTools(options) {
|
|
|
420
463
|
.map((file) => file.path);
|
|
421
464
|
logToolCall(config, {
|
|
422
465
|
tool: "apply_patch",
|
|
423
|
-
...workspaceLogContext(workspace,
|
|
466
|
+
...workspaceLogContext(workspace, requestContext.transportSessionId),
|
|
424
467
|
path: displayPath,
|
|
425
468
|
success: true,
|
|
426
469
|
durationMs: Math.round(performance.now() - startedAt),
|
|
@@ -447,9 +490,9 @@ export function registerFilesystemTools(options) {
|
|
|
447
490
|
removals: applied.removals,
|
|
448
491
|
files: applied.files,
|
|
449
492
|
},
|
|
450
|
-
}, codeIntelligence, workspace.root, diagnosticPaths,
|
|
493
|
+
}, codeIntelligence, workspace.root, diagnosticPaths, requestContext.signal);
|
|
451
494
|
},
|
|
452
|
-
}, activityRelationFor(executionContext)).then((result) => presentSemanticWorkResult(result, target, hostScopeIdFor(
|
|
495
|
+
}, activityRelationFor(executionContext)).then((result) => presentSemanticWorkResult(result, target, hostScopeIdFor(requestContext)));
|
|
453
496
|
});
|
|
454
497
|
}
|
|
455
498
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CapabilityError } from "../../core/capability-registry.js";
|
|
2
2
|
import { deletePath, renamePath } from "../../../filesystem/file-mutations.js";
|
|
3
3
|
import { editFileTool, readFileTool, writeFileTool } from "../../../filesystem/filesystem-tools.js";
|
|
4
|
+
import { createMediaBudget } from "../../../operations/media-content.js";
|
|
4
5
|
import { runToolWithHooks } from "../../../hooks/hooks.js";
|
|
5
6
|
import { toolNames } from "../../../server-instructions.js";
|
|
6
7
|
import { BatchExecutor } from "../../../operations/batch/executor.js";
|
|
@@ -11,7 +12,7 @@ import { markReturnedOutput, processActivityOutcome, processToolResponse, } from
|
|
|
11
12
|
import { capabilityActivityAuditRequest, capabilityActivityAuditResult } from "../../../../subagents/sessions/mcp/audit.js";
|
|
12
13
|
import { activityRelationFor, activityRequestFor, runActivityTool, runActivityToolWithHooks, standardActivityOutcome, } from "../../core/activity-support.js";
|
|
13
14
|
import { capabilityContextFor, managedWorktreeRecoveryCapabilityContext, workspaceHookInvocation, } from "../../core/capability-support.js";
|
|
14
|
-
import { assertWorkspaceInstructionsLoadedBeforeSideEffect, contentLineCount, contentText, countDiffStats, formatDiscoveredWorkspaceInstructions, logFailedToolResponse, logToolCall, newFilePatch, textBlock, textSummary, toolResultContent, toolResultIsError, toolResultText, workspaceLogContext, } from "../../core/tool-support.js";
|
|
15
|
+
import { assertWorkspaceInstructionsLoadedBeforeSideEffect, auditToolResultWithoutImageData, contentLineCount, contentText, countDiffStats, formatDiscoveredWorkspaceInstructions, imageContentMetadata, logFailedToolResponse, logToolCall, metadataSafeContent, newFilePatch, textBlock, textSummary, toolResultContent, toolResultIsError, toolResultText, workspaceLogContext, } from "../../core/tool-support.js";
|
|
15
16
|
import { appendAutomaticMutationDiagnostics } from "./mutation-diagnostics.js";
|
|
16
17
|
export function createOperationRuntime(options) {
|
|
17
18
|
const { config, workspaces, activityLifecycle, hooks, processSessions, bashOutputStore, capabilityRegistry, codeIntelligence, hostScopeIdFor, } = options;
|
|
@@ -19,7 +20,7 @@ export function createOperationRuntime(options) {
|
|
|
19
20
|
read: async (input, context) => {
|
|
20
21
|
const { workspaceId, ...readInput } = input;
|
|
21
22
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
22
|
-
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context
|
|
23
|
+
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
|
|
23
24
|
signal: context.signal,
|
|
24
25
|
tool: toolNames.read,
|
|
25
26
|
invocation: workspaceHookInvocation(workspace),
|
|
@@ -33,6 +34,7 @@ export function createOperationRuntime(options) {
|
|
|
33
34
|
cwd: workspace.root,
|
|
34
35
|
root: workspace.root,
|
|
35
36
|
readRoots: readPath.readRoots,
|
|
37
|
+
mediaBudget: context.mediaBudget ?? createMediaBudget(config.mediaMaxBytes),
|
|
36
38
|
});
|
|
37
39
|
if (response.isError) {
|
|
38
40
|
logFailedToolResponse(config, {
|
|
@@ -49,10 +51,12 @@ export function createOperationRuntime(options) {
|
|
|
49
51
|
const content = discoveredInstructionContent
|
|
50
52
|
? [discoveredInstructionContent, ...response.content]
|
|
51
53
|
: response.content;
|
|
54
|
+
const media = imageContentMetadata(response.content);
|
|
52
55
|
const summary = {
|
|
53
56
|
...textSummary(response.content),
|
|
54
57
|
offset: readInput.offset ?? 1,
|
|
55
58
|
limited: readInput.limit !== undefined,
|
|
59
|
+
...(media ? { media } : {}),
|
|
56
60
|
};
|
|
57
61
|
logToolCall(config, {
|
|
58
62
|
tool: toolNames.read,
|
|
@@ -70,11 +74,12 @@ export function createOperationRuntime(options) {
|
|
|
70
74
|
workspaceId,
|
|
71
75
|
path: readInput.path,
|
|
72
76
|
summary,
|
|
73
|
-
payload: { content: response.content },
|
|
77
|
+
payload: { content: metadataSafeContent(response.content) },
|
|
74
78
|
},
|
|
75
79
|
},
|
|
76
80
|
structuredContent: {
|
|
77
81
|
result: contentText(content),
|
|
82
|
+
...(media ? { media } : {}),
|
|
78
83
|
...(discoveredInstructions.length > 0
|
|
79
84
|
? {
|
|
80
85
|
agentsFiles: discoveredInstructions.map((file) => ({
|
|
@@ -86,12 +91,12 @@ export function createOperationRuntime(options) {
|
|
|
86
91
|
},
|
|
87
92
|
};
|
|
88
93
|
},
|
|
89
|
-
}, activityRelationFor(context));
|
|
94
|
+
}, activityRelationFor(context), auditToolResultWithoutImageData);
|
|
90
95
|
},
|
|
91
96
|
write: async (input, context) => {
|
|
92
97
|
const { workspaceId, ...writeInput } = input;
|
|
93
98
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
94
|
-
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context
|
|
99
|
+
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
|
|
95
100
|
signal: context.signal,
|
|
96
101
|
tool: toolNames.write,
|
|
97
102
|
invocation: workspaceHookInvocation(workspace),
|
|
@@ -152,7 +157,7 @@ export function createOperationRuntime(options) {
|
|
|
152
157
|
edit: async (input, context) => {
|
|
153
158
|
const { workspaceId, ...editInput } = input;
|
|
154
159
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
155
|
-
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context
|
|
160
|
+
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
|
|
156
161
|
signal: context.signal,
|
|
157
162
|
tool: toolNames.edit,
|
|
158
163
|
invocation: workspaceHookInvocation(workspace),
|
|
@@ -214,7 +219,7 @@ export function createOperationRuntime(options) {
|
|
|
214
219
|
rename: async (input, context) => {
|
|
215
220
|
const { workspaceId, path, newPath } = input;
|
|
216
221
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
217
|
-
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context
|
|
222
|
+
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
|
|
218
223
|
signal: context.signal,
|
|
219
224
|
tool: toolNames.rename,
|
|
220
225
|
invocation: workspaceHookInvocation(workspace),
|
|
@@ -273,7 +278,7 @@ export function createOperationRuntime(options) {
|
|
|
273
278
|
delete: async (input, context) => {
|
|
274
279
|
const { workspaceId, path, recursive } = input;
|
|
275
280
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
276
|
-
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context
|
|
281
|
+
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(context), activityRequestFor(input, context), {
|
|
277
282
|
signal: context.signal,
|
|
278
283
|
tool: toolNames.delete,
|
|
279
284
|
invocation: workspaceHookInvocation(workspace),
|
|
@@ -357,7 +362,7 @@ export function createOperationRuntime(options) {
|
|
|
357
362
|
maxOutputTokens,
|
|
358
363
|
};
|
|
359
364
|
let undeliveredProcessId;
|
|
360
|
-
const activityResult = await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context
|
|
365
|
+
const activityResult = await runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context), surface, activityRequestFor(activityRequest, context), async (activityContext) => {
|
|
361
366
|
try {
|
|
362
367
|
const result = await runToolWithHooks(hooks, {
|
|
363
368
|
signal: context.signal,
|
|
@@ -483,7 +488,7 @@ export function createOperationRuntime(options) {
|
|
|
483
488
|
}
|
|
484
489
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
485
490
|
let changedPaths = [];
|
|
486
|
-
return runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context
|
|
491
|
+
return runActivityTool(activityLifecycle, workspace, hostScopeIdFor(context), toolNames.capability, activityRequestFor(capabilityActivityAuditRequest(input), context), (activityContext) => runToolWithHooks(hooks, {
|
|
487
492
|
signal: context.signal,
|
|
488
493
|
tool: toolNames.capability,
|
|
489
494
|
invocation: workspaceHookInvocation(workspace),
|
|
@@ -503,8 +508,10 @@ export function createOperationRuntime(options) {
|
|
|
503
508
|
activityId: activityContext.activityId,
|
|
504
509
|
});
|
|
505
510
|
changedPaths = execution.changedPaths ?? [];
|
|
511
|
+
const transientContent = execution.content;
|
|
506
512
|
const result = {
|
|
507
|
-
content:
|
|
513
|
+
content: transientContent
|
|
514
|
+
?? [textBlock(`Capability ${name} completed.\n${JSON.stringify(execution.value, null, 2)}`)],
|
|
508
515
|
...(execution.card
|
|
509
516
|
? {
|
|
510
517
|
_meta: {
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import { getOAuthProtectedResourceMetadataUrl } from "@modelcontextprotocol/
|
|
4
|
-
import {
|
|
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";
|
|
@@ -59,7 +56,7 @@ export function createHttpServer(config, options, createMcpServer) {
|
|
|
59
56
|
});
|
|
60
57
|
const workspaceStore = createWorkspaceStore(config.stateDir);
|
|
61
58
|
const workspaces = new WorkspaceRegistry(config, workspaceStore);
|
|
62
|
-
const sharedRemoteWorkspaces = new RemoteWorkspaceRelay(config.configDir, config.stateDir);
|
|
59
|
+
const sharedRemoteWorkspaces = new RemoteWorkspaceRelay(config.configDir, config.stateDir, config.mediaMaxBytes);
|
|
63
60
|
const sharedCompositeWorkspaces = new CompositeWorkspaceRegistry(config.stateDir);
|
|
64
61
|
const sharedWorkspaceTasks = new WorkspaceTaskStore(config.stateDir);
|
|
65
62
|
const sharedTaskReminders = new WorkspaceTaskReminderTracker(config.taskReminderInterval, sharedWorkspaceTasks);
|
|
@@ -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
|
|
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 =
|
|
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();
|