@agent-delivery-harness/mcp 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -4
- package/src/server.ts +88 -6
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-delivery-harness/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server exposing the delivery harness submission surface",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/kwam1na/agent-delivery-harness.git",
|
|
10
|
+
"directory": "packages/mcp"
|
|
11
|
+
},
|
|
7
12
|
"engines": {
|
|
8
|
-
"node": ">=22"
|
|
13
|
+
"node": ">=22.6.0"
|
|
9
14
|
},
|
|
10
15
|
"dependencies": {
|
|
11
|
-
"@agent-delivery-harness/cli": "0.
|
|
12
|
-
"@agent-delivery-harness/kernel": "0.
|
|
16
|
+
"@agent-delivery-harness/cli": "0.2.0",
|
|
17
|
+
"@agent-delivery-harness/kernel": "0.2.0"
|
|
13
18
|
},
|
|
14
19
|
"exports": {
|
|
15
20
|
".": "./src/index.ts"
|
package/src/server.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The MCP tool surface: `review-context
|
|
3
|
-
* parity with the CLI.
|
|
2
|
+
* The MCP tool surface: `review-context`, `submit-evidence`, and the read-only
|
|
3
|
+
* `managed` projection, at strict parity with the CLI.
|
|
4
4
|
*
|
|
5
5
|
* THIS IS A WRAPPER, NOT A SECOND IMPLEMENTATION. Every tool call is turned
|
|
6
6
|
* into the argv the CLI would have been invoked with and handed to
|
|
@@ -17,10 +17,18 @@
|
|
|
17
17
|
* supply-chain reasons. The protocol layer lives in `stdio.ts`; this module is
|
|
18
18
|
* transport-free so the parity suite drives the same code an agent reaches.
|
|
19
19
|
*
|
|
20
|
-
* A DELIBERATE SUBSET.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* A DELIBERATE SUBSET, IN TWO DIMENSIONS. Three of the CLI's eleven commands are
|
|
21
|
+
* exposed, and the third — `managed` — exposes only its read-only operations.
|
|
22
|
+
* The rest are not tools, and a call naming one is an unknown tool: what a tool
|
|
23
|
+
* call may reach is the registry below, never the CLI's. Exposing less than the
|
|
24
|
+
* CLI is within the contract; behaving differently about what is exposed is not.
|
|
25
|
+
*
|
|
26
|
+
* The second dimension is the one that matters most. A tool surface that could
|
|
27
|
+
* submit a stage result or run a sensor would be a second orchestrator sitting
|
|
28
|
+
* beside the host that already owns delegation and sequencing. So the operation
|
|
29
|
+
* enum below is read-class only, and the facade's contract-inventory sensor
|
|
30
|
+
* checks that against the product's own operation inventory rather than against
|
|
31
|
+
* this comment.
|
|
24
32
|
*
|
|
25
33
|
* WHAT AN AGENT NEVER GETS. No TTY, therefore no waiver prompt — an MCP session
|
|
26
34
|
* has no human at the other end to answer one, and a prompt nobody can answer
|
|
@@ -32,6 +40,7 @@ import {
|
|
|
32
40
|
EXIT_USAGE,
|
|
33
41
|
commandBlocker,
|
|
34
42
|
importHarnessConfig,
|
|
43
|
+
managedCommand,
|
|
35
44
|
reviewContextCommand,
|
|
36
45
|
runCliBoundary,
|
|
37
46
|
submitEvidenceCommand,
|
|
@@ -257,6 +266,27 @@ function usageBlocker(code: string, summary: string, details: string, remediatio
|
|
|
257
266
|
|
|
258
267
|
const TOOL_NAMES_SENTENCE = (): string => TOOLS.map((tool) => tool.name).join(", ");
|
|
259
268
|
|
|
269
|
+
/**
|
|
270
|
+
* The managed-delivery operations this server will translate, and the whole
|
|
271
|
+
* set of them.
|
|
272
|
+
*
|
|
273
|
+
* WHY ONLY THESE. The facade's boundary is that a tool surface inspects a
|
|
274
|
+
* delivery rather than orchestrating it: the product owns whether a checkpoint
|
|
275
|
+
* is valid and what evidence suffices, and the host owns how it delegates and
|
|
276
|
+
* sequences the work. A tool that could submit a stage result or run a sensor
|
|
277
|
+
* would be a second orchestrator sitting beside the host — so the CLI's control
|
|
278
|
+
* operations are simply not reachable from here, and the contract-inventory
|
|
279
|
+
* sensor checks that every name below is a `read`-class operation in the
|
|
280
|
+
* facade's own inventory.
|
|
281
|
+
*/
|
|
282
|
+
export const MANAGED_READ_OPERATIONS: readonly string[] = Object.freeze([
|
|
283
|
+
"status",
|
|
284
|
+
"next",
|
|
285
|
+
"explain-blocker",
|
|
286
|
+
"blockers",
|
|
287
|
+
"operations",
|
|
288
|
+
]);
|
|
289
|
+
|
|
260
290
|
/**
|
|
261
291
|
* Rejects members the tool does not define, for the same reason the manifest
|
|
262
292
|
* validator rejects them: a tolerated stranger is how a caller comes to believe
|
|
@@ -330,6 +360,58 @@ const TOOLS: readonly ToolDefinition[] = [
|
|
|
330
360
|
return { ok: true, argv: [submitEvidenceCommand.name, "--manifest", manifest] };
|
|
331
361
|
},
|
|
332
362
|
},
|
|
363
|
+
{
|
|
364
|
+
name: managedCommand.name,
|
|
365
|
+
description:
|
|
366
|
+
"Inspect the managed delivery: its typed status model, the next valid checkpoint, the current blocker and its remediation, the blocker inventory, and the facade's own operation contract. Read-only.",
|
|
367
|
+
inputSchema: {
|
|
368
|
+
type: "object",
|
|
369
|
+
properties: {
|
|
370
|
+
operation: {
|
|
371
|
+
type: "string",
|
|
372
|
+
enum: [...MANAGED_READ_OPERATIONS],
|
|
373
|
+
description: "Which read-only projection to return.",
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
required: ["operation"],
|
|
377
|
+
additionalProperties: false,
|
|
378
|
+
},
|
|
379
|
+
command: managedCommand,
|
|
380
|
+
translate(args) {
|
|
381
|
+
const unknown = rejectUnknownMembers(this, args, ["operation"]);
|
|
382
|
+
if (unknown !== null) return { ok: false, blocker: unknown };
|
|
383
|
+
const operation = args["operation"];
|
|
384
|
+
if (operation === undefined) return { ok: true, argv: [managedCommand.name] };
|
|
385
|
+
if (typeof operation !== "string") {
|
|
386
|
+
return {
|
|
387
|
+
ok: false,
|
|
388
|
+
blocker: usageBlocker(
|
|
389
|
+
"invalid_tool_argument",
|
|
390
|
+
"The managed tool's operation argument must be a string.",
|
|
391
|
+
`operation was ${operation === null ? "null" : typeof operation}, not a string.`,
|
|
392
|
+
`Call managed with operation set to one of: ${MANAGED_READ_OPERATIONS.join(", ")}.`,
|
|
393
|
+
),
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
// The enum is enforced here rather than delegated, because delegating it
|
|
397
|
+
// would hand a control operation straight to the command. What the CLI
|
|
398
|
+
// offers an operator at a terminal and what this server offers a model
|
|
399
|
+
// are deliberately different sets, and this is where that difference is
|
|
400
|
+
// mechanical rather than documentary.
|
|
401
|
+
if (!MANAGED_READ_OPERATIONS.includes(operation)) {
|
|
402
|
+
return {
|
|
403
|
+
ok: false,
|
|
404
|
+
blocker: usageBlocker(
|
|
405
|
+
"operation_not_offered",
|
|
406
|
+
"This server offers the managed delivery's read-only projections only.",
|
|
407
|
+
`Requested operation: ${operation}. Offered: ${MANAGED_READ_OPERATIONS.join(", ")}.`,
|
|
408
|
+
"Drive checkpoints from the bound worktree's CLI; this tool inspects the delivery, it does not orchestrate it.",
|
|
409
|
+
),
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
return { ok: true, argv: [managedCommand.name, operation] };
|
|
413
|
+
},
|
|
414
|
+
},
|
|
333
415
|
];
|
|
334
416
|
|
|
335
417
|
// ── The advertised surface ───────────────────────────────────────────────────
|