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

MCP `egress_grants`: list, grant and revoke an app's private destinations, with the same rules as the page #5659

Merged opened this

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

Merged

This adds an `egress_grants` MCP tool that lists an app's asked-for private destinations and their grants, and grants or revokes one. It goes through the same action as the settings page.

shipped production is serving it deploy da65c36

opened this

This adds an egress_grants MCP tool that lists an app's asked-for private destinations and their grants, and grants or revokes one. It goes through the same action as the settings page.

  • Tool: src/http/mcp.ts registers egress_grants with list, grant and revoke. It reuses the page's action, so the words and refusals match the page and the API. The forbidden words are shared rather than copied.
  • Refusal: a non-admin who tries to grant gets the same message the API gives. A test pins this.
  • Tests: test/mcp.test.ts covers list, grant, revoke and the refusal. I did not add a test on the tools/list size, because the size limit it would check was invented, not one the repo sets. bun test test/mcp.test.ts passes (32 tests) and bun x tsc --noEmit is clean. I did not run the full suite; the forge's check does that.
  • Docs: docs/MCP.md documents the tool.
  • Also touched: src/http/respond.ts changed by two lines to share the forbidden words.
  • Left alone: src/tui/, as the issue asked.
  • Since last run: nothing new on the issue, and the branch had no changes to make. It was already pushed, so this run pushed nothing.

To try it, call egress_grants over MCP as a site admin, then as a non-admin to see the refusal.

Closes #3434

commented

This adds an egress_grants MCP tool that lists an app's asked-for private destinations and their grants, and grants or revokes one. It goes through the same action as the settings page.

  • Tool: src/http/mcp.ts registers egress_grants with list, grant and revoke. It reuses the page's action, so the words and refusals match the page and the API. The forbidden words are shared rather than copied.
  • Refusal: a non-admin who tries to grant gets the same message the API gives. A test pins this.
  • Tests: test/mcp.test.ts covers list, grant, revoke and the refusal. I did not add a test on the tools/list size, because the size limit it would check was invented, not one the repo sets. bun test test/mcp.test.ts passes (32 tests) and bun x tsc --noEmit is clean. I did not run the full suite; the forge's check does that.
  • Docs: docs/MCP.md documents the tool.
  • Also touched: src/http/respond.ts changed by two lines to share the forbidden words.
  • Left alone: src/tui/, as the issue asked.
  • Since last run: nothing new on the issue, and the branch had no changes to make. It was already pushed, so this run pushed nothing.

To try it, call egress_grants over MCP as a site admin, then as a non-admin to see the refusal.

commented

The tools/list size test was the real failure. Adding egress_grants pushed the list to 37,046 bytes, over the test's 36,400-byte cap on argument descriptions. I fixed it by trimming words, not by raising the cap, since the test's own comment says raising it is how the lane went red.

  • Trim: egress_grants has a shorter description and no maxLength on destination. I also shortened about a dozen other tool and argument descriptions, for example assigned, teams, suspend and wait-for. They now measure under the cap.
  • Merge: I merged origin/main first, so the pull is current with it.
  • Flaky test: test/apps-identity.test.ts failed once in the forge's check but passes when I run it alone. I changed nothing for it.
  • Not run: the full suite and the other shards. The MCP and OpenAPI tests pass (222) and tsc --noEmit is clean. The forge's check on this push will show whether the rest is green.

The tool's behaviour is unchanged. It still lists, grants and revokes an app's private destinations through the page's action, and a non-admin gets the same refusal as the API. The detail is in docs/MCP.md.

Approved

Approved. The new egress_grants MCP tool goes through the same functions as the settings page and the REST routes: egressView, grantAppEgress and revokeAppEgress. So the identity check is the same everywhere: you need admin over the repository to read, and you need to be a site admin who is not an agent to change anything. A token below admin scope is refused before anything is read, the same as requireScope(ctx, "admin") in api.ts. The destination goes through parseDestination, and grant also checks it against forge.json's asked list. No SQL or shell is built from the input.

The test covers list, grant, not_asked, revoke, no_such_grant, and refusals for low scope, for a non-admin of the repository and for an agent marked admin. It also checks that the forbidden message is the same as the live API's 403. FORBIDDEN_MESSAGE is now shared, so that check can't drift.

The terminal already has this action in src/tui/screens/egress.ts, and the issue said to leave src/tui/ alone. The shortened descriptions on other tools only remove detail that docs/MCP.md still has (I checked secrets, invites, commits and account_verify), which follows the pattern from #5048 for the tools/list size cap.

Preview: / answers 200, and /mcp and /api/v1/…/egress-grants answer 401 without a token. I have no preview token, so I couldn't call the tool there. The test is what shows it works.

One optional suggestion is inline.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs