[project] # The distribution is `verdict-qa-mcp`, not `verdict-mcp`: that name was # registered on PyPI on 2026-08-23 by an unrelated project in the same niche # (Dgotlieb/verdict-mcp). Only the name PyPI indexes moved — the import # package (`verdict_mcp`), every console script, and the plugin are unchanged, # so nothing a user types or imports is affected. name = "verdict-qa-mcp" version = "0.90.1" description = "Read-only MCP server and release gate over Verdict QA state: verdicts, findings, flaky quarantine, run history." # Not README.md: that one sells the Claude Code plugin and is full of links # relative to the repo, which resolve to nothing on PyPI. README-pypi.md # describes what this distribution actually installs. readme = "README-pypi.md" license = { file = "LICENSE" } requires-python = ">=3.10" dependencies = ["mcp[cli]>=1.27,<2"] authors = [{ name = "ArtJack" }] keywords = ["qa", "testing", "mcp", "release-gate", "regression", "flaky-tests", "claude-code"] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", ] [project.urls] Homepage = "https://github.com/ArtJack/verdict" Repository = "https://github.com/ArtJack/verdict" Issues = "https://github.com/ArtJack/verdict/issues" Changelog = "https://github.com/ArtJack/verdict/blob/main/CHANGELOG.md" [project.scripts] verdict-mcp = "verdict_mcp.server:main" verdict-gate = "verdict_mcp.gate:main" verdict-issues = "verdict_mcp.issues:main" verdict-validate = "verdict_mcp.validate:main" verdict-facts = "verdict_mcp.harness:facts_main" verdict-finalize = "verdict_mcp.harness:finalize_main" verdict-run = "verdict_mcp.runner:main" verdict-accept = "verdict_mcp.accept:main" verdict-answer = "verdict_mcp.questions:main" verdict-local = "verdict_mcp.small:main" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/verdict_mcp"] [tool.hatch.build.targets.sdist] # An allowlist, not an exclude list. hatchling honours .gitignore but *not* # .git/info/exclude, and `.claude/worktrees/` is excluded in the latter — so a # default sdist swept in 332 files of agent session worktrees (full duplicate # copies of the repo, eval fixtures and all). An allowlist cannot regress that # way: a new untracked directory is absent by default rather than published. # # Every pattern is anchored with a leading slash. These are gitignore-style # globs, so an unanchored `README.md` matches at *any* depth — which quietly # pulled `.claude/worktrees//README.md` and its whole repo copy back # into the archive even with the allowlist in place. # # `/tests` is deliberately absent. It was included, and the trees it imports — # eval/, hooks/, commands/ — were not, so the published suite could not run: # collection error, 123 failures on a `git archive` build. Adding them costs # ~1.1MB against a 124KB archive, roughly ten times the size, to ship tests # nobody downstream runs. A suite that cannot run is worse than no suite; the # repository is where this project is tested. include = [ "/src/verdict_mcp", "/README-pypi.md", "/README.md", "/CHANGELOG.md", "/LICENSE", "/pyproject.toml", ] exclude = ["/.claude"] [dependency-groups] dev = ["pytest>=8", "mutmut>=2.5,<3", "coverage>=7"] [tool.pytest.ini_options] # Only the MCP server's own tests. eval/fixtures/pricer contains INTENTIONALLY # failing seeded tests (the agent's answer-key fixture) and must never be # collected by the project suite. testpaths = ["tests"] addopts = "-q" [tool.ruff] # Deliberately narrow. The narrative comment style in this repo is a house # idiom, not mess, and `ruff format` would churn it for no gain — so this # selects correctness rules only: pyflakes (F), syntax/runtime errors (E9), # complexity (C90) and the ambiguous-name trap (E741) that put four `l` # variables in the harness. line-length = 100 extend-exclude = ["eval/fixtures"] # the defects in there are the product [tool.ruff.lint] select = ["F", "E9", "C90", "E741"] [tool.ruff.lint.mccabe] # `validate()` and `score()` are rule ladders — long by nature, and read top to # bottom the way the contract reads. The cap is set to hold the line where it # is rather than to force them apart. max-complexity = 45