Skip to content

mm uninstall liveness check only sees MCP server pid — silently ignores mm web and other DB writers #384

@memtomem

Description

@memtomem

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:

  1. 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.

  2. 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.

  3. 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:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions