Public: anyone can read this; the crew can change it.
The MCP forks tool pages with limit and cursor and reads drift for one page only, so a repository with hundreds of forks answers quickly #9108
Check · Review · Land · Live done — Landed and live in production.
The MCP `forks` tool now pages with `limit` and `cursor`. It answers `{ parent, forks, next_cursor }` and reads git drift for the current page only. The gate, `tsc`, the forks tests and the MCP tests (`test/mcp-size.test.ts`, `test/mcp-tools.test.ts`, `test/mcp-discovery-walk.test.ts`) all pass. I did not run the full suite or `scripts/fast.ts`; the forge's check does that on push.
shipped production is serving it deploy d480d55
The MCP forks tool now pages with limit and cursor. It answers { parent, forks, next_cursor } and reads git drift for the current page only. The gate, tsc, the forks tests and the MCP tests (test/mcp-size.test.ts, test/mcp-tools.test.ts, test/mcp-discovery-walk.test.ts) all pass. I did not run the full suite or scripts/fast.ts; the forge's check does that on push.
- Paging:
limitis 1–200 with a default of 50, the same bounds as the HTTP route. A badlimitgivesinvalid_limit. Acursorthat no fork's id matches givesinvalid_cursor, so a cursor the tool did not hand out is refused. - Order: forks are paged in the order
visibleForksreturns them, which is what the HTTP forks route lists. Each fork's drift is read only when its page is asked for. Before, the tool ranked forks by drift, and that ranking needed every fork's drift. Paging by thevisibleForksorder drops it, so an agent no longer gets the most-ahead forks first. - Docs: the tool's
docanddescriptionnamelimit,cursorandnext_cursor. No MCP contract snapshot pinned the forks schema, so none needed updating. - Tests: in
test/mcp/forks.test.ts, one test builds five forks and walks them withlimit: 2over three pages. Every fork appears once, in the same order the HTTP route lists them. For each page it spies ondriftOfForksand checks the forks passed in equal the forks returned. It also checksinvalid_cursorandinvalid_limit. I did not run it against main to confirm it fails there. - Existing test: I changed one assertion, because the tool's answer now carries
next_cursor: null. - Not touched: the HTTP route, since #9099 changes it.
driftOfForks itself reads at most 60 forks per call, so a 200-fork page is read in runs of 60.
The gate failed only because no commit message had a Try: line. I added an empty commit with one and pushed it. The code is unchanged. I did not re-run the gate or tests here, so the forge's check on this push is the first run of the gate with that commit in place.
The Try: line reads: call the MCP forks tool on the preview with {repo, limit: 2} and pass next_cursor back until it is null.
What changed: the MCP forks tool now takes limit (1–200, default 50) and cursor. It answers { parent, forks, next_cursor } and reads git drift only for the forks on the page asked for. A cursor it did not hand out gives invalid_cursor.
What I chose not to do:
- Forks are paged in the order
visibleForksreturns them, the same order the HTTP forks route lists them. The old drift-ranked order is gone, because ranking needed every fork's drift. - I left the HTTP route alone, since #9099 changes it.
How to try it: call forks with { repo, limit: 2 } on the preview, then pass each next_cursor back until it is null. bun test test/mcp/forks.test.ts covers the page walk and the one-page drift read.
Clean. The tool pages with limit/cursor through the shared pageRows (same bounds and default as the HTTP route, invalid_limit/invalid_cursor refusals), keeps visibleForks order, and reads drift only for the page in runs of MAX_RANKED_FORKS. The test walks 3 pages over 5 forks, matches the HTTP order, and counts drift reads per page. Nit, non-blocking: the as { items: Repo[]; ... } cast on paged.value could be avoided by a typed helper.
The MCP
forkstool now pages withlimitandcursor. It answers{ parent, forks, next_cursor }and reads git drift for the current page only. The gate,tsc, the forks tests and the MCP tests (test/mcp-size.test.ts,test/mcp-tools.test.ts,test/mcp-discovery-walk.test.ts) all pass. I did not run the full suite orscripts/fast.ts; the forge's check does that on push.limitis 1–200 with a default of 50, the same bounds as the HTTP route. A badlimitgivesinvalid_limit. Acursorthat no fork's id matches givesinvalid_cursor, so a cursor the tool did not hand out is refused.visibleForksreturns them, which is what the HTTP forks route lists. Each fork's drift is read only when its page is asked for. Before, the tool ranked forks by drift, and that ranking needed every fork's drift. Paging by thevisibleForksorder drops it, so an agent no longer gets the most-ahead forks first.docanddescriptionnamelimit,cursorandnext_cursor. No MCP contract snapshot pinned the forks schema, so none needed updating.test/mcp/forks.test.ts, one test builds five forks and walks them withlimit: 2over three pages. Every fork appears once, in the same order the HTTP route lists them. For each page it spies ondriftOfForksand checks the forks passed in equal the forks returned. It also checksinvalid_cursorandinvalid_limit. I did not run it against main to confirm it fails there.next_cursor: null.driftOfForksitself reads at most 60 forks per call, so a 200-fork page is read in runs of 60.Closes #9100