@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.
Files changed (2) hide show
  1. package/package.json +9 -4
  2. 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.1.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.1.0",
12
- "@agent-delivery-harness/kernel": "0.1.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` and `submit-evidence`, at strict
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. Two of the CLI's seven commands are exposed. The rest
21
- * are not tools, and a call naming one is an unknown tool: what a tool call may
22
- * reach is the registry below, never the CLI's. Exposing less than the CLI is
23
- * within the contract; behaving differently about what is exposed is not.
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 ───────────────────────────────────────────────────