What Changed
This release resolves two production-quality issues in SqliteVecMemoryStorage that were exposed under concurrent async load.
Changed
-
Wrap all remaining direct SQLite calls in
_execute_with_retry(#663, fixes #637): Eliminated ~119 directself.conn.execute()/executemany()/commit()calls in async methods. All DB operations now run viaasyncio.to_thread()through_execute_with_retry, preventing up to 15-second event-loop freezes under concurrent load (busy_timeout=15000WAL mode).Key correctness guarantees introduced vs the community attempt (PR #654):
- Cursor thread-safety: all
fetchall()/fetchone()/rowcountaccesses moved inside closures, never accessed afterawait asyncio.to_thread() - DDL idempotency:
ALTER TABLE ADD COLUMNguarded byPRAGMA table_info()check; re-entrant on retry is safe _savepoint_lock(asyncio.Lock) added to serializestore()/store_batch()/evolve_memory()SAVEPOINT sections at the coroutine level without blocking the event loop- Unique SAVEPOINT names (
store_<hex>,batch_<hex>,evolve_<hex>) to prevent name collision
- Cursor thread-safety: all
Fixed
_record_conflictssilent data loss (#663):_record_conflictswas writing conflict tags and graph edges inside_execute_with_retrythreads but never calledself.conn.commit(), causing all conflict data to be silently discarded. Fixed by addingself.conn.commit()inside the_record_all_conflictsclosure.store_batchouter-scope mutation (#663):batch_insertclosure now returns its results list instead of mutating an outer-scope variable.
Upgrade
Drop-in upgrade — no breaking changes, no migration required.
pip install --upgrade mcp-memory-service
# or
uv add mcp-memory-service==10.33.0Stats
- 1,520 tests passing
- Resolves issue #637
Full Changelog
See CHANGELOG.md for complete details.