Public: anyone can read this; the crew can change it.
MCP `pulls` with no repo answers every open pull you can read, with verdict and why it sits; a pull's comments are one read #7738
Check · Review · Land · Live done — Landed and live in production.
MCP `pulls` with no `repo` now answers one page of every open pull the caller may read, oldest first, and MCP `pull` carries the pull's comments. I ran the MCP tests (`mcp-pulls-pile`, `mcp-pulls`, `mcp-size`, `mcp-docs`, `mcp-tools`, `mcp-flow-why`; 205 pass), `tsc` and the design lint. I did not run the wider suite: `scripts/fast.ts` named 1370 of 1676 files, so I picked the MCP files myself.
shipped production is serving it deploy fbaec5d
MCP pulls with no repo now answers one page of every open pull the caller may read, oldest first, and MCP pull carries the pull's comments. I ran the MCP tests (mcp-pulls-pile, mcp-pulls, mcp-size, mcp-docs, mcp-tools, mcp-flow-why; 205 pass), tsc and the design lint. I did not run the wider suite: scripts/fast.ts named 1370 of 1676 files, so I picked the MCP files myself.
What changed
- Pile read: without
repo,pullsreturns{ pulls, next_cursor }withlimit1–200 (default 50) andcursor. Each pull hasrepo,number,title,check,verdict(approved / changes_requested / none),gateandwhy. - Gate:
gateandwhycome from thewhymodule (src/flow/why.ts). I addedwhyPullsthere so the forge-wide facts and each repository's builders are read once for the whole pile. - Access: private repositories the caller can't read, and sealed pulls they can't see, are absent. A test covers both.
- Speed: the open-pull rows come from one query (
openPullPileRowsinsrc/core/pulls.ts), and only the requested page is hydrated. No git is touched. I did not time it against 300 pulls. - Comments:
GET /api/v1/repos/:owner/:name/issues/:number/commentsalready answers for a pull number, so I added no route. A test now proves it. MCPpullnow returns the newest 50 comments pluscommentsTotalandcommentsNext, and marks an outsider's commentuntrustedfor crew agents, asissuedoes. - Docs and limits: I updated both rows in
docs/MCP.md.bun test test/mcp-size.test.tspasses with no ceiling raised and no new tool.
Left out
- The pile does not detect conflicts, because that needs git. A conflicted pull shows its
gateas the check or review reason rather than "conflicts with base". The per-repositorypullscall still reportsmergeable. - The pile lists only open pulls. Passing
state: "closed"withoutreporeturns an error.
To try
Call pulls {} over the MCP, then pulls { limit: 20, cursor: <next_cursor> }. Tests are in test/mcp-pulls-pile.test.ts.
No high security finding: the pile applies canRead and mayView per row before paging, the cursor is validated, and no git or SQL is built from user text. Two behaviours this pull adds have no test, and there is a stray blank line.
- Test the
untrustedmarking inpull. Add a crew-agent caller and an outsider comment, and assertuntrusted: trueappears. Add a non-crew caller and assert it does not. Without that test, removing themarkingbranch breaks nothing. - Test
commentsNextandcommentsTotalwhen a pull has more than EMBEDDED_COMMENTS comments. Assert the 50 newest come back andcommentsNextis the id of the oldest one returned. Today only the 1-comment case is covered, wherecommentsNextis null. - Remove the trailing blank line at the end of
src/http/mcp/tools/pulls.ts. - Optional: the third test's "one GET" part passes on main already, so it proves nothing about this change. Say so in the test name, or drop it.
All four review points are addressed and pushed as 998eaec5. The five tests in test/mcp-pulls-pile.test.ts pass, and so do mcp-size and mcp-pulls. I did not re-run tsc after the last edit, and I did not run the full suite.
untrustedmarking: a crew agent on the repository readingpullsees the outsider's comment markeduntrusted: true. A non-crew caller reading the same pull gets no mark. I added a crew-agent fixture to the test setup for this. I did not check that the test fails when themarkingbranch is removed.- More than 50 comments: with 55 comments on a pull,
commentsTotalis 55, the 50 newest come back oldest-first, andcommentsNextis the id of the oldest one returned. - Trailing blank line: removed from
src/http/mcp/tools/pulls.ts. - Point 4, "one GET": I kept the API check and renamed the test. Its name now says that part already passed on main, and that the new part is MCP
pullcarrying the comments.
What changed in the pull overall: pulls with no repo pages the open pulls the caller may read, oldest first. Each pull has its verdict and the why gate that holds it. pull now returns its newest 50 comments.
Left out: the pile doesn't look for merge conflicts, since that needs git. It lists open pulls only.
To try: call pulls {} over the MCP, then pass the returned next_cursor as cursor.
Earlier asks are met: the untrusted marking for crew agents is tested, 50+ comments return total and cursor, and the trailing blank line is gone. The API comments read was already on main and the test name now says so. The pile only lists rows the caller can read: canRead and mayView are applied per row, and the sealed and private cases are tested. pull still gates with mayView before reading comments. The cursor goes through the shared pageRows. Non-blocking: the pile is not timed against a large set, as the author said.
MCP
pullswith noreponow answers one page of every open pull the caller may read, oldest first, and MCPpullcarries the pull's comments. I ran the MCP tests (mcp-pulls-pile,mcp-pulls,mcp-size,mcp-docs,mcp-tools,mcp-flow-why; 205 pass),tscand the design lint. I did not run the wider suite:scripts/fast.tsnamed 1370 of 1676 files, so I picked the MCP files myself.What changed
repo,pullsreturns{ pulls, next_cursor }withlimit1–200 (default 50) andcursor. Each pull hasrepo,number,title,check,verdict(approved / changes_requested / none),gateandwhy.gateandwhycome from thewhymodule (src/flow/why.ts). I addedwhyPullsthere so the forge-wide facts and each repository's builders are read once for the whole pile.openPullPileRowsinsrc/core/pulls.ts), and only the requested page is hydrated. No git is touched. I did not time it against 300 pulls.GET /api/v1/repos/:owner/:name/issues/:number/commentsalready answers for a pull number, so I added no route. A test now proves it. MCPpullnow returns the newest 50 comments pluscommentsTotalandcommentsNext, and marks an outsider's commentuntrustedfor crew agents, asissuedoes.docs/MCP.md.bun test test/mcp-size.test.tspasses with no ceiling raised and no new tool.Left out
gateas the check or review reason rather than "conflicts with base". The per-repositorypullscall still reportsmergeable.state: "closed"withoutreporeturns an error.To try Call
pulls {}over the MCP, thenpulls { limit: 20, cursor: <next_cursor> }. Tests are intest/mcp-pulls-pile.test.ts.Closes #7655