[BUG] Windows: Python-based MCP extensions fail to connect due to `uv` venv build race condition

Resolved 💬 2 comments Opened Mar 24, 2026 by tmcfarlane Closed Mar 27, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Bug Description

Python-based MCP extensions that use uv to manage their virtual environment fail to connect on Windows due to a race condition between venv creation and server connection. Claude Desktop launches uv run to start the MCP server, then immediately attempts to initialize the MCP handshake while uv is still installing packages into the .venv. This causes file locks (OS error 32) that crash the install, which crashes the server, which triggers a retry — creating an infinite failure loop.

Environment

  • OS: Windows 10/11
  • Claude Desktop version: v1.1.7714.0 (Windows Store)
  • Extension: Windows-MCP (ant.dir.cursortouch.windows-mcp) — but likely affects all uv-based Python extensions
  • Python: CPython 3.13.12
  • uv: Installed at C:\Python38\Scripts\uv.exe

Expected Behavior

The extension should connect successfully after uv finishes building the virtual environment.

Actual Behavior

Claude Desktop sends the MCP initialize message while uv is still installing packages. The partially-started server process locks files in the .venv directory. When uv tries to complete installation (specifically replacing directories like ipykernel-7.2.0.data or pywin32-311.data), it fails with:

error: Failed to install: ipykernel-7.2.0-py3-none-any.whl (ipykernel==7.2.0)
  Caused by: failed to remove directory `...\ant.dir.cursortouch.windows-mcp\.venv\Lib\site-packages\ipykernel-7.2.0.data`: The process cannot access the file because it is being used by another process. (os error 32)

The server then disconnects, Claude Desktop retries, and the cycle repeats indefinitely. Each retry hits the same locked files from the previous failed attempt.

Additional observation: uv not on PATH

On the first several attempts, Claude Desktop tried to invoke uv as a bare command, which failed with 'uv' is not recognized as an internal or external command. It eventually resolved to the full path C:\Python38\Scripts\uv.exe, but this added extra failed cycles before the real issue (the race condition) could even surface.

Workaround

The following manual workaround resolves the issue:

  1. Fully quit Claude Desktop
  2. Kill any lingering Python/uv processes
  3. Delete the corrupted venv:

``powershell
Remove-Item -Recurse -Force "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp\.venv"
``

  1. Pre-build the venv manually before launching Claude Desktop:

``powershell
cd "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp"
C:\Python38\Scripts\uv.exe run windows-mcp --help
``

  1. Wait for the full install to complete (113 packages), then reopen Claude Desktop

This works because uv builds the venv without Claude Desktop racing to connect mid-install.

Suggested Fix

Claude Desktop should wait for uv to signal that the server is actually ready before sending the MCP initialize message. Possible approaches:

  • Wait for stdout/stderr signal: Don't send initialize until the child process emits a ready indicator (e.g., the MCP server's own startup log line)
  • Retry with backoff on venv builds: If the extension directory contains a pyproject.toml and no .venv, assume first-run setup and allow longer startup time before attempting the handshake
  • Pre-build step: Run uv sync or equivalent as a separate step before launching the server, so the server process starts with a fully-built venv

What Should Happen?

The extension should connect successfully after uv finishes building the virtual environment.

Error Messages/Logs

## Relevant Logs

<details>
<summary>Extension log showing the race condition loop</summary>


2026-03-24T14:03:28.030Z [Windows-MCP] [info] Server started and connected successfully
2026-03-24T14:03:28.031Z [Windows-MCP] [info] Client transport closed
2026-03-24T14:03:28.031Z [Windows-MCP] [info] Server transport closed (intentional shutdown)
...
Using CPython 3.13.12 interpreter at: C:\Users\<username>\AppData\Local\Programs\Python\Python313\python.exe
Creating virtual environment at: .venv
   Building windows-mcp @ file:///...
      Built windows-mcp @ file:///...
error: Failed to install: pywin32-311-cp313-cp313-win_amd64.whl (pywin32==311)
  Caused by: failed to remove directory `...\.venv\Lib\site-packages\pywin32-311.data`: The process cannot access the file because it is being used by another process. (os error 32)
2026-03-24T14:03:39.255Z [Windows-MCP] [info] Server transport closed


</details>

Steps to Reproduce

Steps to Reproduce

  1. Install a Python-based MCP extension that uses uv (e.g., Windows-MCP)
  2. Enable the extension in Claude Desktop on Windows
  3. Observe repeated connection failures in the extension logs

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

  • Claude Desktop version: v1.1.7714.0 (Windows Store)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

Workaround

The following manual workaround resolves the issue:

  1. Fully quit Claude Desktop
  2. Kill any lingering Python/uv processes
  3. Delete the corrupted venv:

``powershell
Remove-Item -Recurse -Force "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp\.venv"
``

  1. Pre-build the venv manually before launching Claude Desktop:

``powershell
cd "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp"
C:\Python38\Scripts\uv.exe run windows-mcp --help
``

  1. Wait for the full install to complete (113 packages), then reopen Claude Desktop

This works because uv builds the venv without Claude Desktop racing to connect mid-install.

Suggested Fix

Claude Desktop should wait for uv to signal that the server is actually ready before sending the MCP initialize message. Possible approaches:

  • Wait for stdout/stderr signal: Don't send initialize until the child process emits a ready indicator (e.g., the MCP server's own startup log line)
  • Retry with backoff on venv builds: If the extension directory contains a pyproject.toml and no .venv, assume first-run setup and allow longer startup time before attempting the handshake
  • Pre-build step: Run uv sync or equivalent as a separate step before launching the server, so the server process starts with a fully-built venv

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗