[project] name = "openproject-mcp-server" dynamic = ["version"] description = "MCP server for OpenProject: 88 tools for work packages, attachments, git activity, time tracking, meetings and reporting over the API v3" readme = "README.md" requires-python = ">=3.12" authors = [{ name = "kar-thik", email = "mail@karthikv.dev" }] license = "MIT" license-files = ["LICENSE"] keywords = [ "mcp", "openproject", "fastmcp", "model-context-protocol", "claude", "ai", "llm", "project-management", ] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development", "Topic :: Office/Business :: Groupware", "Typing :: Typed", ] dependencies = [ "fastmcp>=3.4.5,<4", "httpx[http2]>=0.28.1", "pydantic>=2.12", "pydantic-settings>=2", ] [project.scripts] openproject-mcp-server = "openproject_mcp.__main__:main" openproject-mcp = "openproject_mcp.__main__:main" [project.urls] Homepage = "https://github.com/kar-thik/openproject-mcp" Repository = "https://github.com/kar-thik/openproject-mcp" Issues = "https://github.com/kar-thik/openproject-mcp/issues" Changelog = "https://github.com/kar-thik/openproject-mcp/blob/main/CHANGELOG.md" [dependency-groups] dev = [ "pytest>=8", "pytest-asyncio>=0.24", "respx>=0.22", "hypothesis>=6.164.0", "ruff>=0.6", "pyright>=1.1.411", ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.version] path = "openproject_mcp/__init__.py" [tool.hatch.build.targets.wheel] packages = ["openproject_mcp"] [tool.hatch.build.targets.sdist] include = ["openproject_mcp", "README.md", "LICENSE", "CHANGELOG.md", "SECURITY.md"] [tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" addopts = "-q" markers = [ "integration: requires a live OpenProject instance (opt-in, never run by default)", ] [tool.pyright] include = ["openproject_mcp"] pythonVersion = "3.12" # openproject_mcp/client and openproject_mcp/tools are the layers every tool and # every future module builds on, so they must be strict; the rest of the package # is small enough to hold to the same bar rather than carve out an exception. typeCheckingMode = "strict" # Every tool is a nested function that only the @mcp.tool decorator ever calls, # so "unused" is structurally wrong for this codebase rather than a finding. reportUnusedFunction = false [tool.ruff] line-length = 100 target-version = "py312" src = ["openproject_mcp", "tests"] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "B", # bugbear "UP", # pyupgrade "SIM", # flake8-simplify "RUF", # ruff-specific ] ignore = [ "B008", # function call in default argument — normal for FastMCP/pydantic ] [tool.ruff.lint.per-file-ignores] "tests/*" = ["E501"] [tool.ruff.lint.isort] known-first-party = ["openproject_mcp"]