Přeskočit na obsah

Tato stránka byla automaticky přeložena z angličtiny, jediného jazyka, ve kterém se tento web píše. Číst originál.

Jeden sdílený server MCP na repozitář, peerové a klienti, kteří jej spouštějí sami

Jeden sdílený server MCP na repozitář, peerové a klienti, kteří jej spouštějí sami

majordomus://adr/adr-0003přijato mcpsouběžnostarchitektura

odkazuje na

Nic. Tento objekt nedeklaruje žádný odkaz.

odkazuje na něj

3. Jeden sdílený MCP server na repozitář, peery a klienti, kteří jej spouštějí sami

Rozšiřuje ADR 1 a ADR 2.

Kontext

ADR 1 učinilo z majordomus mcp proces na klienta: jen stdio, žádný port, mrtvý s rourou. ADR 2 přidalo serve, druhý příkaz se stejným registrem na loopback socketu, včetně Swagger UI. Operátor pak požádal o čtyři věci v tomto pořadí: Swagger UI má startovat s majordomus mcp ve výchozím stavu a jeho URL má být v logu; MCP klient (Claude Code, Codex, Gemini CLI, ...) otevřený v repozitáři má server sestavit, spustit a použít bez ručního kroku; v repozitáři má běžet právě jeden server a nechat různé klienty koordinovat hned po instalaci; a justfile má směrovat to, co člověk spouští, na Rust executable všude, kde to zvládne.

Dva nebo tři klienti MCP otevření v jednom checkoutu jsou nyní běžný případ, ne výjimka. Každý spouští vlastní proces stdio, takže „jeden server“ nemůže znamenat „jeden proces na klienta“: znamená, že první proces obsluhuje a ostatní se k němu připojí. Seznam „Intentionally Absent“ repozitáře odmítá démony, servery, fronty a registry pracovníků; níže uvedené rozhodnutí na něj musí odpovědět řádek po řádku, jako ADR 1.

Rozhodnutí

  • Jeden sdílený server na repozitář, vlastněný tím, kdo ho spustil. První majordomus mcp (nebo serve) v repozitáři naváže loopback HTTP projekci (Swagger UI na /docs, /openapi.json, každá trasa schopnosti a MCP přes HTTP na /mcp) vedle své vlastní stdio relace a zaloguje URL. Skončí, když zmizí jeho vlastní klient a odejde poslední připojený peer. Neexistuje proces bez klienta.
  • Lease, ne démon. Server se nachází přes jediný soubor, .ai/local/state/mcp/server.json, v polovině lokální pro checkout, kterou vrstva už vyhrazuje pro provozní stav: vytvoří ho atomicky proces, který vyhraje, nese URL, jakmile je navázáno, a odstraní se, když server skončí. Lease, jehož server pro tento kořen neodpovídá, je zastaralý a převezme se. Nic jiného se nikam nezapisuje; --inspect a --standalone nezapisují vůbec nic.
  • Každý další majordomus mcp je most. Nenese žádný index ani registr: přeposílá rámce svého klienta na /mcp serveru a posílá ping, aby jeho relace zůstala zachována. Když jeho server zanikne, zvolí znovu a buď převezme roli (a přenese initialize svého klienta, takže si klient ničeho nevšimne), nebo se připojí k tomu, kdo ji převzal.
  • MCP přes HTTP je požadavková polovina transportu Streamable HTTP, na /mcp, s hlavičkou Mcp-Session-Id, DELETE pro ukončení relace a klidovým vypršením. Žádný proud iniciovaný serverem: tento server neposílá žádná oznámení, takže by proud nenesl nic. Klient, který transport mluví sám, je peer jako kterýkoli most.
  • Peeři jsou schopnosti registru. peers.list a peers.announce jsou typované deskriptory v builtin.rs s explicitními expozicemi (nástroje majordomus_peers a majordomus_announce, GET /api/v1/peers, POST /api/v1/peers/announce), promítnuté jako každá jiná schopnost; nic v kódu MCP ani HTTP o peerech neví. Peer je relace pojmenovaná tím, co klient řekl v initialize; ohlášení je jeden řádek záměru a cest, kterých se peer chystá dotknout, informativní, v paměti serveru, zmizí s procesem. Instrukce initialize jmenují URL serveru, vlastní id peera volajícího a každého dalšího peera, takže se klient o ostatních dozví před svým prvním voláním nástroje.
  • Třetí druh schopnosti, command. Dva druhy v ADR 2 byly query (provedena, jen pro čtení) a resource (čtení). peers.announce je provedena a mění paměť tohoto procesu, takže je to command: vázaná na POST a klientům MCP oznamovaná jako ne jen pro čtení, obojí odvozeno z druhu kontrolami registru, ne deklarováno na projekci. Žádný druh nezapisuje do repozitáře.
  • Klienti ho spouštějí. bin/majordomus-mcp sestaví spustitelný soubor, když chybí nebo je starší než jeho zdroje (nikdy když to řekne MAJORDOMUS_BIN nebo MAJORDOMUS_NO_BUILD), nastaví adresář share a exec majordomus mcp, bez zápisu na stdout. Kořen nese .mcp.json (Claude Code), .gemini/settings.json (Gemini CLI) a .codex/config.toml (Codex), každý jmenující tento launcher; který klient otevře první, stane se serverem, a ostatní se připojí.
  • justfile v kořeni směruje na Rust executable každý recept, který umí obsloužit (mcp, serve, inspect, capabilities, describe, validate, generate, generate-check, měření výkonu, pokrytí) a recepty životního cyklu nechává shell nástroji. Je tenký z podstaty: každý recept jmenuje skript nebo příkaz, který chování vlastní.

Vůči seznamu „Intentionally Absent“, bod po bodu

seznam odmítátoto rozhodnutí
démon, server, monitor na pozadísdílený server je potomek klienta, který se zdržuje, jen dokud je připojen jiný klient, a končí s posledním; nic ho nespouští kromě klienta, nic ho nedrží naživu kromě klientů a --standalone ho odstraní úplně
databáze, fronta, vektorové úložištějeden JSON soubor leasu v lokální polovině, při ukončení odstraněný; nástěnka peerů je paměť jednoho procesu
registr nebo katalog pojmenovaných pracovníkůnástěnka uvádí živé relace pod jménem, které klient sám poslal, nic podle něj nesměruje, nepřiděluje žádnou roli, úroveň ani personu, nic neukládá a nelze ji upravit; je to stejný druh faktu jako zpráva o překryvu: kdo je tu právě teď
nález bez příkazu reprodukcezastaralý lease, obsazený port, převzetí a nezdařené převzetí se každé loguje s URL nebo důvodem; GET /api/v1/peers a majordomus_peers reprodukují nástěnku
vlastní hlášení, kterému se věří bez nezávislé kontrolytests/mcp_shared.rs spouští procesy a mluví s nimi přes skutečné roury a sockety, zabije server a sleduje, jak most přebírá; test/cases/90_mcp_shared_server.sh to dělá přes launcher v repozitáři, který init zapsal
číslo napsané tam, kde by ho mohl spočítat příkazkaždý počet (peerů, relací, rout) se počítá; měření výkonu nic nehlásí ani netvrdí

Invarianty

  1. Za každý kořen repozitáře odpovídá nejvýše jeden server; druhý proces ho najde přes lease nebo převezme zastaralý, nikdy se nenaváže vedle něj.
  2. Stdio relace klienta přežije smrt svého serveru, když vrstvu může obsloužit jakýkoli proces; když žádný nemůže, klient dostane chybu JSON-RPC, která jmenuje důvod, nikdy ticho.
  3. Stdio relace vlastníka neplatí za stranu HTTP nic: workeři jsou samostatná vlákna nad neměnným registrem; benches/shared.rs měří totéž volání s navázaným a nečinným serverem proti žádnému serveru.
  4. Peery jsou projekce registru jako všechno ostatní; druh rozhoduje o metodě HTTP a anotacích MCP.
  5. Žádný režim nezapisuje nic pod sledovaný strom repozitáře; lease žije tam, kam kontrakt vrstvy už dává provozní stav.

Dodatek, 2026-09-05: nic zanechaného nezamyká klienta venku

Adversariální sondy první implementace našly dva způsoby, jak klient nedostane žádný server: lease soubor, který nebyl dokumentem lease, způsobil, že každé majordomus mcp skončilo, a adresář lease, který odmítal zápis, totéž. Byly přidány tři invarianty; jsou to doktrína project.shared-server-resilience, prokázaná tests/mcp_shared.rs a test/cases/90_mcp_shared_server.sh a uplatňovaná jako mcp-lease-resilience:

  1. Ať lease soubor po pádu, zabití nebo zkopírovaném checkoutu obsahuje cokoli, další proces ho převezme a pojmenuje, co našel; volba je časově omezená.
  2. Proces, který nemůže sdílet (lease nelze zapsat ani nahradit, server nelze spustit), obslouží samotného svého klienta, jako to dělá --standalone, a řekne proč; klienta odmítnou jen vlastní chyby vrstvy.
  3. SIGTERM, SIGINT a SIGHUP odstraní lease dříve, než proces na signál zemře; kill -9 nechá zastaralý lease pro další proces, což je invariant 6.

Zamítnuté alternativy

  • Démon nebo systémová služba. Seznam to odmítá a je to zbytečné: server, který končí s posledním klientem, odpovídá na operátorovo „vždy právě jeden“.
  • Jeden server na klienta na odlišných portech. Každý klient by měl vlastní Swagger UI a žádný by neviděl ostatní; „jeden server“ byl požadavek.
  • Unix socket nebo soubor pod /tmp jako rendezvous. Vrstva už má pro přesně tuto třídu stavu lokální polovinu checkoutu, po worktree, a lease si člověk přečte pomocí cat.
  • Booleovské read_only na deskriptoru místo druhu: kontroly tvaru registru, metoda HTTP a anotace by se na něj musely dotazovat každá zvlášť; druh nese sémantiku jednou.
  • Ponechat vlastní index mostu, aby se --strict a --discovery uplatňovaly na klienta: most by pak startoval stejně pomalu jako server pro nic; volby serveru se uplatní na relaci, log to říká a peer, který nemůže obsluhovat vrstvu s vlastními volbami, to řekne, když je požádán o převzetí.
  • SDK pro MCP nebo crate HTTP klienta pro most: jeden loopback požadavek na zprávu je třicet řádků nad TcpStream a server vždy odpovídá Content-Length.
  • Nechat shellový nástroj dispečovat mcp, serve, capabilities a generate v této změně: na master je dispečovaný příkaz veřejný příkaz s položkou v registru, fixturou a pokrytím (share/commands.yaml); to je změna plochy shellového nástroje a přistane jako vlastní krok poté, co se tato větev rebasuje na ni. Do té doby jsou vstupními body bin/majordomus-mcp a justfile.

Důsledky

Soubor lease, jeho schéma, koncový bod /mcp, hlavička relace, schopnosti peerů a druh command se stávají povrchy kompatibility. Dlouho žijící sdílený server si ponechává index, který sestavil při startu; klient, který se připojí později, vidí vrstvu, jaká byla tehdy, což je znovuobjevení založené na restartu, které ADR 2 už učinilo kontraktem, a server skončí, když odejde poslední klient. Dokumenty, které říkaly „jeden proces na klienta, žádný port“, nyní říkají „jeden server na repozitář, vlastněný svými klienty“ a docs/MCP.md nese životní cyklus.

Strategie testování

Nejprve black-box: tests/mcp_shared.rs spouští binárku jako vlastníka, most a přímého HTTP klienta, přes skutečné roury a skutečný socket, a pokrývá lease, záložní port, odkládání serve, --standalone, převzetí po zabití, opětovné připojení, když lease získal jiný proces, a odmítnutí, když převzímající nemůže vrstvu servírovat; tests/shared_units.rs pokrývá nástěnku, lease, relace koncového bodu a expiraci, klienta mostu a smyčku stdio v procesu; benches/shared.rs měří cesty, o jejichž optimalizaci provozovatel požádal; test/cases/90_mcp_shared_server.sh spouští launcher a dva klienty v repozitáři, který napsal init shellového nástroje, a kontroluje konfigurace klientů. Kontroly ADR 2 jsou beze změny.

Odkud to pochází

kanonický soubor
.ai/repo/adrs/0003-shared-mcp-server-peers-and-client-autostart.md
identity
adr-0003
dostupné také jako
Zdroj MCP majordomus://adr/adr-0003 · majordomus entity show adr/adr-0003 · GET /api/v1/entity?uri=majordomus://adr/adr-0003
v Cockpitu
/cockpit/objects/adr/adr-0003

Tato stránka je generována z výše uvedeného souboru pomocí scripts/generate-site-data; úprava stránky nic nemění, úprava souboru změní všechna rozhraní. Výše uvedené vztahy jsou hrany docs/generated/graph.json, které spustitelný program zapisuje ze stejného indexu.

Prohledává názvy a popisy všech stránek, které tento web publikuje.