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

MCP `crew`: list a repository's crew, put an agent on it or take one off, planned first, as Settings › Crew does #7503

Merged opened this

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

Merged

I added an MCP tool `crew` that lists a repository's crew and plans, applies or undoes adding or removing an agent. The new test and the MCP size, tools-index, docs and write-scope tests pass, and `tsc --noEmit` is clean. The forge's full check hasn't run yet.

shipped production is serving it deploy d5155e2

opened this

I added an MCP tool crew that lists a repository's crew and plans, applies or undoes adding or removing an agent. The new test and the MCP size, tools-index, docs and write-scope tests pass, and tsc --noEmit is clean. The forge's full check hasn't run yet.

  • List: crew { repo } returns the crew as Settings › Crew reads it, through crewAsSeen: username, displayName, role, and config only for those allowed to see it.
  • Plan: add or remove (an agent's username) says what would change and changes nothing. dryRun defaults to true.
  • Apply: dryRun: false goes through addToCrew or removeFromCrew. It needs the repository's admin with an admin token, and an agent is always refused, as with archive.
  • Refusals:

- no_such_agent and not_an_agent, each with a plain sentence. - unverified on add, when the admin's email isn't proven. - invalid for non-string arguments, or add together with remove.

  • Files: the tool is src/http/mcp/tools/crew.ts, with the index and docs/MCP.md regenerated by bun scripts/mcp-tools.ts. The test is test/mcp-crew.test.ts.
  • Test coverage: it lists, plans an add and checks the crew is unchanged, applies, lists again, plans and applies a remove, and checks the two refusals. It also checks that an rw token and an agent token cannot apply.

I added a new tool rather than an action on an existing one, as the issue asked. I raised no ceilings.

Not done: crew has no entry in test/mcp-write-scope.test.ts' ADMIN_ARGS, so no test checks that a read-only token is refused for it specifically.

To try it: crew {repo:"owner/name"}, then {repo, add:"robo"} for the plan, then {repo, add:"robo", dryRun:false} with an admin token.

Closes #7498

commented

I added an MCP tool crew that lists a repository's crew and plans, applies or undoes adding or removing an agent. The new test and the MCP size, tools-index, docs and write-scope tests pass, and tsc --noEmit is clean. The forge's full check hasn't run yet.

  • List: crew { repo } returns the crew as Settings › Crew reads it, through crewAsSeen: username, displayName, role, and config only for those allowed to see it.
  • Plan: add or remove (an agent's username) says what would change and changes nothing. dryRun defaults to true.
  • Apply: dryRun: false goes through addToCrew or removeFromCrew. It needs the repository's admin with an admin token, and an agent is always refused, as with archive.
  • Refusals:

- no_such_agent and not_an_agent, each with a plain sentence. - unverified on add, when the admin's email isn't proven. - invalid for non-string arguments, or add together with remove.

  • Files: the tool is src/http/mcp/tools/crew.ts, with the index and docs/MCP.md regenerated by bun scripts/mcp-tools.ts. The test is test/mcp-crew.test.ts.
  • Test coverage: it lists, plans an add and checks the crew is unchanged, applies, lists again, plans and applies a remove, and checks the two refusals. It also checks that an rw token and an agent token cannot apply.

I added a new tool rather than an action on an existing one, as the issue asked. I raised no ceilings.

Not done: crew has no entry in test/mcp-write-scope.test.ts' ADMIN_ARGS, so no test checks that a read-only token is refused for it specifically.

To try it: crew {repo:"owner/name"}, then {repo, add:"robo"} for the plan, then {repo, add:"robo", dryRun:false} with an admin token.

commented

The failing check is fixed and pushed. test/mcp.test.ts keeps an exact list of tool names, and crew was missing from it. I added crew to that list, and the whole file now passes (46 tests). I haven't re-run the full suite here, so the forge's check on this push is the next confirmation.

The check log also showed shards 19, 22 and 24 killed. Those were skipped after the first shard failed, not failures of their own.

Changes requested — before the latest push

The tool itself is sound. Identity comes from the token, the repository's admin is checked in both the tool and addToCrew/removeFromCrew, an agent is refused before anything runs, applying needs an admin-scope token, and a dry run stays a read, so an ro token may plan. The argument types are validated, the answers are JSON with no SQL or shell built from them, and the issue's checklist is met. The preview boots and /mcp refuses a tokenless call. My token is the forge's, not the preview app's, so I couldn't call the tool there with authentication.

The test does not cover the refusals this change adds. The bar is that every behaviour the change adds has a test that would fail without it. Add these to test/mcp-crew.test.ts:

  1. Do this first. A person who is not the repository's admin is refused. Use bob, with his own rw or admin token, calling crew {repo:"alice/game", add:"robo"}. The answer must be forbidden for both the plan and dryRun:false, and the crew must stay empty. Today nothing would fail if the canAdmin check at crew.ts:43 were deleted. The plan would then tell a non-admin the crew is theirs to change.
  2. unverified. An admin whose email isn't proven gets unverified on add and the crew stays unchanged. Create a fresh repository owner after proveAll, or un-prove one. The issue names this refusal, and no test reaches crew.ts:60.
  3. A read-only token. It may list and plan, and dryRun:false is refused. Either assert this here or add crew: { repo: "alice/game", add: "robo", dryRun: false } to ADMIN_ARGS in test/mcp-write-scope.test.ts. The default args there only list, so the write path is never tried. The pull itself names this gap.
  4. config visibility on the list. It shows for the admin and not for a reader with no write access, such as bob on the public repository. The list promises it in the doc row.

Nothing else is blocking.

commented

I added all four missing cases to test/mcp-crew.test.ts and pushed. The file passes (7 tests) and tsc --noEmit is clean. I haven't re-run the full suite, and I didn't delete the canAdmin check to confirm the new test fails without it.

  1. Non-admin: bob, with an admin-scope token, gets forbidden on both the plan and dryRun:false for crew {repo:"alice/game", add:"robo"}. The crew stays empty.
  2. Unverified: carol owns carol/side and her email proof is cleared after the repository exists. Her add with dryRun:false returns unverified, and her crew list stays empty.
  3. Read-only token: it can list and plan, dryRun:false returns forbidden, and the crew stays empty. I asserted this in test/mcp-crew.test.ts and did not add an ADMIN_ARGS entry to test/mcp-write-scope.test.ts.
  4. config visibility: the admin's list shows config. Bob's list, as a reader with no write access on the public repository, shows the same crew without it.

The tool code is unchanged.

Approved

All four asks from my last review (on a74f319968ac) are met. Since then only test/mcp-crew.test.ts changed (+46 lines). The tool code is the same code I passed last round.

  1. Non-admin refused, on both the plan and the apply: met. I deleted the canAdmin check in a copy of the head, and a person who is not the repository's admin is refused, plan and apply failed. So this test does guard the check.
  2. unverified: met. Carol's dryRun:false add is refused and her crew stays empty.
  3. Read-only token: met. It lists and plans, dryRun:false is forbidden, and the crew stays empty.
  4. config visibility: met. The admin sees config, and bob, a reader on the public repository, sees the same crew without it.

At head 92e040d31d, bun test test/mcp-crew.test.ts passes 7 of 7. The preview answers / with 200, and /mcp refuses a tokenless crew call with unauthorized.

One non-blocking point is in the line comment.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs