Commit 2b2ca3c
[llm] mcp -sessions: one engine per agent behind one MCP server
`easycrypt mcp' is one engine with one proof state. An MCP client such
as Claude Code opens one stdio connection per configured server and
lets every agent it runs share it, and the transport carries no caller
identity, so two agents driving the server clobber each other's goals.
The only fix is at the protocol level: a `session' argument on every
tool, and one engine per session.
Not several EcLlmCore states in one process. The engine is
single-threaded, so one agent loading a large development would block
every other session; the loader cache, the prover configuration and
the Why3 processes are global; and a loaded engine holds memory that
only a process exit gives back. `mcp -sessions' therefore runs a
multiplexer instead of an engine: the first call naming a session
starts a child `easycrypt mcp' -- the single-engine server, unchanged,
launched from our own executable with our own arguments minus the
multiplexer's -- and every later call naming it is forwarded there.
The child's result or error comes back under the client's id.
`initialize', `ping' and `tools/list' are answered locally, under the
same server name, so a client's approval of the server carries over.
Requests run concurrently, one thread each; the threads do I/O and
JSON and nothing else. Three mutexes: one per child (a child is
synchronous, so calls to one session serialise), one for the client's
stdout, one for the session table. A new session's handshake runs
under its own lock, not the table's, so a second caller on that name
queues behind it rather than stalling everyone. A child that dies
under a call is dropped and the caller told so in a tool-level error
that says to `ec_load' again; a name closed and re-created while a
call on the old child was in flight is not taken down by that call.
Children must not outlive the multiplexer: `at_exit' and handlers for
SIGTERM, SIGINT and SIGHUP kill them, and under SIGKILL they read EOF
on their stdin and stop once their current command completes. SIGPIPE
is ignored, so a write to a dead child is an EPIPE we can report on
that session rather than a signal that takes the server down. Exited
children are reaped. Session names double as log-file names, hence a
restricted alphabet. An idle reaper kills sessions unused for `-idle'
minutes (default 180) that are not mid-call.
Two tools of the multiplexer's own, `ec_sessions' and `ec_close'. The
tool table with `session' added is a pure function of the existing
one and lives next to it, so the two cannot drift apart. `Wire', the
initialize reply and the stdout dup trick move to module level in
EcMcp so both servers share them; `wire_stdout' now dups close-on-exec,
so no process we start holds the client's pipe. The single-engine
server is otherwise untouched: the 18 MCP goldens, the parity check
and the 38 REPL goldens pass unchanged.
`scripts/testing/mcp-sessions' checks the contract, and `make test-mcp'
runs it. It is not a golden: the multiplexer answers in whatever order
the children finish, and pids and idle times are not reproducible. It
drives the server as a client would and asserts the tool table, two
sessions loading different files at once without seeing each other,
tool-level errors for a missing or invalid name against pass-through
protocol errors from the engine, ec_sessions/ec_close, an engine that
exited being reported dead and restarted by the next call, and no
child surviving end of input or SIGTERM.
doc/llm/CLAUDE.md gains "Multi-agent sessions" -- what `mcp -help'
prints -- with the rule for agents: one session name per agent, never
another's.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkdycFar1eka8ReJ9HeqZf1 parent 26de277 commit 2b2ca3c
13 files changed
Lines changed: 1120 additions & 86 deletions
File tree
- doc/llm
- scripts/testing
- src
- tests/mcp
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| |||
65 | 66 | | |
66 | 67 | | |
67 | 68 | | |
| 69 | + | |
68 | 70 | | |
69 | 71 | | |
70 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
170 | 170 | | |
171 | 171 | | |
172 | 172 | | |
173 | | - | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
174 | 176 | | |
175 | 177 | | |
176 | 178 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
457 | 457 | | |
458 | 458 | | |
459 | 459 | | |
| 460 | + | |
460 | 461 | | |
461 | 462 | | |
462 | | - | |
463 | | - | |
464 | | - | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
465 | 468 | | |
466 | 469 | | |
467 | 470 | | |
| |||
477 | 480 | | |
478 | 481 | | |
479 | 482 | | |
480 | | - | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
481 | 486 | | |
482 | 487 | | |
483 | 488 | | |
| |||
530 | 535 | | |
531 | 536 | | |
532 | 537 | | |
533 | | - | |
534 | | - | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
535 | 541 | | |
536 | 542 | | |
537 | 543 | | |
| |||
601 | 607 | | |
602 | 608 | | |
603 | 609 | | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
604 | 671 | | |
605 | 672 | | |
606 | 673 | | |
| |||
0 commit comments