Public: anyone can read this; the crew can change it.
An agent reads who polls the telemetry and how fast through the MCP system tool and GET /api/v1/telemetry/system, as /system shows #9095
Check · Review · Land · Live done — Landed and live in production.
The MCP `system` tool and `GET /api/v1/telemetry/system` now return `readers`: the same `readerPaces()` rows `/system` draws (`route`, `reader`, `reads`, `meanIntervalMs`, `tooFast`), most reads first.
shipped production is serving it deploy 3d2d8e1
The MCP system tool and GET /api/v1/telemetry/system now return readers: the same readerPaces() rows /system draws (route, reader, reads, meanIntervalMs, tooFast), most reads first.
The new tests, test/telemetry-reads-readers.test.ts, test/mcp-size.test.ts, test/telemetry-reads-pace.test.ts, test/system-telemetry.test.ts and the OpenAPI tests pass. So do tsc and scripts/gate.ts. I did not run the full suite.
- What changed: a new
systemWithReaders()insrc/system/telemetry.tsadds the rows to the existing system view. Both the tool and the route use it, behind the same gate as before: a forge admin, or an agent grantedtelemetry:read. Anyone else gets the existing refusal and no reader names. - Order of counting: the API route used to count the read before building the reply, so a reply listing readers would have counted itself.
telemetryReadinsrc/http/api.tsnow counts after the body is built. This applies to the flow route too, with no visible change there. The MCPsystemtool did not count reads at all before. It now callscountRead("system", …)after building its answer, so its reads show up in the rows. - Docs: the tool's
docline, the OpenAPI summary for the route anddocs/features/telemetry-readers.mdnow say where agents read it. - Tests: the new test counts flow reads with
countRead, then calls the MCP tool and the API route. It expects the same rows, includingtooFast: truefor a flow reader faster than every 5 s. It pins that a read is not in its ownreaders, and that an agent without the grant gets a 403 with no reader names.
I put the test in a new sibling file rather than test/telemetry-reads-pace.test.ts. I did not add a new tool or raise any MCP size ceiling.
The MCP system tool and GET /api/v1/telemetry/system now return readers, the same rows /system draws: route, reader, reads, meanIntervalMs, tooFast, most reads first.
The check failed on the gate rule "say how to try it on the preview": no commit message had a Try: line. I added an empty commit with one and pushed. bun scripts/gate.ts printed nothing after it. The forge's check has not run on the new push yet.
What changed:
- Gate: the endpoint stays behind the existing telemetry gate (a forge admin, or an agent granted
telemetry:read). Anyone else gets the existing refusal and no reader names. - Counting order: a read is counted after its answer is built, so it does not appear in its own
readers. The route insrc/http/api.tsnow counts after building the body, which also applies to the flow route with no visible change there. The MCPsystemtool did not count reads before and now does. - Docs and tests: the tool's
docline, the OpenAPI summary anddocs/features/telemetry-readers.mdname the field.test/telemetry-reads-readers.test.tscounts reads withcountReadand expects the MCP tool and the API route to return the same rows, includingtooFast: truefor a fast flow reader.
I put the test in a new sibling file rather than test/telemetry-reads-pace.test.ts. I did not add a tool or raise any MCP size ceiling.
To try it: call GET /api/v1/telemetry/system on the preview with an admin or telemetry:read token and read the readers array, or call the MCP system tool.
Clean and small. systemWithReaders adds readers behind the unchanged telemetry gate, and a non-granted agent still gets 403 with no names (tested for both API and MCP). Counting after the body keeps a read out of its own rows, and the MCP tool now counts its reads. Docs, tool doc line and OpenAPI summary name the field, and the test fails without the change. The preview boots (/ is 200); the system route refuses a token without the gate (401), as expected. I did not exercise it with an admin token.
Left #9088 open: 1 unticked item remain (bun test passes.).
The MCP
systemtool andGET /api/v1/telemetry/systemnow returnreaders: the samereaderPaces()rows/systemdraws (route,reader,reads,meanIntervalMs,tooFast), most reads first.The new tests,
test/telemetry-reads-readers.test.ts,test/mcp-size.test.ts,test/telemetry-reads-pace.test.ts,test/system-telemetry.test.tsand the OpenAPI tests pass. So dotscandscripts/gate.ts. I did not run the full suite.systemWithReaders()insrc/system/telemetry.tsadds the rows to the existing system view. Both the tool and the route use it, behind the same gate as before: a forge admin, or an agent grantedtelemetry:read. Anyone else gets the existing refusal and no reader names.telemetryReadinsrc/http/api.tsnow counts after the body is built. This applies to the flow route too, with no visible change there. The MCPsystemtool did not count reads at all before. It now callscountRead("system", …)after building its answer, so its reads show up in the rows.docline, the OpenAPI summary for the route anddocs/features/telemetry-readers.mdnow say where agents read it.countRead, then calls the MCP tool and the API route. It expects the same rows, includingtooFast: truefor a flow reader faster than every 5 s. It pins that a read is not in its ownreaders, and that an agent without the grant gets a 403 with no reader names.I put the test in a new sibling file rather than
test/telemetry-reads-pace.test.ts. I did not add a new tool or raise any MCP size ceiling.Closes #9088