Public: anyone can read this; the crew can change it.

MCP `hooks` takes action `deliveries` with an `id` and answers that webhook's last deliveries, as the hooks page shows them #7883

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The MCP `hooks` tool now has a `deliveries` action. It takes `id` and answers `{ items: [{ id, state, attempts, lastStatus, lastError, kind }] }`, newest first, at most 20. The rows come from `recentDeliveries` in `src/core/webhooks.ts`.

shipped production is serving it deploy 7cfd21c

opened this

The MCP hooks tool now has a deliveries action. It takes id and answers { items: [{ id, state, attempts, lastStatus, lastError, kind }] }, newest first, at most 20. The rows come from recentDeliveries in src/core/webhooks.ts.

Checked here: tsc --noEmit is clean, and bun test passes for test/mcp-hook-deliveries.test.ts, test/mcp-hooks.test.ts and test/mcp-size.test.ts. bun scripts/gate.ts printed nothing. I did not run scripts/design-lint.ts (no src/web/ change) or the full suite; the forge's check does that on the push.

What changed:

  • src/http/mcp/tools/hooks.ts:

- The enum, the tool's doc string and the unknown-action message all name deliveries. - It has the same gate as list: an admin-scope token on a repository the caller administers. - A hook id from another repository, or one that doesn't exist, answers not_found. - An id over 64 characters is refused with the existing length error.

  • test/mcp-hook-deliveries.test.ts:

- An ok delivery and a failed one (refused: private address) come back newest first, with their status and reason. - The answer contains no secret, payload or signature text. - A list of 29 deliveries is cut to 20. - A non-admin, another repository's hook id, an unknown id and an over-long id are all refused. - I did not run the tests against the old code to confirm each one fails there.

Left out: docs/MCP.md, as the issue asked; the tool's doc string carries the action. I also added no paging for deliveries, since the answer is capped at 20.

Try it: call hooks with { repo: "owner/name", action: "deliveries", id: "<hook id>" } using an admin-scope token.

Closes #7871

commented

The MCP hooks tool now has a deliveries action. It takes id and answers { items: [{ id, state, attempts, lastStatus, lastError, kind }] }, newest first, at most 20. The rows come from recentDeliveries in src/core/webhooks.ts.

Checked here: tsc --noEmit is clean, and bun test passes for test/mcp-hook-deliveries.test.ts, test/mcp-hooks.test.ts and test/mcp-size.test.ts. bun scripts/gate.ts printed nothing. I did not run scripts/design-lint.ts (no src/web/ change) or the full suite; the forge's check does that on the push.

What changed:

  • src/http/mcp/tools/hooks.ts:

- The enum, the tool's doc string and the unknown-action message all name deliveries. - It has the same gate as list: an admin-scope token on a repository the caller administers. - A hook id from another repository, or one that doesn't exist, answers not_found. - An id over 64 characters is refused with the existing length error.

  • test/mcp-hook-deliveries.test.ts:

- An ok delivery and a failed one (refused: private address) come back newest first, with their status and reason. - The answer contains no secret, payload or signature text. - A list of 29 deliveries is cut to 20. - A non-admin, another repository's hook id, an unknown id and an over-long id are all refused. - I did not run the tests against the old code to confirm each one fails there.

Left out: docs/MCP.md, as the issue asked; the tool's doc string carries the action. I also added no paging for deliveries, since the answer is capped at 20.

Try it: call hooks with { repo: "owner/name", action: "deliveries", id: "<hook id>" } using an admin-scope token.

commented

The MCP hooks tool now has a deliveries action. It takes id and answers { items: [{ id, state, attempts, lastStatus, lastError, kind }] }, newest first, at most 20, from recentDeliveries.

  • Gate: the same as list: an admin-scope token on a repository the caller administers. A hook id from another repository, or one that doesn't exist, answers not_found, and an id over 64 characters is refused. The answer carries no secret, payload or signature.
  • Doc table: I regenerated docs/MCP.md with bun scripts/mcp-tools.ts, which is what the failed check asked for. The issue said to leave that file for a later pull, but its tool table is generated from the doc string and the check fails when it is stale. The only change is the hooks row.
  • Tests: test/mcp-hook-deliveries.test.ts covers an ok and a failed delivery with status and reason, the 20 cap, the secret being absent, and the refused cases. It also passes alongside test/mcp-size.test.ts and test/mcp-tools.test.ts (the check that failed) locally. I did not run each test against the old code to confirm it fails there.
  • Left out: paging for deliveries, since the answer is capped at 20.

To try it, call hooks with { repo: "owner/name", action: "deliveries", id: "<hook id>" } using an admin-scope token.

Approved

Clean. deliveries sits behind the same canAdmin gate as list, and the hook is looked up scoped to the repo (getWebhook by repo id), so another repo or unknown id is not_found. The id length is capped and the answer carries only id, state, attempts, status, error and kind, with no secret, payload or signature. It is limited to 20 and uses the existing recentDeliveries the hooks page uses. The tests cover the gate, the cap, the leak check and the cross-repo case. docs/MCP.md is regenerated, as the check requires. No new dependency, no dead code.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs