1.2.0
Migrates to the mcp 2.x server API. Closes #27.
Upgrading
Nothing to do — the MCP tools and their arguments are unchanged. In proxy mode the server restarts itself on the version change.
mcp>=2.0.0,<3 is now required. 1.1.0 capped mcp at <2 as a stopgap because mcp 2.0 removed mcp.server.fastmcp; this release moves to the new API properly.
Slow tools no longer block the server
mcp 1.x invoked sync tool functions directly on the asyncio event loop, one at a time, which is why a single slow operation could stall everything — the complaint behind #25. mcp 2.x dispatches them on worker threads, so tools run in parallel:
pings served while a recall was in flight: 6244
That property is now structural rather than something Exocortex has to maintain.
The part that needed care
Parallel dispatch made several check-then-write guards reachable for the first time. exo_link_memories reads "does this link already exist?" before creating it; under 1.x nothing could interleave between those two statements, under 2.x it can. Eight concurrent identical calls produced four duplicate links.
Database-touching tools are now serialized with an operation-level lock, restoring the guarantee those guards were written against while leaving the event loop free. KùzuDB permits a single writer anyway, so little is given up. exo_ping is deliberately excluded — it never touches the database, and involving the manager would load the embedding model just to answer a health check.
Verified after the fix: eight concurrent exo_link_memories → exactly one link.
Reproducible builds
uv.lock is now committed, and mcp carries a <3 cap.
An unpinned dependency with no lockfile is what let an upstream major release break every fresh install and all of CI with no change in this repository — and it went unnoticed because main had not run CI in months. The lock also pins ruff, whose newer releases began formatting Python inside Markdown code fences and failing lint on untouched files.
The lock covers CI and local development; uvx --from git+... resolves from package metadata, so the version specifiers are what protect end users from the next major bump.
Verification
331 tests pass on Python 3.10, 3.11 and 3.12 against mcp 2.0.0. The new concurrency guard was mutation-tested: removing the serialization makes it fail with six duplicate links.
Full Changelog: 1.1.0...1.2.0