SIGN IN SIGN UP

(core) Route MCP doc requests through the standard doc API forwarding

Summary:
MCP used to find its way to documents on its own: the server handling the request did the work if it hosted documents, and otherwise forwarded the call with its own homemade forwarding. Fleet (D4951) broke that. Every server there hosts documents, but each hosts only some of them, so "this server hosts documents" stopped meaning "this server hosts *this* document."

Regular document API calls already know how to travel to the right server, so MCP now rides along:

- A call to /api/docs/:docId/mcp is passed along to the doc's server like any other document API call, through a new "route" mode: look the doc up just enough to know where to send it, and leave permission checks to the server that owns it, since MCP checks them per tool from what is inside the message. Sign-ins through OAuth look anonymous at first glance, so the lookup uses the actual signed-in user, or private documents would get sent to the wrong place.

- That endpoint now exists only on servers that host documents, and always does the work locally. It also reads URLs the way the regular document API does: the team site in the web address matters, so asking through the wrong site's address now gets a polite "not found."

- /api/mcp names the document inside the message, so the URL alone can't tell us where to send it. That decision now happens once per call, before the tool runs: if another server hosts the doc, we re-send the client's own request there and relay the answer untouched, so a throttle 429 or a scope 403 arrives as itself rather than flattened into a 200 carrying error text. The per-tool forwarding machinery goes with it.

- MCP and the doc-to-doc calls (/compare, /replace) now share one forwarder, which goes straight to the doc's worker, dropping the worker-to-home-to-worker hop those calls took. Moving /compare onto it surfaced two bugs there: it forwarded a urlId, winning the other document a second worker assignment that could open it in two places at once, and it ignored the status of its second request, turning a worker's error into an opaque 500.

One behavior change: an /api/mcp doc call counts against the doc's daily API allowance wherever it runs, where an in-process one used to escape it. It still runs in place when this server hosts the doc, so no extra hop.

The old addExtraDocForwarder hook is gone, and the MCP tests turned off for Fleet are back on and passing.

Test Plan: updated tests

Reviewers: Spoffy

Reviewed By: Spoffy

Differential Revision: https://phab.getgrist.com/D5016
P
Paul Fitzpatrick committed
b2145fe0a5ec127a9b0ec1788c0cd9864c78184c
Parent: 3f96a71