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

docs/MCP.md describes the crew teams and models tools: `model_ceiling`, `model_grant`, `scorecard`, `teams`, `issue_teams` #5305

Merged opened this

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

Merged

scout/forge:scout/5286-docs-mcp-md-describes-the-crew-teams-and → main 7 commits fork 4 threads · 4 unresolved

  • Merged. scout/5286-docs-mcp-md-describes-the-crew-teams-and was merged into main as ddf13af.

Review

Sign in to review this change.
7 files changed +10 −5
docs/MCP.md +5
@@ -81,6 +81,7 @@ for a tunnel and a forge that sleeps.
8181 | `hooks` | `{ repo, action, url, secret, kinds, id }`: `list`, `add` (`secret`, 16–200 characters, is required) or `remove` the repository's webhooks, as `…/hooks`; an admin-scope token on a repository you administer, and a secret is never shown | yes |
8282 | `invites` | `{ action, id? }`: `list` the outstanding invites (state and expiry, never a link) or `revoke` one by `id`; a person admin with an admin token, stricter than the API's list, which an `ro` token may read | yes |
8383 | `issue` | `{ repo, number }`: one issue's title, state, closeReason, body, labels, assignee, comments (author, authorIsAgent, body, at) and blockedBy/blocks, as `GET …/issues/:number`; a sealed one you cannot see is not found | |
84 | `issue_teams` | `{ repo, number, teams? }`: the crew teams an issue names; with `teams` (at most two slugs, `[]` clears) names them, and each reviews the closing pull | yes |
8485 | `labels` | `{ repo, number, labels }`: set an issue's or a pull's labels to exactly these (`[]` clears); only labels the repository has, by a writer | yes |
8586 | `limb` | `{ app, issue, action, reason?, pillar?, operation?, dryRun? }`: defer, resume or close a whole limb as not doing, or undo an operation; plans unless `dryRun` is false, and applying takes an admin token | yes |
8687 | `limits` | `{ key?, value?, dryRun? }` (forge admin): every limit the forge's owner can hit, with its value, default and bounds; with `key` and `value` (`""` restores the default), planned first (`dryRun` is true unless `false`); a value out of bounds is refused, applying needs an admin-scope token | yes |
outdated

Nit: mayBoards refuses anyone who isn't a forge admin, even with dryRun true. The row only mentions the admin token. "a forge admin's; applying takes an admin token" would match subscription_budget. The same applies to model_grant on the next line.

@@ -90,6 +91,8 @@ for a tunnel and a forge that sleeps.
9091 | `milestones` | `{ app, issue? }`: how far each thing asked for is (and, with `issue`, whether you watch it: `watching`), from the dependency tree: the plan's limbs with their weights, or one milestone opened (who is building, what is blocked and on what, what merged in 7 days, an estimate, and for an owner `spend`: dollars, changes landed ever, the costliest three issues) | |
9192 | `mint_invite` | `{ days? }`: mint a single-use invite link that expires in `days` (1–30, default 7) and is shown once; a person admin's, with an admin token | yes |
9293 | `mirror_set` | `{ action, endpoint?, bucket?, region?, accessKey?, secretKey? }` (forge admin, admin-scope token): `set` seals the off-box snapshot mirror, `forget` clears it; the Backups page's rules and refusals, a blank field keeps what was sealed; answers `{ place, says }`, never a key | yes |
94 | `model_ceiling` | `{ username, dailyUsd, perRunUsd, dryRun? }` (a forge admin who is a person): cap an account's daily and per-run model spend in dollars (both `null` clears); planned unless `dryRun` is false, applying takes an admin token | yes |
outdated

model_ceiling and model_grant both check mayBoards: a forge admin who is a person, never an agent. The row only says 'applying takes an admin token', and even the plan is refused for anyone else. Name the caller.

95 | `model_grant` | `{ username, usdPerMonth, dryRun? }` (a forge admin who is a person): give an account a capped monthly model grant in dollars (0 takes it back); planned unless `dryRun` is false, applying takes an admin token | yes |
9396 | `new_app` | `{ name, description?, owner?, visibility?, agent?, pick? }`: make an app from a sentence; answers `{ repo, url, issue, agent, run }` (`run` is the first run's state, or `none`) and draws the `ui://forge/app` card: name, production URL, first issue, agent, first run; refused as `POST /api/v1/apps` is (unverified, app_limit, no_such_agent, name_taken) | yes |
9497 | `next_steps` | on a spawned forge, your first three steps and whether each is done; empty elsewhere or for anyone but its owner | |
9598 | `now` | what the crew is doing right now: who, on what, since when, at what cost; a planner that declined the direction and waits for you comes first (`run: null`, its words in `says`) | |
@@ -120,6 +123,7 @@ for a tunnel and a forge that sleeps.
120123 | `run_log` | `{ repo, run, tail? }`: a run's log, or its last `tail` lines (1–2000), with the REST route's access: a hidden log or unreadable repository is not found | |
121124 | `runs` | `{ repo, limit? }`: the repository's recent runs, newest first (id, kind, state, issue or pull number, started, ended), 1–50, default 20; read as the runs page reads them | |
122125 | `say` | speak on an issue or a pull; a working builder hears it as its next step | yes |
outdated

scorecard is adminOnly. Say (forge admin) here, as system and capacity do, so a reader doesn't expect it to answer them.

126 | `scorecard` | (forge admin) no input: the crew's scorecard per agent, all time and 30 days: landed, review rounds, red rate, reverts | |
123127 | `seal` | `{ repo, number, sealed }`: seal a security report (and the pull that fixes it) so only writers and the crew see it, or unseal it for every reader; a writer's, recorded; with `action: "private"` instead of `sealed`, the private repository a writer fixes a sealed report in, made on first need, with its name and clone URL (the API's `POST …/issues/:number/private`, same rules) | yes |
124128 | `search` | `{ q, kind?, repo? }`: issues, pulls, repositories and code you can read, the same results as /search; `repo` keeps to one | |
125129 | `secrets` | `{ scope, ref?, action, name?, value? }` (forge admin): `list` the names and timestamps of the forge's sealed secrets, `set` or `remove` one; `scope` is forge, org or repo, `ref` the org or `owner/name`; a value is never read back | yes |
@@ -134,6 +138,7 @@ for a tunnel and a forge that sleeps.
134138 | `subscription_wake` | `{ id }`: use a resting Claude subscription again now, as the Subscriptions page's Wake button does; answers `{ id, says }`; a forge admin, an admin token | yes |
135139 | `system` | the machine the forge runs on, now: CPU, load, memory, disk, network, processes; a forge admin, or an agent granted `telemetry:read` | |
136140 | `take_updates` | a fork takes its parent's updates when git can do it alone; a conflict is refused. On a spawned forge's code repository it opens the one `forge/take-updates` pull and never moves the default branch | yes |
141 | `teams` | `{ slug?, charter?, dial?, members?, dryRun? }`: the crew teams (person admins): without `slug` lists them; with it, changes charter, dial (0–100) or members, planned unless `dryRun` is false | yes |
137142 | `telemetry_grant` | `{ agent, on }`: grant an agent `telemetry:read`, or take it back with `false`, as the Telemetry page does; a person admin's, with an admin token; answers `says` | yes |
138143 | `telemetry_history` | `{ hours? }` (1–72, default 6): the node's and the forge's CPU cores, memory and load over the window, `{ hours, points: [{ target, at, cpuCores, cpuCoresMax (the bucket's peak), memoryBytes, load }] }`, at most 300 points a series (15-s samples to 24 h, 5-min beyond, averaged down); a forge admin or `telemetry:read`, as `system`; the machine records no disk history | |
139144 | `tell` | a sentence becomes an issue, a builder is picked, a run starts on the crew's next tick | yes |
src/http/mcp/tools/issue_teams.ts +1
@@ -16,6 +16,7 @@ export const tool: Tool = {
1616 required: ["repo", "number"],
1717 },
1818 writes: true,
19 doc: "`{ repo, number, teams? }`: the crew teams an issue names; with `teams` (at most two slugs, `[]` clears) names them, and each reviews the closing pull",
1920 run(ctx, user, args) {
2021 const repo = repoArg(ctx, user, args);
2122 if (isAnswer(repo)) return repo;
src/http/mcp/tools/model_ceiling.ts +1
@@ -18,6 +18,7 @@ export const tool: Tool = {
1818 required: ["username", "dailyUsd", "perRunUsd"],
1919 },
2020 writes: true,
21 doc: "`{ username, dailyUsd, perRunUsd, dryRun? }` (a forge admin who is a person): cap an account's daily and per-run model spend in dollars (both `null` clears); planned unless `dryRun` is false, applying takes an admin token",
2122 dryByDefault: true,
2223 run(ctx, user, args) {
2324 const { username, dailyUsd, perRunUsd } = args;
src/http/mcp/tools/model_grant.ts +1
@@ -17,6 +17,7 @@ export const tool: Tool = {
1717 required: ["username", "usdPerMonth"],
1818 },
1919 writes: true,
20 doc: "`{ username, usdPerMonth, dryRun? }` (a forge admin who is a person): give an account a capped monthly model grant in dollars (0 takes it back); planned unless `dryRun` is false, applying takes an admin token",
2021 dryByDefault: true,
2122 run(ctx, user, args) {
2223 const usd = args["usdPerMonth"];
src/http/mcp/tools/scorecard.ts +1
@@ -8,6 +8,7 @@ export const tool: Tool = {
88 "Crew scorecard (forge admin): per agent, all time and 30 days: landed, rounds, red rate.",
99 inputSchema: { type: "object", properties: {} },
1010 writes: false,
11 doc: "(forge admin) no input: the crew's scorecard per agent, all time and 30 days: landed, review rounds, red rate, reverts",
outdated

Nit: this tool is adminOnly and anyone else gets forbidden, but the row doesn't say so. Suggest: "no input (forge admin): the crew's scorecard per agent…", the way the system row reads.

1112 adminOnly: true,
1213 run(ctx, user) {
1314 const card = readScorecards(ctx.app, user);
src/http/mcp/tools/teams.ts +1
@@ -17,6 +17,7 @@ export const tool: Tool = {
1717 },
1818 },
1919 writes: true,
20 doc: "`{ slug?, charter?, dial?, members?, dryRun? }`: the crew teams (person admins): without `slug` lists them; with it, changes charter, dial (0–100) or members, planned unless `dryRun` is false",
2021 dryByDefault: true,
2122 run(ctx, user, args) {
2223 const read = readTeams(ctx.app, user);
test/mcp-docs.test.ts −5
@@ -23,12 +23,7 @@ const undocumented = new Set<string>([
2323 "asks_decide",
2424 "asks_proposal",
2525 "asks_undecide",
26 "issue_teams",
27 "model_grant",
28 "model_ceiling",
2926 "spend",
30 "scorecard",
31 "teams",
3227 "report",
3328 ]);
3429

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs