- version 2026.08.17 in pyproject and __init__, kept in sync by a test - add the MIT LICENSE file the metadata already claimed; it ships in both the sdist and the wheel - classifiers and Repository URL following the convention used by the other MCP servers (git.supported.systems/MCP/<name>) - tests/test_packaging.py guards the invariants that only bite after upload: version drift, an unimportable console-script target, a declared license with no file, and a Python floor that moves ahead of what we test
78 lines
2.0 KiB
TOML
78 lines
2.0 KiB
TOML
[project]
|
|
name = "mcqemu"
|
|
version = "2026.08.17"
|
|
description = "MCP server for managing QEMU virtual machines"
|
|
readme = "README.md"
|
|
requires-python = ">=3.11"
|
|
authors = [{ name = "Ryan Malloy", email = "ryan@supported.systems" }]
|
|
license = "MIT"
|
|
keywords = ["mcp", "qemu", "qmp", "virtualization", "kvm", "sandbox"]
|
|
classifiers = [
|
|
"Development Status :: 4 - Beta",
|
|
"Intended Audience :: Developers",
|
|
"Intended Audience :: System Administrators",
|
|
"License :: OSI Approved :: MIT License",
|
|
"Operating System :: POSIX :: Linux",
|
|
"Programming Language :: Python :: 3",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Programming Language :: Python :: 3.13",
|
|
"Topic :: System :: Emulators",
|
|
"Topic :: System :: Systems Administration",
|
|
]
|
|
|
|
dependencies = [
|
|
"fastmcp>=3.4.7,<4",
|
|
"qemu.qmp>=0.0.6",
|
|
]
|
|
|
|
[project.urls]
|
|
Repository = "https://git.supported.systems/MCP/mcqemu"
|
|
|
|
[project.scripts]
|
|
mcqemu = "mcqemu.server:main"
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"pytest>=8",
|
|
"pytest-asyncio>=1.0",
|
|
"ruff>=0.12",
|
|
]
|
|
|
|
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["src/mcqemu"]
|
|
|
|
[tool.hatch.build.targets.sdist]
|
|
exclude = [
|
|
"CLAUDE.md",
|
|
".env",
|
|
".mcp.json",
|
|
"tests/",
|
|
".pytest_cache/",
|
|
".ruff_cache/",
|
|
"dist/",
|
|
]
|
|
|
|
[tool.ruff]
|
|
line-length = 100
|
|
src = ["src", "tests"]
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "I", "UP", "B", "SIM", "ASYNC"]
|
|
# ASYNC109: `timeout` params here are deliberate LLM-facing tool parameters.
|
|
# ASYNC110: polling an external process's death has no event to await.
|
|
# ASYNC240: pathlib use is microsecond stat/exists checks, not bulk I/O.
|
|
# ASYNC230: the one blocking read is a bounded 256KB tail, not bulk I/O.
|
|
ignore = ["ASYNC109", "ASYNC110", "ASYNC230", "ASYNC240"]
|
|
|
|
[tool.pytest.ini_options]
|
|
asyncio_mode = "auto"
|
|
markers = [
|
|
"integration: boots real QEMU (run with '-m integration')",
|
|
]
|
|
addopts = "-m 'not integration'"
|