Co to znamená
Otevřete repozitář v jednom klientovi MCP a majordomus mcp je server: jeho stdio obsluhuje tohoto klienta a vedle něj loopback socket obsluhuje domovskou stránku se seznamem všech povrchů, dokumentaci tohoto repozitáře na /docs/, Swagger UI na /swagger, dokument OpenAPI, každou cestu schopnosti a MCP přes HTTP na /mcp; URL i všechny povrchy jsou v logu hned, jakmile se naváže. Otevřete repozitář ve druhém klientovi a jeho majordomus mcp nespustí další server: najde první přes lease, ověří, že odpovídá za tento kořen, a předává mu rámce svého klienta. Zavřete klienty v libovolném pořadí a server přetrvá přesně tak dlouho, dokud je připojen jeden; když odejde poslední, zavře port a odstraní lease. Zabijte server a přemostěný klient jeho místo převezme nebo se připojí k procesu, který lease získal první, a jeho vlastní klient se nikdy znovu neinicializuje. --standalone obsluhuje samotného klienta bez portu a bez lease.
Princip
src/lease.rs atomicky vytvoří .ai/local/state/mcp/server.json (proces, který vyhraje, je server), publikuje do něj URL po navázání portu, otestuje URL, kterou najde, proti GET / a kořeni repozitáře a převezme lease, jehož server neodpovídá; soubor, který není dokumentem lease, prázdný soubor nebo soubor, jehož vlastník nepublikoval URL do patnácti sekund, se převezmou také, každý pojmenovaný v logu, aby nic, co klient zanechá, nemohlo zamknout ostatní. Když soubor nelze ani zapsat, ani nahradit, src/commands/mcp.rs obslouží samotného klienta, jako by to udělal --standalone, a řekne proč. SIGTERM, SIGINT a SIGHUP odstraní lease uvnitř handleru dřív, než proces signálem zemře. src/shared.rs naváže (--http-port, výchozí 8741, obsazený port nahrazen volným), spustí pracovní vlákna nad neměnným registrem a před zastavením počká, až připojené relace odejdou. src/http/mcp.rs je MCP přes HTTP: initialize odpoví s Mcp-Session-Id, každý další požadavek ho nese, DELETE ukončí relaci a nečinná vyprší. src/mcp/bridge.rs je druhá strana, jeden HTTP požadavek na zprávu stdio a ping každých dvacet sekund; src/commands/mcp.rs drží relaci, která je buď zodpovězena lokálně, nebo přemostěna, a znovu volí, když most ztratí svůj server.
Jak to vidět
just build
apps/majordomus-cli/target/debug/majordomus mcp < /dev/null # the log: shared server listening on http://127.0.0.1:8741 — 7 surface(s): api .../api/v1, ...
# in one terminal, keep a client attached:
mkfifo /tmp/in; apps/majordomus-cli/target/debug/majordomus mcp < /tmp/in & exec 3>/tmp/in
cat .ai/local/state/mcp/server.json # the lease: url, root, pid
# in another: a second client bridges instead of binding
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"second","version":"0"}}}\n' | apps/majordomus-cli/target/debug/majordomus mcp
# stderr: a shared server for this repository is already running at http://127.0.0.1:8741 ...; bridging this stdio session to it
exec 3>&- # the first client goes: the server stops, the lease is goneCo nepokrývá
Server drží index, který sestavil při startu; klient, který se připojí později, vidí vrstvu, jaká tehdy byla, a znovuobjevení je restart (server skončí, když odejde poslední klient). --discovery a --strict serveru platí pro každou relaci, kterou obsluhuje. Na /mcp není žádný stream iniciovaný serverem, žádné oznámení, žádný odběr. Lease je na checkout: dva worktrees mají dva servery. kill -9 nelze zachytit, takže ponechává lease dalšímu procesu k převzetí; klient HTTP, který odejde bez DELETE /mcp, udrží server, jehož vlastník už odešel, naživu nejvýše devadesát sekund.
Proč existuje
Operátor požádal o Swagger UI vedle majordomus mcp ve výchozím stavu a o právě jeden server na repozitář, aby jej sdílelo několik klientů (Claude, Codex, Gemini) a mohli se koordinovat. Daemon návrh odmítá; server, který je potomkem klienta a končí s posledním klientem, odpovídá na obojí. Rozhodnutí a jeho odpověď na seznam „Intentionally Absent“ jsou .ai/repo/adrs/0003-shared-mcp-server-peers-and-client-autostart.md. apps/majordomus-cli/tests/mcp_shared.rs spouští procesy a mluví s nimi přes skutečné roury a sockety, zabíjí server a sleduje, jak převezme most, zasazuje poškozené, cizí, prázdné a opuštěné leasy a sleduje, jak jsou převzaty, spouští dva klienty ve stejném okamžiku, činí adresář leasů nezapisovatelným a sleduje, jak je klient obsluhován sám, posílá SIGTERM a zjišťuje, že lease zmizel, hází malformovaný provoz na /mcp a kontroluje, že přemostěná relace a restartovaný server odpovídají bajt po bajtu totéž co první server; test/cases/90_mcp_shared_server.sh spouští dva klienty přes bin/majordomus-mcp v repozitáři, který zapsal init shellového nástroje.