Metadata-Version: 2.4
Name: warmcp
Version: 0.1.0
Summary: Warm-start MCP launcher that hot-swaps its tool list to survive Windows cold-start timeouts
Author-email: Newton Winter <isoutthere@gmail.com>
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: fastmcp>=3.4.2
Description-Content-Type: text/markdown

# warmcp (POC)

Proof-of-concept for surviving the **~60s hard MCP startup timeout** Claude
Desktop applies on Windows. A server launched as `uvx some-pkg@latest` can
exceed that budget just downloading/building deps on a cold start, and the
client kills it before it serves a single tool.

The intended fix is a thin proxy that:

1. launches **instantly** and exposes a stub `mcp_status` tool,
2. boots the real (slow) server in the background, and
3. once ready, **swaps in the real tools** and emits
   `notifications/tools/list_changed` so the client re-reads `tools/list`.

This is all standard MCP — the server advertises `tools.listChanged` and
sends the list-changed notification. **This repo validates only that
mechanism.** It does not proxy anything yet.

## What it does

- Starts immediately with one tool: `mcp_status` (reports "loading" + seconds
  left).
- After `WARMCP_SWAP_DELAY` seconds (default **60**), removes the stub,
  registers `tool_a` + `tool_b`, and notifies the client.

If the client picks up `tool_a`/`tool_b` without a reconnect, the standard
works and the proxy approach is viable. If not, scrap it.

## How the swap is wired (FastMCP specifics)

- FastMCP advertises `tools.listChanged` automatically, but `add_tool` /
  `remove_tool` do **not** emit the notification — we send it explicitly via
  `ctx.session.send_tool_list_changed()`.
- The notification needs a live session, and the swap fires outside any
  request. `SwapTimerMiddleware.on_list_tools` grabs the session on the
  client's first `tools/list` (sent right after `initialize`) and starts a
  one-shot timer.

## Run the automated test

```bash
uv sync
uv run pytest -s          # spawns the server over real stdio, asserts the swap
```

The test sets `WARMCP_SWAP_DELAY=3` so it finishes in a few seconds.

## Validate manually in Claude Desktop

Add to `claude_desktop_config.json` (use a short delay so you don't wait a
full minute):

```json
{
  "mcpServers": {
    "warmcp-poc": {
      "command": "uvx",
      "args": ["warmcp@latest"],
      "env": { "WARMCP_SWAP_DELAY": "10" }
    }
  }
}
```

Or run from a local checkout instead of PyPI:

```json
{
  "mcpServers": {
    "warmcp-poc": {
      "command": "uv",
      "args": ["run", "--directory", "C:\\path\\to\\warmcp", "warmcp"],
      "env": { "WARMCP_SWAP_DELAY": "10" }
    }
  }
}
```

Restart Claude Desktop. Initially only `mcp_status` should be listed; ~10s
later the tool list should refresh to `tool_a` + `tool_b` **without** a
reconnect. That refresh is the signal the proxy plan is sound.
