# UV Running Python Scripts

Based on the official UV documentation for script execution, here's how `uv run python` works and why it's recommended for MCP servers.

## Key Benefits of `uv run python`

### Automatic Environment Management
- **No manual activation**: UV automatically creates and manages virtual environments
- **Dependency isolation**: Each script runs in its own isolated environment
- **Cross-platform**: Works consistently across macOS, Linux, and Windows

### Declarative Dependencies
Scripts can declare their dependencies inline using script metadata:

```python
# /// script
# dependencies = ["mcp[cli]>=1.9.2", "pydantic>=2.0.0"]
# ///

import mcp
# Script content here...
```

### Flexible Execution Options

```bash
# Basic script execution
uv run python script.py

# Add dependencies on-the-fly
uv run --with mcp[cli] python script.py

# Specify Python version
uv run --python 3.12 python script.py

# Use alternative package indexes
uv run --index-url https://custom.pypi.org/simple/ python script.py
```

## Why Use `uv run python` for MCP Servers?

### 1. **Dependency Isolation**
Each MCP server runs with its exact dependencies without conflicts:

```bash
# Each server gets its own environment
uv run python /path/to/server1/main.py  # Uses server1's dependencies
uv run python /path/to/server2/main.py  # Uses server2's dependencies
```

### 2. **Reproducible Environments**
UV ensures consistent dependency versions across different machines:

```bash
# With pyproject.toml, dependencies are locked
uv run python main.py  # Always uses same versions
```

### 3. **No Pre-activation Required**
Unlike traditional virtual environments, no need to activate:

```bash
# Traditional approach (error-prone)
source .venv/bin/activate
python main.py

# UV approach (automatic)
uv run python main.py
```

### 4. **Better Error Handling**
UV provides clear error messages when dependencies are missing or incompatible.

## MCP Configuration Best Practices

### For Local Development
```json
{
  "mcpServers": {
    "my-server": {
      "command": "uv",
      "args": ["run", "python", "/absolute/path/to/main.py"],
      "env": {
        "LOG_LEVEL": "DEBUG"
      }
    }
  }
}
```

### For Production Deployment
```json
{
  "mcpServers": {
    "production-server": {
      "command": "uv",
      "args": ["run", "--python", "3.12", "python", "/path/to/main.py"],
      "env": {
        "LOG_LEVEL": "INFO",
        "PYTHONPATH": "/path/to/server"
      }
    }
  }
}
```

## Script Metadata Support

UV supports PEP 723 script metadata for dependency declaration:

```python
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# dependencies = [
#     "mcp[cli]>=1.9.2",
#     "pydantic>=2.0.0",
#     "httpx>=0.25.0"
# ]
# ///

"""MCP Server with inline dependencies."""

from mcp.server import FastMCP
# Rest of server implementation...
```

## Performance Considerations

### Environment Caching
UV caches environments for faster subsequent runs:

```bash
# First run: Creates environment
uv run python main.py  # ~2-3 seconds

# Subsequent runs: Uses cached environment  
uv run python main.py  # ~0.1 seconds
```

### Lock Files
Use `uv.lock` for reproducible builds:

```bash
# Generate lock file
uv lock

# Run with exact locked versions
uv run python main.py
```

## Troubleshooting

### Common Issues

1. **Permission Errors**: Ensure UV has write access to cache directory
2. **Path Issues**: Always use absolute paths in MCP configurations
3. **Python Version**: Specify Python version if system default differs

### Debug Commands

```bash
# Check UV environment
uv run python -c "import sys; print(sys.executable)"

# List installed packages
uv run python -m pip list

# Verbose execution
uv run --verbose python main.py
```

## Inline Dependencies with `--with` Flag

UV's `--with` flag allows you to add dependencies on-the-fly without modifying project files. This is particularly useful for one-off scripts, debugging, and quick prototyping.

### Basic Usage

```bash
# Run a script with additional dependencies
uv run --with requests python -c "import requests; print(requests.__version__)"

# Multiple dependencies
uv run --with "pandas>=2.0.0" --with "plotly>=5.0.0" python -c "
import pandas as pd
import plotly.express as px
df = pd.DataFrame({'x': [1,2,3], 'y': [4,5,6]})
print('Data loaded successfully!')
"
```

### Data Analysis Examples

```bash
# Quick data analysis without a dedicated project
uv run --with pandas --with matplotlib python -c "
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# Generate sample data
data = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=30),
    'sales': np.random.randint(100, 1000, 30)
})

# Quick analysis
print('Sales Summary:')
print(data['sales'].describe())
print(f'Total Sales: ${data[\"sales\"].sum():,}')
"

# Web scraping with requests and beautifulsoup
uv run --with requests --with beautifulsoup4 python -c "
import requests
from bs4 import BeautifulSoup

response = requests.get('https://httpbin.org/json')
print(f'Status: {response.status_code}')
print(f'Data: {response.json()}')
"
```

### MCP Server Prototyping

```bash
# Prototype an MCP server with specific versions
uv run --with "mcp[cli]>=1.9.2" --with "pydantic>=2.11.0" python -c "
from mcp.server import FastMCP
from pydantic import BaseModel

class TestModel(BaseModel):
    name: str
    value: int

mcp = FastMCP('test-server')

@mcp.tool()
async def test_tool(name: str, value: int) -> dict:
    model = TestModel(name=name, value=value)
    return {'message': f'Created {model.name} with value {model.value}'}

print('MCP server prototype created successfully!')
print(f'Server name: {mcp.name}')
"

# Test database connections
uv run --with psycopg2-binary --with sqlalchemy python -c "
import sqlalchemy
from sqlalchemy import create_engine, text

print(f'SQLAlchemy version: {sqlalchemy.__version__}')
print('Database drivers available')
"
```

### Development Workflow Examples

```bash
# Test package compatibility
uv run --with "fastapi>=0.104.0" --with "uvicorn>=0.24.0" python -c "
import fastapi
import uvicorn
print(f'FastAPI: {fastapi.__version__}')
print(f'Uvicorn: {uvicorn.__version__}')
print('Compatibility check passed!')
"

# Data format conversion
uv run --with "openpyxl>=3.1.0" --with "pandas>=2.2.0" python -c "
import pandas as pd
import json

# Simulate reading Excel and converting to JSON
data = {'col1': [1, 2, 3], 'col2': ['a', 'b', 'c']}
df = pd.DataFrame(data)

json_output = df.to_json(orient='records', indent=2)
print('Excel to JSON conversion:')
print(json_output)
"

# API testing
uv run --with httpx --with pydantic python -c "
import httpx
import asyncio
from pydantic import BaseModel

class ApiResponse(BaseModel):
    status: str
    data: dict

async def test_api():
    async with httpx.AsyncClient() as client:
        response = await client.get('https://httpbin.org/json')
        print(f'Status: {response.status_code}')
        print(f'Headers: {dict(response.headers)}')
        return response.json()

result = asyncio.run(test_api())
print(f'API test result: {result}')
"
```

### Machine Learning Prototyping

```bash
# Quick ML experiment
uv run --with scikit-learn --with numpy python -c "
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# Generate sample data
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Train model
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# Evaluate
predictions = model.predict(X_test)
accuracy = accuracy_score(y_test, predictions)

print(f'Model Accuracy: {accuracy:.3f}')
print(f'Feature Importance (top 5):')
for i, importance in enumerate(model.feature_importances_[:5]):
    print(f'  Feature {i}: {importance:.3f}')
"
```

### Advanced Usage Patterns

```bash
# Combine with version constraints
uv run --with "numpy>=1.24.0,<2.0.0" --with "scipy>=1.11.0" python -c "
import numpy as np
import scipy as sp
print(f'NumPy: {np.__version__} (meets constraint)')
print(f'SciPy: {sp.__version__} (compatible)')
"

# Use pre-release versions for testing
uv run --with "django>=5.0.0rc1" --with "channels>=4.0.0" python -c "
import django
print(f'Testing with Django pre-release: {django.__version__}')
"

# Development dependencies for testing
uv run --with pytest --with pytest-asyncio --with hypothesis python -c "
import pytest
import hypothesis
print('Testing framework ready!')
print(f'Pytest: {pytest.__version__}')
print(f'Hypothesis: {hypothesis.__version__}')
"
```

### Benefits of `--with` Flag

- ✅ **No project modification**: Test dependencies without changing `pyproject.toml`
- ✅ **Rapid prototyping**: Quickly test ideas with different package combinations
- ✅ **Debugging**: Add debugging tools without permanent installation
- ✅ **CI/CD testing**: Test different dependency versions in pipelines
- ✅ **Documentation examples**: Run examples without environment setup

### When to Use `--with` vs Project Dependencies

| Use `--with` for: | Use project dependencies for: |
|-------------------|-------------------------------|
| One-off scripts | Production applications |
| Quick prototypes | Long-term projects |
| Testing compatibility | Reproducible builds |
| Debug sessions | Team collaboration |
| Documentation examples | Deployment scenarios |

## Comparison with Traditional Approaches

| Method | Pros | Cons |
|--------|------|------|
| `python main.py` | Simple | No isolation, manual env management |
| `source .venv/bin/activate && python main.py` | Explicit control | Manual activation, platform-specific |
| `uv run python main.py` | Automatic isolation, cross-platform | Requires UV installation |

## Conclusion

Using `uv run python` for MCP servers provides:
- ✅ **Automatic dependency management**
- ✅ **Environment isolation**
- ✅ **Cross-platform compatibility**
- ✅ **Reproducible deployments**
- ✅ **No manual environment activation**

This makes it the recommended approach for running MCP servers in both development and production environments.
