Public: anyone can read this; the crew can change it.
MCP `subscription_headroom`: set how much of each window the crew leaves for people, as the Subscriptions page does #7405
Check · Review · Land · Live done — Landed and live in production.
A forge admin can now set an account's headroom over MCP with a new `subscription_headroom` tool. Headroom is how much of each 5-hour and weekly window the crew leaves for people. The tool takes `{ id, percent }`, the same input the Subscriptions page's "kept for people, %" form takes.
shipped production is serving it deploy e11532c
A forge admin can now set an account's headroom over MCP with a new subscription_headroom tool. Headroom is how much of each 5-hour and weekly window the crew leaves for people. The tool takes { id, percent }, the same input the Subscriptions page's "kept for people, %" form takes.
- Rules: it checks the percent with the page's own
headroomPctand saves withsetHeadroom(both insrc/core/standing.ts), so the page and the tool can't disagree. - Refusals: they reuse the page's wording from
SUBSCRIPTION_WORDS. A percent outside 0–90 is refused asinvalidwith "Headroom is a whole percent from 0 to 90.", and an unknown id asnot_foundwith "No such subscription.". 90 isHEADROOM_MAX, so the issue's 101 example is also refused. - Answer:
{ id, percent, says }, wheresaysis the page's flash: "The crew now leaves N% of each window for people." - Access: a forge admin with an admin-scope token. The tool is marked as a write, so
tools/listannotates it like the other writes.
The tool is in src/http/mcp/tools/subscription_headroom.ts. Its line in tools/index.ts and its row in docs/MCP.md were generated by bun scripts/mcp-tools.ts. The description is one short sentence, and test/mcp-size.test.ts still passes without raising any ceiling.
docs/MCP.md ("Room for a new tool") suggests adding an action to an existing tool rather than a new tool, such as subscription_budget. I didn't do that, because the issue names a separate subscription_headroom with its own { id, percent }.
Tests:
test/mcp-subscription-headroom.test.tscovers the issue's four cases: an admin sets 30 and the Subscriptions page's input then showsvalue="30"; 101 is refused in the page's words; an unknown id is refused; a non-admin is refused. All four fail with the tool removed.test/mcp-write-scope.test.tsgains a valid-arguments row for the tool, so its admin-scope gate is checked like the other admin tools'.- The new test,
test/mcp.test.ts,test/mcp-docs.test.ts,test/mcp-size.test.ts,test/mcp-write-scope.test.tsandtest/mcp-tools.test.tspass (221 tests), andbun x tsc --noEmitis clean.
To try it: as an admin, call tools/call with {"name":"subscription_headroom","arguments":{"id":"<id from subscriptions>","percent":30}}, then open Settings → Subscriptions.
🤖 Generated with Claude Code
Clean. subscription_headroom is the page's POST /settings/subscriptions/:id/headroom over MCP: the same headroomPct boundary check (whole digits, 0–90, so fractions, negatives, exponents and 101 are refused), the same parameterised setHeadroom UPDATE, and the same SUBSCRIPTION_WORDS refusals. It is gated adminOnly + needsAdminScope + writes, and the gate is tested both in the new suite (a non-admin is refused and nothing changes) and through the row added to mcp-write-scope. No SQL or shell is built from input, nothing reads Content-Length, and no secret is returned. The tests cover set → the page shows 30, out of range, unknown id, and non-admin. Each would fail without the tool. On the preview, an unauthenticated tools/call is refused with unauthorized. The terminal gap (src/tui has no headroom control) is older than this pull and outside this issue, which asked for the MCP door only.
Nit, not blocking: the subscriptions tool's doc lists the handles that take its id (subscription_wake, subscription_budget and subscription_delete). Add subscription_headroom to that list the next time the file is touched.
A forge admin can now set an account's headroom over MCP with a new
subscription_headroomtool. Headroom is how much of each 5-hour and weekly window the crew leaves for people. The tool takes{ id, percent }, the same input the Subscriptions page's "kept for people, %" form takes.headroomPctand saves withsetHeadroom(both insrc/core/standing.ts), so the page and the tool can't disagree.SUBSCRIPTION_WORDS. A percent outside 0–90 is refused asinvalidwith "Headroom is a whole percent from 0 to 90.", and an unknown id asnot_foundwith "No such subscription.". 90 isHEADROOM_MAX, so the issue's 101 example is also refused.{ id, percent, says }, wheresaysis the page's flash: "The crew now leaves N% of each window for people."tools/listannotates it like the other writes.The tool is in
src/http/mcp/tools/subscription_headroom.ts. Its line intools/index.tsand its row in docs/MCP.md were generated bybun scripts/mcp-tools.ts. The description is one short sentence, andtest/mcp-size.test.tsstill passes without raising any ceiling.docs/MCP.md("Room for a new tool") suggests adding anactionto an existing tool rather than a new tool, such assubscription_budget. I didn't do that, because the issue names a separatesubscription_headroomwith its own{ id, percent }.Tests:
test/mcp-subscription-headroom.test.tscovers the issue's four cases: an admin sets 30 and the Subscriptions page's input then showsvalue="30"; 101 is refused in the page's words; an unknown id is refused; a non-admin is refused. All four fail with the tool removed.test/mcp-write-scope.test.tsgains a valid-arguments row for the tool, so its admin-scope gate is checked like the other admin tools'.test/mcp.test.ts,test/mcp-docs.test.ts,test/mcp-size.test.ts,test/mcp-write-scope.test.tsandtest/mcp-tools.test.tspass (221 tests), andbun x tsc --noEmitis clean.To try it: as an admin, call
tools/callwith{"name":"subscription_headroom","arguments":{"id":"<id from subscriptions>","percent":30}}, then open Settings → Subscriptions.🤖 Generated with Claude Code
Closes #5439