Skip to content

Concurrent MCP sidecars can permanently drop a workspace from the registry #26

Description

@anbturki

Code analysis only: confirmed by reading the code, not reproduced live. Filed for completeness after the v0.9.1 sync work.

Problem

Registry writes are neither atomic nor serialized, so a concurrent registration can be lost permanently.

upsert_workspace (src-tauri/core/src/workspace/registry.rs:56-61) is an unlocked read-modify-write:

let mut workspaces = load_registry(file)?;
workspaces.retain(|w| w.path != entry.path);
workspaces.push(entry);
save_registry(file, &workspaces)

save_registry then writes with a plain std::fs::write (registry.rs:51), truncating in place rather than writing a temp file and renaming.

Two consequences:

  1. Lost workspace (permanent). Multiple MCP sidecars run concurrently, one per agent session. If two call init_workspace at the same time, both read the same registry, and the second write clobbers the first entry. That workspace never appears in the GUI, and nothing retries, because as far as the agent is concerned the registration succeeded.
  2. Torn read (transient). A reader can observe a partially written file. The GUI's reconcile logs the parse error and returns, so the workspace stays unlisted until the next focus reconcile. Self-correcting, but it means a legitimate write can be invisible for a while.

The same non-atomic std::fs::write pattern is used for doc, task, and memory writes; those are self-correcting on the next scan, so this issue is scoped to the registry, where the loss is permanent.

Proposed fix

Write via temp file plus std::fs::rename in save_registry (rename is atomic on the same filesystem, which fixes the torn read), and guard the read-modify-write in upsert_workspace with an advisory file lock so concurrent sidecars serialize instead of clobbering.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions