Merge open PRs: retry/backoff, custom fields, relationship tools, packaging, DevOps#19
Open
kingfly55 wants to merge 13 commits intoAndyEverything:mainfrom
Open
Merge open PRs: retry/backoff, custom fields, relationship tools, packaging, DevOps#19kingfly55 wants to merge 13 commits intoAndyEverything:mainfrom
kingfly55 wants to merge 13 commits intoAndyEverything:mainfrom
Conversation
- Dockerfile: pin base image to python:3.11-slim (stable) instead of the pre-release python:3.14-slim; fix CMD to point to the correct entry point openproject-mcp-fastmcp.py - client.py: add exponential backoff retry to _request(); retries up to 3 times (delays 1s, 2s, 4s) on transient server errors (500/502/ 503/504) and network/timeout failures; non-retryable 4xx errors are raised immediately without retry https://claude.ai/code/session_01WE3p81Gk65b4fmA395dg7w
…itory-IFyU2 claude/analyze-repository-IFyU2
Create tests/ directory with 155 tests covering all 12 MCP tool modules: - conftest.py: shared fixtures and dummy env vars for offline testing - test_connection.py: test_connection, check_permissions (5 tests) - test_projects.py: CRUD + input validation (14 tests) - test_users.py: list/get users, roles, memberships (14 tests) - test_work_packages.py: CRUD, filters, types/statuses/priorities (17 tests) - test_memberships.py: CRUD + validation edge cases (13 tests) - test_hierarchy.py: parent/child relationships (8 tests) - test_relations.py: relation CRUD + validation (14 tests) - test_time_entries.py: time tracking CRUD + activities fallback (14 tests) - test_versions.py: versions CRUD + validation (8 tests) - test_news.py: news CRUD + formatting utilities (20 tests) - test_weekly_reports.py: report generation, JSON format, date validation (13 tests) All tests use AsyncMock to patch get_client() — no live API required. pytest-asyncio added to dev dependencies with asyncio_mode = "auto". All 155 tests pass with 0 warnings. https://claude.ai/code/session_01WE3p81Gk65b4fmA395dg7w
…e-and-fixes test: add comprehensive pytest test suite for all 12 tool modules
When READ_ONLY_MODE=true, every POST/PATCH/PUT/DELETE request made by OpenProjectClient._request raises immediately with a clear error message before any network call is attempted. GET requests are unaffected. Changes: - src/client.py: add _WRITE_METHODS frozenset; add `readonly` param to __init__; insert guard at the top of _request - src/server.py: read READ_ONLY_MODE env var; pass readonly= to client constructor; log⚠️ warning on startup; export is_readonly() helper - env_example.txt: document READ_ONLY_MODE=false - pyproject.toml: add pytest-asyncio dev dependency + pytest config - tests/conftest.py + tests/__init__.py: test infrastructure - tests/test_readonly_mode.py: 31 tests across 3 layers Layer 1 — client unit tests (POST/PATCH/PUT/DELETE blocked, GET allowed) Layer 2 — tool-level tests (write tools return ❌, read tools unaffected) Layer 3 — server helpers (is_readonly(), client.readonly attribute) https://claude.ai/code/session_01WE3p81Gk65b4fmA395dg7w
…-only feat: add READ_ONLY_MODE env var to block all write operations
…yload Custom fields were passed through the tool handler but never copied to the API payload in create_work_package and update_work_package client methods. Added handling for customField* keys: list-type fields (with href) go to payload["_links"], text/number fields go directly to payload. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…/list/delete) Core relationship functionality (create_work_package_relation, list_work_package_relations, delete_work_package_relation) was already present in src/client.py and src/tools/relations.py from prior work. This commit ports the supporting infrastructure from PR AndyEverything#4 (addictivedev/openproject-mcp-server): - docker-compose.yml for full-stack local/CI testing - Dockerfile.test for test runner container - run-e2e-tests.sh convenience script - pytest.ini test configuration - TESTING.md testing documentation - .flake8 linter configuration - .pre-commit-config.yaml (Black + Flake8 + pre-commit hooks) - .github/ISSUE_TEMPLATE/{bug_report,feature_request}.md - .github/pull_request_template.md - .github/workflows/{e2e-tests,release,security,dependency-updates}.yml - tests/test_unit.py (adapted for modular src/ structure; 12/12 pass) - tests/{e2e_test,simple_e2e_test,setup_test_data}.py
…y point - pyproject.toml: add [project.scripts] entry point (openproject-mcp -> src.server:main), Python 3.13 classifier, ruff/mypy tool config, [dependency-groups] - src/server.py: add main() entry point function for CLI invocation - LICENSE: add MIT license file (AndyEverything + Compass Rose Systems) - .github/workflows/ci.yml: CI with lint, test matrix (3.10-3.13), build jobs - .github/workflows/publish.yml: PyPI Trusted Publishing on version tags - .github/workflows/security.yml: dependency review, SBOM, CodeQL - .github/dependabot.yml: weekly updates for Actions and pip - CI_CD.md, RELEASING.md, TROUBLESHOOTING.md: new CI/CD documentation - .gitignore: minor additions (uv.lock comment, GITHUB_ACTIONS_PLAN.md) - README.md: add uvx/pip Quick Start and Claude Code/Desktop config examples - tests/: add test_basic.py and test_client.py (adapted for src/ layout) Skipped: file rename (openproject-mcp.py -> openproject_mcp.py), uv.lock regeneration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…D, and docs (resolve conflicts)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR merges and ports all 4 open pull requests into the upstream codebase. Each PR is addressed below.
Closes #17 — Upgrade Dockerfile to Python 3.11 and add HTTP retry/backoff (gmt1996)
Merged cleanly (fast-forward).
Dockerfile: pin base image frompython:3.14-slim(pre-release) →python:3.11-slim(stable); fixCMDentry point toopenproject-mcp-fastmcp.pysrc/client.py:_request()now retries up to 3× with exponential backoff (1 s, 2 s, 4 s) on 500/502/503/504 and network/timeout failures; non-retryable 4xx errors raise immediatelysrc/client.py+src/server.py: newREAD_ONLY_MODEenv var — whentrue, all POST/PATCH/PUT/DELETE calls are blocked before any network callpyproject.toml: addpytest-asynciodev dep andasyncio_mode = "auto"configenv_example.txt: documentREAD_ONLY_MODE=falsetests/: 14 new test modules covering connection, hierarchy, memberships, news, projects, readonly mode, relations, time entries, users, versions, weekly reports, and work packagesCloses #16 — Fix custom fields not being sent in API payload (roromedia)
Ported to current
src/layout (original targeted the legacyopenproject-mcp.py).src/client.py:create_work_packageandupdate_work_packagenow iterate overcustomField*kwargs — list-type fields (dicts withhref) are routed topayload["_links"]; text/number values go directly topayloadCloses #4 — Add work package relationship tools (addictivedev)
Core relationship tools were already present in
src/client.pyandsrc/tools/relations.py(with an even more complete implementation — includesget_work_package_relationandupdate_work_package_relationbeyond what the PR added). The DevOps infrastructure from the PR was ported:docker-compose.yml: full-stack local/CI environment (postgres, redis, OpenProject, mcp-server, test-runner)Dockerfile.test: isolated test runner containerrun-e2e-tests.sh: convenience E2E test scriptpytest.ini: pytest configurationTESTING.md: testing documentation.flake8: linter configuration (120-char line length).pre-commit-config.yaml: Black + Flake8 + standard pre-commit hooks.github/ISSUE_TEMPLATE/: bug report and feature request templates.github/pull_request_template.md.github/workflows/:e2e-tests.yml,release.yml,dependency-updates.ymltests/test_unit.py: 12 unit tests adapted for the modularsrc/layouttests/e2e_test.py,simple_e2e_test.py,setup_test_data.py: Docker-based E2E suiteCloses #15 — Add uvx/pip installation support with entry point (Compass-Rose-Systems)
Ported non-rename parts (the
openproject-mcp.py→openproject_mcp.pyrename doesn't apply; the codebase already uses asrc/layout).pyproject.toml:[project.scripts]entry point (openproject-mcp = "src.server:main"), Python 3.13 classifier,[tool.ruff]+[tool.mypy]config sections, updated dev deps (ruff,mypy,cyclonedx-bom)src/server.py:main()function andif __name__ == "__main__"block for CLI invocationLICENSE: MIT license.github/workflows/ci.yml: lint (ruff), type-check (mypy), test matrix across Python 3.10–3.13, build verification.github/workflows/publish.yml: PyPI Trusted Publishing onv*tags.github/workflows/security.yml: dependency review, SBOM generation (cyclonedx-py), CodeQL analysis (merged with Add tools #4's security workflow).github/dependabot.yml: weekly updates for Actions and pipREADME.md: new "Quick Start (uvx / pip)" section withuvx openproject-mcp-server,pip install, and Claude Code/Claude Desktop config JSON examplesCI_CD.md,RELEASING.md,TROUBLESHOOTING.md: new documentationConflict resolutions
Two conflicts arose when combining the above PRs:
.github/workflows/security.yml— Add tools #4 contributed a CodeQL-only workflow; Add uvx/pip installation support with entry point #15 contributed a more comprehensive one (dependency-review + SBOM + CodeQL). Resolved by merging all three jobs into a single workflow, keeping theuv-based dependency install from Add tools #4's CodeQL job.pyproject.toml[project.optional-dependencies].dev— upgrade Dockerfile to Python 3.11 and add HTTP retry/backoff #17 addedpytest-asyncio,black,flake8; Add uvx/pip installation support with entry point #15 replaced withruff,mypy,cyclonedx-bom. Resolved by keepingpytest-asyncio(still needed) and adoptingruff/mypy/cyclonedx-bom(supersedingblack/flake8).Test plan
uv sync && uv run pytest tests/ -v— unit tests passuv run openproject-mcpstarts without error whenOPENPROJECT_URLandOPENPROJECT_API_KEYare setuvx openproject-mcp-serverinstalls and runs from PyPI entry point./run-e2e-tests.shwith a live OpenProject instancecustomField*values appear in work package create/update API payloadsREAD_ONLY_MODE=trueblocks all write tools🤖 Generated with Claude Code