Problem
mm uninstall (shipped in v0.1.23, #379) refuses to proceed when it detects a running server — good design, protects against deleting SQLite out from under a live WAL handle. The liveness probe is os.kill(pid, 0) against ~/.memtomem/.server.pid.
Gap: .server.pid is written by the MCP memtomem-server entrypoint only. Every other process that can hold a live handle on ~/.memtomem/memtomem.db is invisible to the check:
mm web (FastAPI uvicorn) — no pid file
mm watchdog long-running checks — no pid file
- Ad-hoc
sqlite3 connections, user scripts, test harnesses — no pid file
Result: liveness check false-negatives, mm uninstall proceeds without --force, DB file is unlinked while another process is still writing to it. On POSIX this doesn't surface immediately (the other process keeps writing to the unlinked inode), so the uninstall reports success and the user has no signal that anything went wrong — until a re-install inherits a state that doesn't match the live writer's view.
Reproduction (observed 2026-04-22)
# Terminal A — start mm web against the default DB
mm web & # PID 74828, opens ~/.memtomem/memtomem.db
# Terminal B — run uninstall without --force
mm uninstall -y
# Output:
# memtomem state inventory:
# Database ~/.memtomem/memtomem.db 200.0 KB
# ...
# Removed: config.json, database, state dir.
#
# No warning. No refusal. No `--force` required.
# DB file is gone, but mm web (PID 74828) still holds the inode.
ls -la ~/.memtomem # -> No such file or directory
ps -p 74828 # -> still running, still writing
The .server.pid file was absent throughout — mm web doesn't write one.
Suggested directions
Pick one or combine:
-
Extend pid-file scheme to all long-lived entrypoints. Every process that holds a DB connection for more than one request writes ~/.memtomem/.<name>.pid at startup, removes it on clean shutdown. mm uninstall scans ~/.memtomem/.*.pid. Simple, but requires discipline in every entrypoint forever.
-
Fall back to lsof / fuser when .server.pid is absent or stale. Platform-specific but reliable for any process that actually has the file open. lsof -t ~/.memtomem/memtomem.db returns PIDs.
-
Try a BEGIN IMMEDIATE write lock on the DB with a short busy_timeout. If another process holds a write lock, you get SQLITE_BUSY and can refuse cleanly. Platform-independent, reasoning-from-semantics rather than scanning process tables.
My preference: (3) as the primary check (captures any writer regardless of how it was launched), keep .server.pid as a fast-path / hint for the error message ("looks like memtomem-server PID X is holding the lock").
Severity
High — silent data-corruption path triggered by the documented uninstall command. The current --force flag exists precisely to let the user override refusals, so a working liveness check is load-bearing.
Context
Discovered during a first-time-user smoke test of v0.1.23, 2026-04-22. See also:
Problem
mm uninstall(shipped in v0.1.23, #379) refuses to proceed when it detects a running server — good design, protects against deleting SQLite out from under a live WAL handle. The liveness probe isos.kill(pid, 0)against~/.memtomem/.server.pid.Gap:
.server.pidis written by the MCPmemtomem-serverentrypoint only. Every other process that can hold a live handle on~/.memtomem/memtomem.dbis invisible to the check:mm web(FastAPI uvicorn) — no pid filemm watchdoglong-running checks — no pid filesqlite3connections, user scripts, test harnesses — no pid fileResult: liveness check false-negatives,
mm uninstallproceeds without--force, DB file is unlinked while another process is still writing to it. On POSIX this doesn't surface immediately (the other process keeps writing to the unlinked inode), so the uninstall reports success and the user has no signal that anything went wrong — until a re-install inherits a state that doesn't match the live writer's view.Reproduction (observed 2026-04-22)
The
.server.pidfile was absent throughout —mm webdoesn't write one.Suggested directions
Pick one or combine:
Extend pid-file scheme to all long-lived entrypoints. Every process that holds a DB connection for more than one request writes
~/.memtomem/.<name>.pidat startup, removes it on clean shutdown.mm uninstallscans~/.memtomem/.*.pid. Simple, but requires discipline in every entrypoint forever.Fall back to
lsof/fuserwhen.server.pidis absent or stale. Platform-specific but reliable for any process that actually has the file open.lsof -t ~/.memtomem/memtomem.dbreturns PIDs.Try a
BEGIN IMMEDIATEwrite lock on the DB with a shortbusy_timeout. If another process holds a write lock, you getSQLITE_BUSYand can refuse cleanly. Platform-independent, reasoning-from-semantics rather than scanning process tables.My preference: (3) as the primary check (captures any writer regardless of how it was launched), keep
.server.pidas a fast-path / hint for the error message ("looks likememtomem-serverPID X is holding the lock").Severity
High — silent data-corruption path triggered by the documented uninstall command. The current
--forceflag exists precisely to let the user override refusals, so a working liveness check is load-bearing.Context
Discovered during a first-time-user smoke test of v0.1.23, 2026-04-22. See also:
uvx --from memtomem memtomem-serververify command is misleading and has hidden side effect #381 (docs: verify command side effects)mm statusto mirror the MCPmem_statustool (no CLI equivalent today) #382 (CLI: missingmm status)serverInfo.versionreports SDK version (1.27.0) instead ofmm --version(0.1.23) #383 (MCP serverInfo.version mismatch)