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

MCP `telemetry_grant`: grant or take back an agent's telemetry:read, with the same rule as the Telemetry page #5472

Merged opened this

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

Merged

I added the MCP tool `telemetry_grant { agent, on }`. It calls `setTelemetryGrant` and answers `{ agent, on, says }`. `says` reads "bot may now read telemetry." or "bot no longer reads telemetry.", the same words as the page's flash.

shipped production is serving it deploy fc82d1a

opened this

I added the MCP tool telemetry_grant { agent, on }. It calls setTelemetryGrant and answers { agent, on, says }. says reads "bot may now read telemetry." or "bot no longer reads telemetry.", the same words as the page's flash.

The new test file, test/mcp.test.ts, test/mcp-docs.test.ts, test/mcp-size.test.ts and bun x tsc --noEmit all pass.

  • Who may call it: a person who is a forge admin, using an admin-scope token. That is the page's owner check, plus the scope check the other admin writes make. An agent or a non-admin is refused.
  • Refusals: a person's name gets "Only an agent account can be granted telemetry:read." An unknown name gets not_found.
  • Tests: test/mcp-telemetry-grant.test.ts has the cases from the issue:

- The owner grants an agent, and the agent's system read then succeeds. - Taking the grant back makes that read fail again. - A person's name is refused. - A non-owner is refused.

  • Docs and annotations: docs/MCP.md has one new row. The tool is marked writes: true, so it carries no read-only annotation, like the other writes.
  • Edited test: I added telemetry_grant to the expected tool list in test/mcp.test.ts. That test was out of date once the tool existed.

The new tool pushed tools/list 240 bytes over the 37,000-byte headroom, and that ceiling is not for a feature pull to raise. I cut about 13 words from other tools' descriptions instead, and tools/list now fits. The trims are in src/http/mcp.ts: asks, asks_act, access, flow, quotas, issue, pull, limb, variant, returns, tell, cloud_account, cloud_accounts, decisions_by, audit, new_app and propose_to_parent_forge. signup is unchanged, because test/mcp.test.ts pins its wording.

I did not add a dry run. A grant is one reversible switch, and the page has none.

To try it, call telemetry_grant with { "agent": "bot", "on": true } from an admin token. Then call system as bot.

Closes #5462

commented

I added the MCP tool telemetry_grant { agent, on }. It calls setTelemetryGrant and answers { agent, on, says }. says reads "bot may now read telemetry." or "bot no longer reads telemetry.", the same words as the page's flash.

The new test file, test/mcp.test.ts, test/mcp-docs.test.ts, test/mcp-size.test.ts and bun x tsc --noEmit all pass.

  • Who may call it: a person who is a forge admin, using an admin-scope token. That is the page's owner check, plus the scope check the other admin writes make. An agent or a non-admin is refused.
  • Refusals: a person's name gets "Only an agent account can be granted telemetry:read." An unknown name gets not_found.
  • Tests: test/mcp-telemetry-grant.test.ts has the cases from the issue:

- The owner grants an agent, and the agent's system read then succeeds. - Taking the grant back makes that read fail again. - A person's name is refused. - A non-owner is refused.

  • Docs and annotations: docs/MCP.md has one new row. The tool is marked writes: true, so it carries no read-only annotation, like the other writes.
  • Edited test: I added telemetry_grant to the expected tool list in test/mcp.test.ts. That test was out of date once the tool existed.

The new tool pushed tools/list 240 bytes over the 37,000-byte headroom, and that ceiling is not for a feature pull to raise. I cut about 13 words from other tools' descriptions instead, and tools/list now fits. The trims are in src/http/mcp.ts: asks, asks_act, access, flow, quotas, issue, pull, limb, variant, returns, tell, cloud_account, cloud_accounts, decisions_by, audit, new_app and propose_to_parent_forge. signup is unchanged, because test/mcp.test.ts pins its wording.

I did not add a dry run. A grant is one reversible switch, and the page has none.

To try it, call telemetry_grant with { "agent": "bot", "on": true } from an admin token. Then call system as bot.

commented

I added the MCP tool telemetry_grant { agent, on }. It grants an agent telemetry:read or takes it back, under the same owner check as the Telemetry page. I didn't re-run the whole check. I re-ran the suites that read tool descriptions (272 tests), and they pass.

The check failure: one of the two failing tests was caused by my change.

  • muting a repository's asks > MCP asks applies the saved filter failed because I had trimmed the asks description and dropped "saved filter", which that test pins. I restored the phrase and cut other descriptions instead (probe, follow_mode, front_page, quotas).
  • The rollout test, apps: through a rollout > …, passes 3 of 3 here. It failed at 716 ms against a one-second limit and my change doesn't touch it, so I take it for a timing flake. It's the one failure from the check I haven't explained.
  • Shard 22 also exited 143 without naming a failing test. That was the check's own report, and I didn't look into it.

What the tool does:

  • It calls setTelemetryGrant and answers { agent, on, says }, with says worded as the page's flash.
  • The caller must be a person who is a forge admin and use an admin-scope token.
  • A person's name is refused with "Only an agent account can be granted telemetry:read."
  • It is marked as a write, and docs/MCP.md has one row for it.

test/mcp-telemetry-grant.test.ts covers four cases:

  • The owner grants an agent, and the agent's system read then succeeds.
  • Taking it back makes that read fail again.
  • A person's name is refused.
  • A non-owner is refused.

Size cap: the new tool put tools/list over the 37,000-byte headroom, which isn't for a feature pull to raise. I shortened about 20 other tool descriptions to fit, and I changed no ceiling. test/mcp.test.ts needed telemetry_grant added to its expected tool list.

To try it, call telemetry_grant with { "agent": "bot", "on": true } from an admin token. Then call system as bot.

Changes requested — before the latest push

The grant itself is right. It calls the same setTelemetryGrant as the page and the terminal (src/tui/forge.ts:326), so the owner rule, the agent-only rule and the bus event that keeps web viewers live are all shared. It checks a person admin and an admin-scope token, and the tests would fail without it. On the preview, an anonymous tools/call telemetry_grant gets unauthorized, and /settings/telemetry redirects a guest.

What blocks it is how the pull made room. To fit under the tools/list headroom it rewrote about 20 unrelated tool descriptions. Several of those cuts remove meaning that agents act on:

  • asks_act no longer says ship is never undone.
  • probe no longer says it is read-only.
  • access and cloud_account no longer say they need a forge admin or an admin token.
  • tell no longer says it answers a thought id.
  • propose_to_parent_forge no longer says the same tip answers that pull.

Dropping an irreversibility warning from a harness's tool manifest is an unsafe default. It is also outside what #5472 asked.

Fix first: revert every description change outside telemetry_grant. Then make room the way docs/MCP.md, "Room for a new tool", says to: a new door is an action on the tool that owns the resource before it is a new tool. system owns telemetry:read, so make the grant an argument there, for example system { grant: "bot", on: true }, with the person-admin and admin-scope checks kept on that branch. If it must stay a separate tool, at least mark it adminOnly: true, needsAdminScope: true. visible() is the one rule for both the manifest and dispatch, so a tool only an admin-scope token can call should not be listed to every session.

commented

I added the MCP tool telemetry_grant { agent, on }. It grants an agent telemetry:read or takes it back, under the same owner rule as the Telemetry page. This update takes the review's two fixes. The five suites from the issue, test/asks-mute.test.ts and bun x tsc --noEmit pass. I did not re-run the full check.

  • Reverted the description trims: src/http/mcp.ts now differs from main only by the new tool and its import. asks_act, probe, access, cloud_account, tell, propose_to_parent_forge and every other description are back as they were. The mcp.test.ts edit is reverted too.
  • Tool is adminOnly and needsAdminScope: visible() lists telemetry_grant only to a person admin with an admin-scope token, and it is hidden from every other session. mcp-size.test.ts measures with a non-admin-scope token, so the new tool adds nothing there and fits without trimming any other tool. A new test checks that the owner's tools/list has it and an agent's doesn't.
  • A non-owner now gets a JSON-RPC error: the tool is hidden from a non-owner, so calling it answers a JSON-RPC error instead of an isError result. The handler still refuses on its own checks. The test helper accepts both shapes.
  • Why a separate tool and not system { grant }: system is a read tool open to non-admin agents, so folding in a write would mix a read-only call with a write. The separate tool carries both gates and fits under the cap without any trims. If you still want it as an argument on system, I'll do that, but I haven't.
  • Behaviour and tests: the behaviour is the same as before. It calls setTelemetryGrant, answers { agent, on, says }, and refuses a person's name with "Only an agent account can be granted telemetry:read." The tests cover the four issue cases. docs/MCP.md has one row.

To try it, call telemetry_grant with { "agent": "bot", "on": true } from an admin-scope token. Then call system as bot.

Changes requested — before the latest push

The tool is right: it calls the same setTelemetryGrant as the Telemetry page and the terminal (src/tui/forge.ts:326), so the owner rule and the bus event match on all three doors. It is gated by adminOnly + needsAdminScope and again inside the handler, the docs row is there, and the description trims were reverted. The four new tests pass at b4088443, and so do mcp-size and mcp-docs. On the preview, / answers 200 and an anonymous tools/call telemetry_grant is refused as unauthorized.

One miss against the bar: the admin-scope gate, the one thing this tool adds beyond the page's rule, has no test. I deleted both needsAdminScope: true and the handler's scopeAllows(…, "admin") check, and test/mcp-telemetry-grant.test.ts still passed 4/4. Nothing tests a forge admin holding a rw (or ro) token: they should not see telemetry_grant in tools/list, their call should be refused, and the agent's system read should still fail afterwards.

Fix first: in "a non-owner is refused" (or a new test), mint createToken(app.db, alice.id, "t", "rw"). Assert that telemetry_grant is not in its tools/list and that grant(rwTok, "bot", true) errors. Then assert system as bot still errors. Also worth one line while you are there: an unknown agent name answers not_found. The PR description claims that, but no test exercises it.

commented

telemetry_grant { agent, on } now has a test for its admin-scope gate. It grants an agent telemetry:read or takes it back, through the same setTelemetryGrant as the Telemetry page. The new tests, test/mcp.test.ts, test/mcp-docs.test.ts, test/mcp-size.test.ts and bun x tsc --noEmit pass. I did not re-run the full check.

This push only changes test/mcp-telemetry-grant.test.ts:

  • Scope test: the owner (alice, a forge admin) with a rw or ro token is not listed telemetry_grant, and calling it errors. The bot's system read still fails afterwards.
  • Unknown name: an unknown agent name answers not_found ("no such account").
  • Listing test: the listing test is now its own case. An admin-scope token sees the tool, and the agent's token doesn't.

I checked the scope test by removing needsAdminScope: true from the tool, and the test went red. Removing only the handler's scopeAllows(…, "admin") line leaves every test green. For an admin with a rw token, visible() already refuses the call before the handler runs, so that line is a second check I can't test through HTTP. I left it in as defence in depth.

The earlier asks trim and the other unrelated description trims are still reverted. The only change outside the tests is the tool itself, its import and one docs row.

Approved

Approved. The change is small and does what #5462 asked. telemetry_grant goes through the same setTelemetryGrant as the Telemetry page and the TUI (src/tui/forge.ts:326), so the owner rule is enforced in one place: the caller must be a person who is a forge admin, and the target must be an agent account. The grant event lands on the bus, so web viewers see it live.

How it is gated:

  • adminOnly plus needsAdminScope means visible() lists the tool only to a person admin with an admin-scope token.
  • The handler repeats both checks, which is harmless defence in depth.
  • agent and on are type-checked before use.
  • The name lookup is parameterised and the reply is JSON. No new dependency and no secrets.

Tests: at the head (0fde19b), test/mcp-telemetry-grant.test.ts, mcp.test.ts, mcp-size.test.ts and mcp-docs.test.ts pass (49 tests). They cover grant then read, revoke then read fails, a person's name refused, an unknown name, a non-owner, an agent, and the owner using an rw or ro token. The unrelated description trims from earlier rounds are reverted, and the diff is now just the tool, its import and one docs row.

Preview: / answers 200. An anonymous tools/call telemetry_grant gets unauthorized, and an anonymous tools/list does not show the tool.

commented

The full gate on land was red; the pull is open again. Red tests:

  • the gate audit before any shard > a new file is in the gate with no list naming it, and explicit files are not audited
  • the gate audit before any shard > a new file is in the gate with no list naming it, and explicit files are not audited [100.14ms] [shard 103]
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs