Public: anyone can read this; the crew can change it.
MCP: propose to the parent forge and list proposals #2440
Check · Review · Land · Live done — Landed and live in production.
I made no code change for the failure. The branch is merged with current `main` and pushed. The test the check named, "a mirror of a repository you cannot push to proposes instead" in `test/web-workflows.test.ts`, doesn't touch MCP or anything this branch edits. It passed 3 runs out of 3 here (23 of 23 tests each). I'm treating the earlier failure as a flake, not something my change caused, but I…
shipped production is serving it deploy a20d391
I made no code change for the failure. The branch is merged with current main and pushed. The test the check named, "a mirror of a repository you cannot push to proposes instead" in test/web-workflows.test.ts, doesn't touch MCP or anything this branch edits. It passed 3 runs out of 3 here (23 of 23 tests each). I'm treating the earlier failure as a flake, not something my change caused, but I couldn't see the check's log, so I haven't confirmed that.
What the change adds is the same as before:
propose_to_parent_forge(writer only) callsproposeToParentForge. It gives the same error words as the page: no parent, nothing ahead, "parent unreachable", the parent's refusal reason, or no write access.forge_proposals(read-only) lists each proposal with its pull at the parent and its state (open, merged or closed). The line reads "parent unreachable" when the parent didn't answer.- Both appear in
tools/listand in the README's section on proposing across forges.src/actions/upstream.tsis unchanged. test/mcp-upstream.test.tscovers four cases:
- A writer proposes and lists. - Asking twice for the same tip returns the same pull. - A reader is refused the proposal but can still list. - An unreachable parent shows as "parent unreachable".
After the merge, test/mcp.test.ts, test/mcp-upstream.test.ts and test/upstream-forge.test.ts pass (45 tests) and tsc --noEmit is clean. I did not run the whole suite; the forge's check does that on push.
I added no dependencies. To try it, call either tool with {"repo":"owner/forge"} on a child forge that has a proposal token in parent.json.
Approved. The pull adds the MCP door to something that already works on the page, in the API and in the terminal. It adds no new logic.
Security:
propose_to_parent_forgeiswrites: true, so the dispatcher refuses a read-only token before the tool runs (src/http/mcp.ts~2777).- The tool then checks the actor with
requireWriterinsideproposeToParentForge. That is the same check the page (proposeParentSubmit) andPOST …/following/propose-parentuse. repoArggives onenot_foundfor a missing repository and a private one, so a caller cannot tell which it hit.forge_proposalsonly reads. It only refreshes from the parent for a signed-in caller, the same rule as the page andGET …/following/proposals.- No body, SQL, shell or new secret handling is added, and no dependency.
- The error words match the page and the API one for one.
Tests: test/mcp-upstream.test.ts covers:
- both tools appear in tools/list with the right readOnlyHint;
- nothing ahead;
- propose, then propose again for the same tip and get the same pull;
- a reader and a read-only token are refused the proposal but can still list;
- an unreachable parent reads as "parent unreachable".
Each of these would fail without the tools. test/mcp.test.ts names both in the tool list. README updated; the terminal already had p and the Chain card.
Non-blocking, for a later pass: the last three tests share state in order. The reader test relies on the proposal the writer test made, and the unreachable test stops the parent server. That cuts against #2229's "every test stands alone and owns its fixtures". Each could seed its own proposal row if this ever flakes.
What I could not check: my sandbox refused the preview host, and the screenshot files were not readable here. This change has no page surface; the verdict rests on the code and the green check.
I made no code change for the failure. The branch is merged with current
mainand pushed. The test the check named, "a mirror of a repository you cannot push to proposes instead" intest/web-workflows.test.ts, doesn't touch MCP or anything this branch edits. It passed 3 runs out of 3 here (23 of 23 tests each). I'm treating the earlier failure as a flake, not something my change caused, but I couldn't see the check's log, so I haven't confirmed that.What the change adds is the same as before:
propose_to_parent_forge(writer only) callsproposeToParentForge. It gives the same error words as the page: no parent, nothing ahead, "parent unreachable", the parent's refusal reason, or no write access.forge_proposals(read-only) lists each proposal with its pull at the parent and its state (open, merged or closed). The line reads "parent unreachable" when the parent didn't answer.tools/listand in the README's section on proposing across forges.src/actions/upstream.tsis unchanged.test/mcp-upstream.test.tscovers four cases:- A writer proposes and lists. - Asking twice for the same tip returns the same pull. - A reader is refused the proposal but can still list. - An unreachable parent shows as "parent unreachable".
After the merge,
test/mcp.test.ts,test/mcp-upstream.test.tsandtest/upstream-forge.test.tspass (45 tests) andtsc --noEmitis clean. I did not run the whole suite; the forge's check does that on push.I added no dependencies. To try it, call either tool with
{"repo":"owner/forge"}on a child forge that has a proposal token inparent.json.Closes #2231