from fastmcp import FastMCP
from loguru import logger
router = FastMCP(name="dev-python")
def _python_uv_content() -> str:
return """\
# Python/uv Conventions
## Package Manager
- Always use `uv`; never invoke `pip` directly
- Add a runtime dependency: `uv add <package>`
- Add a dev-only dependency: `uv add --dev <package>`
- Remove a dependency: `uv remove <package>`
- Sync from lockfile: `uv sync`
- Run a script or tool: `uv run <script>`
- Run a module: `uv run -m path.to.module`
- Upgrade a package: `uv add <package>@latest`
- Always commit `uv.lock` to version control
## Project Initialization
```
uv init <project-name> # creates pyproject.toml, .python-version, main.py
cd <project-name>
uv add <deps...>
```
## Project Layout (src layout preferred for installable packages)
```
project/
├── pyproject.toml # single source of truth: metadata + deps
├── uv.lock # committed lockfile
├── .python-version # pins Python version for uv
├── src/
│ └── <package>/
│ └── __init__.py
└── tests/
```
For simple scripts or servers (non-installable), a flat layout is fine.
## pyproject.toml Conventions
- Use `[project]` table for metadata (PEP 621)
- Set `requires-python` explicitly (e.g. `>=3.13`)
- Do not manually pin versions in `pyproject.toml`; let `uv add` manage them
- Dev tools (pytest, ruff, mypy) go under `[dependency-groups] dev`
## Python Style
- Follow PEP 8; use `ruff` for linting and formatting (`uv add --dev ruff`)
- Use type annotations everywhere; validate with `mypy` (`uv add --dev mypy`)
- Prefer `pathlib.Path` over `os.path`
- Prefer f-strings over `.format()` or `%`
- Use `tomllib` (stdlib ≥3.11) for reading TOML files
- Prefer dataclasses or Pydantic models over raw dicts for structured data
## Running Tools
```
uv run ruff check . # lint
uv run ruff format . # format
uv run mypy src/ # type-check
uv run pytest # tests
```
### One-liner: Format + Lint Auto-fix
After editing code, run this combined command to auto-format and auto-fix lint issues:
```
uv run ruff format . && uv run ruff check --fix
```
- `ruff format .` — applies consistent code style (quotes, trailing commas, line length, etc.)
- `ruff check --fix` — detects lint issues and auto-fixes what it can (unused imports, etc.)
**Best practice:** always run this command after editing Python files and before committing.
## `uv run` Script Mode vs Module Mode
There are two ways to execute Python code with uv:
| | `uv run a/b.py` (script) | `uv run -m a.b` (module) |
|---|---|---|
| `sys.path[0]` | directory of the script (`a/`) | current working directory |
| `__package__` | `None` | `"a"` |
| relative imports | **fail** (`ImportError`) | **work** correctly |
### When to use which
- **`uv run a/b.py`** — standalone scripts that do NOT use relative imports.
- **`uv run -m a.b`** — code that lives inside a package and uses relative imports
(e.g. `from . import c`, `from .utils import helper`).
### Rule of thumb
If the file contains any relative import (`from .xxx import ...`), always use
`uv run -m <dotted.module.path>` instead of `uv run <file/path.py>`.
"""
@router.prompt
def python_uv() -> str:
"""Python project setup and conventions using uv as the package manager."""
return _python_uv_content()
@router.tool
def get_python_uv_conventions() -> str:
"""Return Python/uv project conventions and best practices."""
logger.debug("Tool called: get_python_uv_conventions")
return _python_uv_content()