[project] name = "tmodloader-mcp" version = "0.6.3" description = "Drive a running tModLoader instance: launch it, ask it questions, photograph it, and read its state back." readme = "README.md" requires-python = ">=3.12" license = { text = "MIT" } authors = [{ name = "mjarnold" }] keywords = ["mcp", "tmodloader", "terraria", "modding", "testing"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Testing", ] dependencies = [ # 2.x only. This package imports mcp.server.mcpserver, which does not exist # in 1.x, so a range spanning both majors could resolve to a version that # cannot import the server at all. "mcp>=2,<3", ] [project.urls] Homepage = "https://github.com/musharna/tmodloader-mcp" Repository = "https://github.com/musharna/tmodloader-mcp" Issues = "https://github.com/musharna/tmodloader-mcp/issues" [project.scripts] tmodloader-mcp = "tmodloader_mcp.server:main" [dependency-groups] dev = ["pytest>=8", "ruff>=0.6"] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/tmodloader_mcp"] [tool.hatch.build.targets.sdist] # hatchling's `packages` covers the WHEEL ONLY, so the sdist needs its own # allow-list or it ships the whole working tree. include = [ "src/tmodloader_mcp", "tests", # The mod-side half. Without these an sdist ships a README telling you to # copy a folder the sdist does not contain, and MOD_CONTRACT.md - the thing # responder/README.md sends you to for the diag grammar - is not there # either. `tests/` is excluded from the copy but shipped here, because it is # the proof that the folder carries no mod's code. "responder", # THE ONE FILE, not `docs` wholesale. The wholesale include shipped # docs/superpowers/ - internal planning notes carrying real usernames and # machine paths - in every built tarball, verified by listing the 0.4.0 # sdist. Nothing was ever uploaded, so the leak stayed latent; this line # is what keeps it that way. Anything added under docs/ stays out of the # sdist until it is named here, which is the right default for a # directory that mixes contract with diary. "docs/MOD_CONTRACT.md", "README.md", "CHANGELOG.md", "LICENSE", "pyproject.toml", ] [tool.pytest.ini_options] testpaths = ["tests"] addopts = "-q" [tool.ruff] line-length = 88 target-version = "py312" # `docs/superpowers` holds PLANS AND SPECS, not published documentation - their # Python code blocks are deliberately partial fragments (an in-function body, # a snippet showing what to insert where), not standalone modules. Ruff # formats Python inside markdown fences as if each block were a whole file, so # pointed at a fragment it "corrects" the indentation that was the point, # occasionally past the edge of what still parses (a dedented `return` reads # as one outside any function). Scoped to this one directory rather than # `docs/` wholesale so docs/MOD_CONTRACT.md - a protocol document whose # examples should stay well-formed - stays linted. exclude = ["docs/superpowers"] [tool.mutmut] source_paths = ["src"] also_copy = [".github", ".gitignore", ".mcp.json", ".pre-commit-config.yaml", "CHANGELOG.md", "CLAUDE.md", "LICENSE", "README.md", "docs", "global.json", "responder", "scripts", "template", "tools"] # test_mcp_protocol drives the stdio server as a subprocess, which mutmut's in-process output capture closes pytest_add_cli_args = ["--ignore=tests/test_mcp_protocol.py"]