[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "zh-education-mcp" version = "0.3.0" description = "MCP server for education statistics of the Canton and City of Zurich (BISTA)" readme = "README.md" license = { file = "LICENSE" } authors = [{ name = "Hayal Oezkan" }] requires-python = ">=3.11" keywords = [ "mcp", "model-context-protocol", "bildungsstatistik", "kanton-zuerich", "bista", "schulkreis", "volksschule", "open-data", ] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Education", "Topic :: Scientific/Engineering :: Information Analysis", ] dependencies = [ # Upper bound added deliberately: `mcp` 2.0.0 removed `mcp.server.fastmcp` # outright (the API moved to `mcp.server.mcpserver`), so an unbounded # `>=1.28.1` breaks every fresh install — CI and `pip install` alike. # Migrating to the 2.x API is real work and a decision to take on purpose, # not one a resolver should make silently. "mcp[cli]>=2.0.0,<3", "httpx>=0.27.0", "pydantic>=2.0.0", "pydantic-settings>=2.0.0", "starlette>=0.37.0,<2", "uvicorn>=0.30.0", "structlog>=24.1.0,<27", ] [project.optional-dependencies] dev = [ "pytest>=8.0.0", "pytest-asyncio>=0.23.0", "pytest-cov>=5.0.0", "respx>=0.21.0", # Exakt gepinnt, nicht `>=`: ruff ist ein Gate, kein Hilfsmittel. Der Pin # steht hier und nur hier — die CI installiert ihn ueber das `dev`-Extra # mit und hat keinen eigenen Pin-Schritt mehr. # # Vorher stand hier `>=0.16,<0.17`. Die Obergrenze hatte den richtigen # Grund: Ohne sie installiert ein frischer Klon die jeweils neuste Version # und formatiert anders als das Gate — CI meldet dann einen Formatfehler an # Code, den niemand angefasst hat. Genau das ist am 3. August passiert. # # Sie reichte nur nicht. Auch innerhalb von 0.16.x gibt es mehr als eine # Version — 0.16.2 existiert bereits — und der Formatierer muss zwischen # ihnen nicht gleich entscheiden. Der Bereich schuetzt gegen den # Minor-Sprung, nicht gegen den Fall, der ihn ausgeloest hat. Nur `==` # schliesst beides. # # Beim Anheben: Version aendern, `ruff format` einmal ueber die gelinteten # Pfade laufen lassen und das Ergebnis mit committen. "ruff==0.16.5", ] # Optionales OpenTelemetry-Tracing (OBS-006). Aktivierung via MCP_OTEL_ENABLED=true. otel = [ "opentelemetry-sdk>=1.20.0", "opentelemetry-exporter-otlp-proto-http>=1.20.0", "opentelemetry-instrumentation-httpx>=0.40b0", ] [project.scripts] zh-education-mcp = "zh_education_mcp.server:main" [project.urls] Homepage = "https://github.com/malkreide/zh-education-mcp" Repository = "https://github.com/malkreide/zh-education-mcp" Issues = "https://github.com/malkreide/zh-education-mcp/issues" [tool.hatch.build.targets.wheel] packages = ["src/zh_education_mcp"] [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] addopts = "-v --tb=short" markers = [ "live: Tests, die echte API-Aufrufe machen (von CI ausgeschlossen)", ] [tool.ruff] line-length = 100 target-version = "py311" [tool.ruff.lint] select = ["E", "F", "W", "I", "UP"] ignore = ["E501"]