[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "srgssr-mcp" version = "2.0.1" description = "MCP server for SRG SSR public APIs – weather, TV/radio metadata, program guide & Swiss votations/elections since 1900" readme = "README.md" license = { file = "LICENSE" } requires-python = ">=3.11" keywords = ["mcp", "model-context-protocol", "srgssr", "srf", "rts", "swiss", "media", "llm"] classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] dependencies = [ # `fastmcp` was dropped: nothing in src/ or tests/ imports it. It was a # leftover from when this server received `mcp` transitively through it, # which stopped being true once `mcp` was declared directly below. A # `test_dependencies.py` guard now fails if an import of it reappears # without the declaration coming back. # On the 2.x API (`mcp.server.mcpserver`). The floor is hard: 2.0.0 # removed `mcp.server.fastmcp` with no compatibility shim, so this code # cannot run on 1.x — a `>=1.x` range would let a resolver pick a version # that fails at import. The `<3` cap stays for the reason the old `<2` one # existed: a major bump is a decision to take on purpose. # Declared explicitly rather than inherited, so the real dependency and its # version are this project's decision. # Existing clients see no difference: the legacy `initialize` handshake # still caps at 2025-11-25 (measured — a client asking for 2026-07-28 gets # 2025-11-25 back). mcp 2.x additionally serves a "modern" per-request # envelope era that reaches 2026-07-28, so a 2.x-aware client negotiates # the newer revision. Not a break, but not a protocol no-op either. "mcp[cli]>=2.0.0,<3", "httpx>=0.27.0", "pydantic>=2.0.0", "pydantic-settings>=2.0.0", "structlog>=24.1.0,<27", ] [project.optional-dependencies] dev = [ # Exact pin, and the only place ruff's version is written down. A range # let `pip install -e ".[dev]"` resolve to whatever ruff was newest, so a # local run reported lint and format differences nobody introduced, while # CI installed its own pinned version over the top. Bumping this line is a # deliberate act — a new ruff can change the default rule set or the # formatter and turn untouched code red. `test_ruff_is_pinned_exactly` # fails if this is ever loosened back to a range. "ruff==0.16.5", "pytest>=8.0.0", "pytest-asyncio>=0.23.0", "pytest-cov>=4.1.0", "respx>=0.21.0", # Fuer `tests/test_codex_gate.py`: der Test extrahiert das `run`-Skript # aus `codex-gate.yml` und faehrt es, statt seine Logik nachzubauen. # Deklariert und nicht per `importorskip` umgangen — ein Test, der in der # CI still uebersprungen wird, haelt die Suite gruen und prueft nichts. "pyyaml>=6.0", ] [project.scripts] srgssr-mcp = "srgssr_mcp.server:main" [project.urls] Homepage = "https://github.com/malkreide/srgssr-mcp" Repository = "https://github.com/malkreide/srgssr-mcp" "Bug Tracker" = "https://github.com/malkreide/srgssr-mcp/issues" [tool.hatch.build.targets.wheel] packages = ["src/srgssr_mcp"] [tool.ruff] line-length = 120 # No `include` here. It used to read `["src/**/*.py"]`, which silently undid the # `tests/ scripts/` half of the CI's own `ruff check src/ tests/ scripts/`: # `include` filters the files ruff collects, so paths named on the command line # were dropped again. Both ruff gates passed while linting src/ alone, and a # file under tests/ with unused imports and broken formatting exited 0. [tool.ruff.lint] select = ["E", "F", "I", "B"] [tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto" markers = [ "live: tests against real APIs (manual, nightly only; deselect with '-m \"not live\"')", ]