| layout | default |
|---|---|
| title | Chapter 4: Runtime, Dependencies, and uv Packaging |
| nav_order | 4 |
| parent | Create Python Server Tutorial |
This chapter covers the uv-based dependency and packaging model for generated MCP servers: how dependencies are declared, how lockfiles maintain reproducibility, and how to build and publish a server as a standalone Python package.
- Manage dependencies with
uvconventions in generated projects - Run generated servers in development and published modes
- Keep lockfiles and build artifacts reproducible across environments
- Avoid environment drift across contributors and CI systems
Generated MCP servers use uv as the complete Python toolchain — environment manager, package manager, and build tool. This eliminates the pip + virtualenv + poetry + twine fragmentation common in Python projects.
graph LR
UV[uv toolchain]
UV --> SYNC[uv sync\nCreate .venv, install deps from lock]
UV --> RUN[uv run server-name\nRun in managed .venv]
UV --> BUILD[uv build\nCreate wheel + sdist in dist/]
UV --> PUBLISH[uv publish\nUpload to PyPI or private registry]
UV --> ADD[uv add package\nAdd dep + update lock]
The generated pyproject.toml uses the hatchling build backend (the default for uv init):
[project]
name = "my-notes-server"
version = "0.1.0"
description = "A simple MCP server for managing notes"
readme = "README.md"
requires-python = ">=3.10"
dependencies = ["mcp>=1.0.0"]
[project.scripts]
my-notes-server = "my_notes_server:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"Key constraints:
requires-python = ">=3.10"— themcpSDK requires Python 3.10+ for union type syntax (X | Y)mcp>=1.0.0— unpinned upper bound; updates get new SDK versions onuv sync[project.scripts]entry enablesuvx my-notes-serverwithout explicit path management
flowchart TD
EDIT[Edit server.py]
EDIT --> SYNC[uv sync\ninstall or refresh deps]
SYNC --> TEST[Test with Inspector:\nnpx @modelcontextprotocol/inspector\nuv --directory . run my-notes-server]
TEST --> VERIFY[Verify tool calls\nresource list\nprompt rendering]
VERIFY --> EDIT
# Full development cycle
# 1. Install / refresh dependencies
uv sync --dev --all-extras
# 2. Run server directly (stdio — useful for pipes)
uv run my-notes-server
# 3. Run in Inspector for interactive testing
npx @modelcontextprotocol/inspector uv --directory /path/to/my-notes-server run my-notes-server
# 4. Add a new dependency
uv add requests
uv add --dev pytestuv.lock pins every transitive dependency to an exact version and hash. This is committed to source control to ensure every environment gets identical packages:
# After anyone adds/removes a dependency, commit the updated lock file
git add uv.lock pyproject.toml
git commit -m "deps: add requests for HTTP resource fetching"If a contributor runs uv sync without updating the lock, they get the locked versions — not the latest. To upgrade dependencies:
# Upgrade all dependencies within pyproject.toml constraints
uv lock --upgrade
# Upgrade a specific package
uv lock --upgrade-package mcp# Build wheel and source distribution
uv build
# Output: dist/my_notes_server-0.1.0-py3-none-any.whl
# dist/my_notes_server-0.1.0.tar.gzThe generated wheel includes only the src/ package — no test files, no development artifacts. hatchling reads the [build-system] config to determine what to include.
flowchart LR
SRC[src/my_notes_server/\n__init__.py · server.py]
TOML[pyproject.toml]
SRC --> BUILD[uv build]
TOML --> BUILD
BUILD --> WHEEL[dist/my_notes_server-0.1.0.whl]
BUILD --> SDIST[dist/my_notes_server-0.1.0.tar.gz]
WHEEL --> INSTALL[pip install / uvx install]
# Configure credentials (one-time)
export UV_PUBLISH_TOKEN=pypi-...
# Publish
uv publish
# Or publish with explicit credential flags
uv publish --token $PYPI_TOKENAfter publishing, any user can run your server with:
uvx my-notes-serverNo Python installation steps required — uvx handles environment creation transparently.
Update the version in pyproject.toml before each release:
[project]
version = "0.2.0"Semantic versioning conventions for MCP servers:
- Patch (0.1.x): bug fixes, no new tools/resources
- Minor (0.x.0): new tools, resources, or prompts added
- Major (x.0.0): breaking changes to tool signatures or removed primitives
| Python Version | Status | Notes |
|---|---|---|
| 3.9 | Not supported | mcp requires union syntax (X | Y) which needs 3.10+ |
| 3.10 | Minimum | Full support |
| 3.11 | Recommended | Better performance for async |
| 3.12+ | Supported | No known issues |
# Pin Python version for the project (creates .python-version file)
uv python pin 3.12Generated MCP servers are standard Python packages managed entirely by uv. The uv sync → uv run → uv build → uv publish pipeline handles the full lifecycle without touching pip or virtualenv directly. Commit uv.lock to ensure reproducibility. Use semantic versioning to signal breaking changes in tool signatures to downstream clients.
Next: Chapter 5: Local Integration: Claude Desktop and Inspector