What it means
Open the repository in one MCP client and majordomus mcp is the server: its stdio serves that client, and beside it a loopback socket serves a home page listing every surface, this repository's documentation at /docs/, Swagger UI at /swagger, the OpenAPI document, every capability route and MCP over HTTP at /mcp; the URL and every surface are in the log the moment it is bound. Open the repository in a second client and its majordomus mcp does not start another server: it finds the first through the lease, checks that it answers for this root, and forwards its client's frames to it. Close the clients in any order and the server lingers exactly as long as one is attached; when the last leaves it closes the port and removes the lease. Kill the server and a bridged client takes its place, or attaches to whichever process took the lease first, and its own client never re-initialises. --standalone serves one client alone with no port and no lease.
How it works
src/lease.rs creates .ai/local/state/mcp/server.json atomically (the process that wins is the server), publishes the URL into it once the port is bound, probes a URL it finds against GET / and the repository root, and takes over a lease whose server does not answer; a file that is not a lease document, an empty one, or one whose owner published no URL within fifteen seconds is taken over as well, each named in the log, so that nothing a client leaves behind can lock the others out. When the file can neither be written nor replaced, src/commands/mcp.rs serves the client alone, as --standalone would, and says why. SIGTERM, SIGINT and SIGHUP remove the lease inside the handler before the process dies of the signal. src/shared.rs binds (--http-port, default 8741, a taken port replaced by a free one), starts the worker threads over the immutable registry, and waits for the attached sessions to leave before stopping. src/http/mcp.rs is MCP over HTTP: initialize answers with an Mcp-Session-Id, every later request carries it, DELETE ends the session, and an idle one expires. src/mcp/bridge.rs is the other side, one HTTP request per stdio message and a ping every twenty seconds; src/commands/mcp.rs holds the session that is either answered locally or bridged, and elects again when the bridge loses its server.
How to see it
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 goneWhat it does not cover
The server keeps the index it built at start; a client that attaches later sees the layer as it was then, and rediscovery is a restart (the server ends when the last client leaves). The server's --discovery and --strict apply to every session it serves. There is no server-initiated stream on /mcp, no notification, no subscription. The lease is per checkout: two worktrees have two servers. kill -9 cannot be caught, so it leaves the lease for the next process to take over; an HTTP client that leaves without DELETE /mcp keeps a server whose owner has already left alive for at most ninety seconds.
Why it exists
The operator asked for Swagger UI beside majordomus mcp by default, and for exactly one server per repository so that several clients (Claude, Codex, Gemini) share it and can coordinate. A daemon is refused by the design; a server that is a client's child and ends with the last client answers both asks. The decision and its answer to the "Intentionally Absent" list are .ai/repo/adrs/0003-shared-mcp-server-peers-and-client-autostart.md. apps/majordomus-cli/tests/mcp_shared.rs spawns the processes and speaks to them over real pipes and sockets, kills the server and watches the bridge take over, plants corrupt, foreign, empty and abandoned leases and watches them being taken over, starts two clients in the same instant, makes the lease directory unwritable and watches the client being served alone, sends SIGTERM and finds the lease gone, throws malformed traffic at /mcp, and checks that a bridged session and a restarted server answer byte for byte what the first server did; test/cases/90_mcp_shared_server.sh runs two clients through bin/majordomus-mcp in a repository the shell tool's init wrote.