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
- Launch two instances of the server concurrently pointing at the same credentials dir (e.g. host app double-spawns the stdio server on startup).
- 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:
- 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
- Make cleanup tolerant — ignore
FileNotFoundError on the os.remove.
- 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.
Version: workspace-mcp 1.22.0
Transport: stdio,
--single-user, local credential backendOS: 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 callssys.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()incore/utils.pywrite-tests the directory using a fixed filename: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 theopen/removeinterleave), raisingOSError/PermissionError. The directory is perfectly writable — it's purely a same-filename collision.In
main.py(local-backend branch, ~L780) that exception is fatal:(Note: the equivalent call in
fastmcp_server.pycatches the same exception and only logs it — it does not exit. The two call sites disagree on severity.)Reproduction
<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:
FileNotFoundErroron theos.remove.main.py; log a warning and continue (matchfastmcp_server.py), since a benign concurrent launch shouldn't kill an otherwise-healthy server.