# Phase 11: PyPI Packaging - Context

**Gathered:** 2026-03-24
**Status:** Ready for planning

<domain>
## Phase Boundary

Make vmcluster-mcp installable from PyPI with a single command. This phase covers:
- `pyproject.toml` completeness (entry point, metadata, classifiers, README)
- Console script definition so `vmcluster-mcp` works after install
- Package build verification (sdist + wheel)
- First manual PyPI publish

Automated CI/CD publishing (GitHub Actions on tag push) is explicitly out of scope — that is INST-07, deferred to a later phase.

</domain>

<decisions>
## Implementation Decisions

### Console script entry point
- **D-01:** Add `[project.scripts]` to `pyproject.toml`: `vmcluster-mcp = "vmcluster_mcp.__main__:main"`
- **D-02:** Wrap the existing `mcp.run()` call in `__main__.py` with a `main()` function:
  ```python
  def main():
      mcp.run()

  if __name__ == "__main__":
      main()
  ```
- **D-03:** `uvx vmcluster-mcp` must also work — this is satisfied automatically by the console script entry point once the package is on PyPI.

### Version number
- **D-04:** Bump version to `"1.0.0"` in `pyproject.toml` — the v1.0 milestone shipped, so the first PyPI release should reflect that.
- **D-05:** Static version string (no dynamic versioning with hatch-vcs). Manual bump on each release. This keeps the setup simple until INST-07 (CI auto-publish) is implemented.

### Package metadata
- **D-06:** Add `readme = "README.md"` to `[project]` so PyPI shows the full README as the long description.
- **D-07:** Add `license = "MIT"` to `[project]` and create a `LICENSE` file with MIT license text.
- **D-08:** Add Python classifiers:
  - `"Programming Language :: Python :: 3"`
  - `"Programming Language :: Python :: 3.11"`
  - `"License :: OSI Approved :: MIT License"`
  - `"Operating System :: POSIX :: Linux"`
  - `"Topic :: Software Development :: Testing"`
  - `"Topic :: System :: Systems Administration"`
- **D-09:** Add `keywords` array: `["mcp", "libvirt", "qemu", "kvm", "vm", "cluster", "testing"]`
- **D-10:** Add author info: name and optional email in `[project]`.

### libvirt-python dependency
- **D-11:** Keep `libvirt-python` as a hard dependency — this tool is fundamentally a libvirt orchestration layer. Making it optional would be confusing.
- **D-12:** Document in README (and/or install notes) that system-level libvirt dev headers are required before `pip install vmcluster-mcp`. This is a pre-existing install story concern that Phase 12 (setup wizard) addresses further.

### Build verification
- **D-13:** Run `python -m build` (or `uv build`) to produce both sdist and wheel — verify no missing files before publishing.
- **D-14:** Check wheel contents with `unzip -l dist/*.whl` to confirm all `vmcluster_mcp/` subpackages are included.
- **D-15:** Test install from wheel locally with `pip install dist/*.whl` and verify `vmcluster-mcp --help` or the entry point works.

### PyPI publishing
- **D-16:** Manual publish via `uv publish` or `twine upload`. No CI/CD for this phase.
- **D-17:** Publish to the real PyPI (not TestPyPI) — package name `vmcluster-mcp` must be available.

### Claude's Discretion
- Exact author name/email format
- Whether to add `project.urls` (Homepage, Repository, Bug Tracker) — standard practice, add if clean
- Exact license year and holder in LICENSE file
- Whether to add `python_requires` version bounds (already have `>=3.11`)

</decisions>

<specifics>
## Specific Ideas

- Project already uses hatchling build backend — no change needed there.
- The `__main__.py` pattern is already in place for `python -m vmcluster_mcp`; the console script wraps the same entry.
- No non-Python data files exist in the package — hatchling will auto-include all `.py` files.

</specifics>

<canonical_refs>
## Canonical References

### Phase scope
- `.planning/REQUIREMENTS.md` — INST-01 requirement definition
- `.planning/ROADMAP.md` §Phase 11 — Success criteria and acceptance criteria

### Existing package definition
- `pyproject.toml` — Current build configuration to extend (hatchling, deps, ruff config)
- `vmcluster_mcp/__main__.py` — Entry point to wrap with `main()` function

No external specs or ADRs exist for this phase — all requirements are captured in decisions above and in REQUIREMENTS.md.

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets
- `vmcluster_mcp/__main__.py`: Currently calls `mcp.run()` directly — needs `main()` wrapper function added
- `vmcluster_mcp/server.py`: Defines `mcp = FastMCP("vmcluster-mcp")` — this is what runs

### Established Patterns
- Build backend: hatchling (already in `pyproject.toml` `[build-system]`)
- No existing `[project.scripts]` section — must be added
- No existing `[project.urls]` section — add as standard practice
- Version is `"0.1.0"` — bump to `"1.0.0"`

### Integration Points
- `pyproject.toml` is the single file to modify for metadata + entry points
- `vmcluster_mcp/__main__.py` gets a `main()` function added
- New `LICENSE` file at repo root
- No changes to server logic, dependencies, or test infrastructure

</code_context>

<deferred>
## Deferred Ideas

- **Automated CI/CD publishing** (GitHub Actions on tag push, OIDC trusted publishing) — INST-07, explicitly deferred from v1.1 scope
- **TestPyPI staging** — acceptable for manual validation but not required by success criteria
- **Version pinning / dynamic versioning** (hatch-vcs, setuptools-scm) — defer until CI/CD publishing is implemented

</deferred>

---

*Phase: 11-pypi-packaging*
*Context gathered: 2026-03-24*
