Skip to content

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

Description

@tmcfarlane

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • 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:
    Remove-Item -Recurse -Force "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp\.venv"
  4. Pre-build the venv manually before launching Claude Desktop:
    cd "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp"
    C:\Python38\Scripts\uv.exe run windows-mcp --help
  5. 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:
    Remove-Item -Recurse -Force "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp\.venv"
  4. Pre-build the venv manually before launching Claude Desktop:
    cd "$env:APPDATA\Claude\Claude Extensions\ant.dir.cursortouch.windows-mcp"
    C:\Python38\Scripts\uv.exe run windows-mcp --help
  5. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidIssue doesn't seem to be related to Claude Code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions