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

Proposal tokens through MCP and the terminal: mint, list and revoke, writer-only #2217

Merged opened this

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

Merged

MCP and the terminal can now mint, list and revoke proposal tokens, for writers only. I ran the new test file plus `proposal-token`, `mcp` and `tui-screens` (66 pass) and the type check, but not the whole suite. The forge runs that on push.

shipped production is serving it deploy b4d876b

opened this

MCP and the terminal can now mint, list and revoke proposal tokens, for writers only. I ran the new test file plus proposal-token, mcp and tui-screens (66 pass) and the type check, but not the whole suite. The forge runs that on push.

What changed

  • One action for every door. src/actions/proposal_tokens.ts now holds mint, list and revoke. The issue pointed at src/actions/proposals.ts and src/tty.ts, but neither fits. The first is the wave-proposal action, and the terminal is the TUI under src/tui/. So this is a new action file, and the POST …/proposal-tokens handler in src/http/api.ts now calls it instead of keeping its own copy of the rules. New list and delete queries are in src/core/proposal_token.ts.
  • MCP. A new proposal_tokens tool takes repo and a verb of mint, list or revoke. The secret comes back once, on mint.
  • Terminal. ctrl+k → Proposal tokens asks for owner/name. On the list, n mints (child name, then https origin) and shows the secret once on its own screen. x revokes the row under the cursor. The screen is src/tui/screens/proposal_tokens.ts.
  • Non-writers. All three doors refuse with the API's existing 404 words: "no such resource here, or it is not visible to you". Neither list nor revoke touches anything for them.
  • Tests. test/proposal-token-doors.test.ts covers the mint, list and revoke round trip on MCP and on the terminal, the non-writer refusal on both (compared against the API's own response), and bad input. I also added the tool to the tool-name list in test/mcp.test.ts.
  • README. Both doors are described in the Proposal tokens section, replacing the "API-only for now" line.

Left out

  • There is no list or revoke route in the REST API. The settings token list already shows these tokens as proposal:<child>.
  • List and revoke cover only tokens you minted, not a colleague's.
  • There is no web page for this (the issue only asked for the two doors).

Try it Over MCP: proposal_tokens {repo:"you/hello", verb:"mint", child:"kid", origin:"https://kid.example.com/"}.

In the terminal: ctrl+k, type "Proposal tokens", enter you/hello, then press n.

Closes #2148

Approved

Approved. This does what #2148 asked. Mint, list and revoke now sit in one action, src/actions/proposal_tokens.ts, and the API, the MCP tool and the terminal all call it. The API's own copy of the rules is gone.

Security, checked line by line:

  • Who you are comes from the authenticated bearer or the ssh session. The MCP tool is writes: true, so a read-only token is refused before run.
  • Every verb, list included, goes through mine(), which uses canWrite. A non-writer gets the API's 404 words at all three doors.
  • deleteProposalToken is limited to the actor's own token for that repository, so you cannot revoke a token on another repository by guessing its id.
  • The SQL is parameterised. list never returns the secret.
  • The API handler keeps requireScope and the byte-counted boundedBody.

Tests: the new file checks the round trip and the non-writer refusal through both MCP and the terminal. It also checks that the secret shown on screen verifies and that it is not shown again on the list. Locally at 3121b1b7: proposal-token-doors, proposal-token and mcp give 45 pass, 0 fail, and tsc --noEmit is clean.

I could not reach the preview or the screenshots from my sandbox, so this verdict rests on the code and the tests.

Two small points, neither blocking:

  • The terminal's x revokes with no confirmation.
  • The terminal mint cannot set childRepo, which the API and MCP can.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs