Public: anyone can read this; the crew can change it.
MCP `sync`: sync a mirror now, or reconnect its origin, with the same rules as the API #6994
Check · Review · Land · Live done — Landed and live in production.
There was nothing to merge, so I changed nothing and pushed nothing. `main` on the forge is still `d36a4a74`, which is the commit I merged last time, and it is already an ancestor of this branch. A merge of `origin/main` reports "Already up to date", with no conflicts in `docs/MCP.md` or `src/http/mcp.ts`.
shipped production is serving it deploy 93e874d
The sync MCP tool is back on the branch and pushed. It now lives where main keeps tools, so the earlier red check should clear. I couldn't confirm the push from here: it printed the new commit, but a local ref update failed (a read-only .git path). I haven't seen the forge's verdict.
The old branch had put sync in src/http/mcp.ts. Main has since moved every tool into its own file under src/http/mcp/tools/, so the merge conflicted. I merged main, took main's mcp.ts and docs/MCP.md, and re-added the tool as src/http/mcp/tools/sync.ts. I regenerated its index line and the docs row with bun scripts/mcp-tools.ts.
What it does:
sync { repo }runs the same action asPOST …/sync, for the same caller, so the API's permission checks apply.- With
originIdit runs the reconnect action instead. That needs an admin-scope token, and a refusal names admin rather than write access. - A fork is refused with
not_a_mirrorand pointed totake_updates. - Each refusal says what to do next.
- Its description is one short sentence, to keep
tools/listsmall.
Tests: test/mcp-sync.test.ts covers an admin syncing a faked origin with no network, a non-mirror refused, a reader refused, and the reconnect and fork paths. bun x tsc --noEmit is clean. The tests that cover the change pass: mcp-sync, mcp, mcp-size and mcp-tools.
Left out: the API routes are unchanged, and I didn't run the full check.
There was nothing to merge, so I changed nothing and pushed nothing. main on the forge is still d36a4a74, which is the commit I merged last time, and it is already an ancestor of this branch. A merge of origin/main reports "Already up to date", with no conflicts in docs/MCP.md or src/http/mcp.ts.
The branch is at 1e767d56, and the forge's refs/pull/6994/head points at the same commit. A plain git push says "Everything up-to-date". I didn't re-run the tests, since nothing changed since they passed.
The conflict report was probably computed against an older main, from before the merge I pushed. If it still shows on #6994, re-check the pull against the current main. If main moves again, send me back and I'll merge it then.
The check failed because the new sync tool had the sentence "the origin could not be reached" written into its own refusal text. A test requires that sentence to come only from src/actions/origin_app_words.ts. I changed src/http/mcp/tools/sync.ts to import ORIGIN_UNREACHABLE from that module and append "; try again later" to it. The agent still sees the same words.
I ran origin-app-words, crew-limit-words, mcp-sync, mcp-size and mcp-tools, plus the type check. All pass. The forge's full check hasn't run on the fix yet. The push landed as 8b14e6e8.
The pull adds an MCP sync tool, in its own file under src/http/mcp/tools/. sync { repo } syncs a mirror now, and sync { repo, originId } reconnects its origin, which needs an admin token. Both call the actions behind POST …/sync and …/origin/reconnect, so the refusals match the API's. A fork is pointed to take_updates. docs/MCP.md has the tool's row, and test/mcp-sync.test.ts covers an admin sync against a faked origin, a non-mirror, a reader, reconnect and fork.
I left the API routes and the full check untouched.
Clean. sync calls the same actions as POST …/sync and …/origin/reconnect (syncRepoNow → requireWriter, reattachMirror → requireRepoAdmin plus the caller's own origin). The MCP dispatcher requires an rw scope for writes, and the tool requires an admin scope before it reconnects, which matches the API's requireScope. repoArg gives one not_found for missing and unreadable repositories. The refusal words come from the shared module, and nothing builds shell or SQL from user text. At 8b14e6e8, test/mcp-sync.test.ts covers sync, a reader, a non-mirror, a fork, rw-vs-admin scope, not_detached, an unknown origin and a real reconnect against a faked origin. mcp-sync, mcp-size and mcp-tools pass locally: 160 tests, 0 fail. The preview refuses a guest tools/call sync with the token prompt. The page and the TUI already have Sync, so this completes the agent door.
Nit, not blocking: a readable repository that is not a mirror answers "no such app or repository". That matches the API's 404, but a not_a_mirror message like the one forks get would tell an agent more.
There was nothing to merge, so I changed nothing and pushed nothing.
mainon the forge is stilld36a4a74, which is the commit I merged last time, and it is already an ancestor of this branch. A merge oforigin/mainreports "Already up to date", with no conflicts indocs/MCP.mdorsrc/http/mcp.ts.The branch is at
1e767d56, and the forge'srefs/pull/6994/headpoints at the same commit. A plaingit pushsays "Everything up-to-date". I didn't re-run the tests, since nothing changed since they passed.The conflict report was probably computed against an older
main, from before the merge I pushed. If it still shows on #6994, re-check the pull against the currentmain. Ifmainmoves again, send me back and I'll merge it then.Continues #6994