[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "segment-mcp" dynamic = ["version"] description = "A read-first MCP server for Twilio Segment. Answers which destinations get which events, which sources are dead, and which are governed by nothing." readme = "README.md" license = "MIT" requires-python = ">=3.12" authors = [{ name = "Kate Kruger" }] classifiers = [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Typing :: Typed", ] dependencies = ["mcp>=1.2", "httpx>=0.28", "pydantic>=2.9"] [project.urls] Repository = "https://github.com/katekruger/segment-mcp" Changelog = "https://github.com/katekruger/segment-mcp/blob/main/CHANGELOG.md" [project.scripts] segment-mcp = "segment_mcp.server:main" [tool.hatch.version] path = "src/segment_mcp/__init__.py" [tool.hatch.build.targets.wheel] packages = ["src/segment_mcp"] [dependency-groups] # PEP 735 dev dependencies. Deliberately NOT [project.optional-dependencies] — # that installs alongside the package for end users; this group never ships. dev = [ # Linter/type-checker versions are PINNED, not floated with `>=`. Ruff and # pyright both change their default rule sets between releases, so an # unpinned linter can turn a green CI red with zero code change on our # side. Bump these deliberately, in their own PR, reviewing the changelog. "ruff==0.16.5", "pyright==1.1.411", "pytest>=8.3", "pytest-cov>=6.0", # The client is fully async (httpx.AsyncClient). Declared explicitly # rather than relying on the anyio pytest plugin that `mcp` pulls in # transitively — that's an implementation detail of `mcp`, not a # contract this repo should depend on. "pytest-asyncio>=0.24", "pre-commit>=4.0", ] [tool.ruff] target-version = "py312" line-length = 100 src = ["src", "tests"] # BUILD-PLAN.md is committed byte-identical to the original plan document — # ruff's markdown-embedded-code formatting must not touch it. extend-exclude = ["BUILD-PLAN.md"] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "UP", # pyupgrade "B", # flake8-bugbear "S", # flake8-bandit (security) "C4", # flake8-comprehensions "SIM", # flake8-simplify "RET", # flake8-return "PTH", # flake8-use-pathlib "RUF", # ruff-specific rules ] ignore = [ "S101", # assert is how pytest and our own invariants work ] [tool.ruff.lint.per-file-ignores] # Test files may use asserts freely and construct fixtures with weaker names. "tests/**" = ["S101", "S105", "S106", "S107", "S311"] [tool.ruff.lint.isort] known-first-party = ["segment_mcp", "tests"] [tool.ruff.format] quote-style = "double" [tool.pyright] include = ["src", "tests"] pythonVersion = "3.12" typeCheckingMode = "strict" reportMissingImports = true reportMissingTypeStubs = false [tool.pytest.ini_options] testpaths = ["tests"] addopts = "--cov=segment_mcp --cov-report=term-missing" filterwarnings = ["error"] asyncio_mode = "auto" [tool.coverage.run] source = ["src/segment_mcp"] branch = true [tool.coverage.report] exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:", "\\.\\.\\."] show_missing = true