Skip to content

Concurrent server launches race on a shared .permission_test file → false "Cannot write to credentials directory" and fatal sys.exit(1) #937

Description

@bjarrin

Version: workspace-mcp 1.22.0
Transport: stdio, --single-user, local credential backend
OS: macOS

Summary

When two server instances start at (nearly) the same moment against the same credentials directory — which happens routinely when a host app spawns the stdio server more than once during startup — the credentials-directory permission check intermittently fails with Cannot write to existing credentials directory, and the losing instance calls sys.exit(1) and dies. The host surfaces this as a "Server disconnected" error even though a sibling instance started fine and works.

Root cause

check_credentials_directory_permissions() in core/utils.py write-tests the directory using a fixed filename:

test_file = os.path.join(credentials_dir, ".permission_test")
with open(test_file, "w") as f:
    f.write("test")
os.remove(test_file)

Two concurrent processes use the identical path, so they race: one process's os.remove() can fail because the other already removed the file (or the open/remove interleave), raising OSError/PermissionError. The directory is perfectly writable — it's purely a same-filename collision.

In main.py (local-backend branch, ~L780) that exception is fatal:

except (PermissionError, OSError) as e:
    ...
    logger.error(f"Failed credentials directory permission check: {e}")
    sys.exit(1)

(Note: the equivalent call in fastmcp_server.py catches the same exception and only logs it — it does not exit. The two call sites disagree on severity.)

Reproduction

  1. Launch two instances of the server concurrently pointing at the same credentials dir (e.g. host app double-spawns the stdio server on startup).
  2. Intermittently, one instance logs (paths redacted):
port_resolver - INFO  - <PID_A> - Port resolver: bound preferred port 8000
port_resolver - WARN  - <PID_B> - preferred port 8000 unavailable; falling back to 8001
main - ERROR - <PID_A> - Failed credentials directory permission check: Cannot write to existing credentials directory '~/.google_workspace_mcp/credentials'

<PID_A> exits; <PID_B> serves normally. Frequency observed: roughly a handful of times per week across daily restarts.

Suggested fix

Any one of these resolves it; ideally all three:

  1. Use a unique temp filename in the write-test so concurrent instances can't collide:
    import tempfile
    fd, test_file = tempfile.mkstemp(prefix=".permtest-", dir=credentials_dir)
    try:
        os.write(fd, b"test"); os.close(fd)
    finally:
        try: os.remove(test_file)
        except FileNotFoundError: pass
  2. Make cleanup tolerant — ignore FileNotFoundError on the os.remove.
  3. Don't hard-exit on this check in main.py; log a warning and continue (match fastmcp_server.py), since a benign concurrent launch shouldn't kill an otherwise-healthy server.

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