I built an MCP server that pulls my Oura Ring data into Claude Desktop. It's a small Python project with nine tools. The part that cost the most time wasn't the tools. It was the Python.

My Mac's system Python is 3.9.6. I ended up running the server on 3.12.

3.9 Gaps

Python 3.9 reached end of life on October 31, 2025, according to the Python developer guide. The MCP quickstart for Python says Python 3.10 or higher. The current pyproject for the MCP Python SDK says 3.11 or higher. Those two numbers obviously don't match, so check the requirement for the version you actually install.

Either way, 3.9 is below both. And 3.10 reached end of life on October 1, 2026, so I'd start from 3.12, which gets security fixes into October 2028.

T*he fix*

Leave the system Python alone. Install a current one next to it, then do three things.

Create a virtual environment with the new Python. Install your server's dependencies inside it. Then point Claude Desktop at that environment's interpreter, using absolute paths.

The config file lives at

~/Library/Application Support/Claude/claude_desktop_config.json 

on macOS. It looks like this:

json { "mcpServers": { "oura": { "command": "/Users/you/oura_mcp/.venv/bin/python", "args": ["/Users/you/oura_mcp/server.py"] } } } 

The MCP docs make the same point about uv. You may need the full path to the executable in the command field, and you need the absolute path to your server.

What Will break later

A freeCodeCamp guide on the "ENOENT" error explains a second trap. On macOS, a Homebrew Python upgrade or a brew cleanup can remove the old interpreter your virtual environment points to. The folder is still there, but the symlinks lead nowhere. The guide's most reliable fix is to delete the environment and rebuild it.

So, when a server that worked last month stops starting, check the interpreter before you check your code.

One more thing that looks like a Python problem

If your server talks to Claude Desktop over STDIO, a stray print() can break it. The MCP docs say never to write to stdout in a STDIO server, because it corrupts the JSON RPC messages. Use the standard logging module instead, which writes to stderr.

Do this first

Before you write the first tool, run python3 and read the version in the banner it prints. Write down which interpreter your config points to. Keep a one line note of how to rebuild the environment.

It's boring work, and that's why it bites. Nobody puts the Python version on the architecture diagram.