feat: add project membership management tools#180
Conversation
📝 WalkthroughWalkthroughProject membership management now supports adding members, updating roles, and removing memberships through MCP tools, with role/input validation, REST integration, clarified member identifiers, documentation updates, and end-to-end coverage. ChangesProject Membership Management
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant MCPTool
participant ProjectMembershipAPI
participant PlaneRESTAPI
MCPTool->>ProjectMembershipAPI: Create, update, or delete membership
ProjectMembershipAPI->>PlaneRESTAPI: Send membership REST request
PlaneRESTAPI-->>ProjectMembershipAPI: Return membership response or error
ProjectMembershipAPI-->>MCPTool: Return mutation result
Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
plane_mcp/tools/projects.py (3)
386-388: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRefactor the list endpoint to omit pagination metadata.
Based on learnings, list endpoints in
plane_mcp/toolsshould return only the list of items (response.results) and omit the full pagination metadata from the initial response. Since you are modifying the docstring here, consider updating the tool's signature and return statement to return just the results list to conform with this pattern.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plane_mcp/tools/projects.py` around lines 386 - 388, Update the project-member listing tool’s signature and docstring to describe a list of member items rather than paginated response metadata, and change its return statement to return only response.results. Preserve the existing member retrieval behavior and field mappings.Source: Learnings
429-434: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueOptimize duplicate member detection.
Using
list.count()inside a set comprehension results in$O(N^2)$ time complexity. Whilemembersis likely small, using asetto track seen elements is more efficient and idiomatic.♻️ Proposed refactor
- member_ids = [member.member for member in members] - duplicate_member_ids = {member_id for member_id in member_ids if member_ids.count(member_id) > 1} + seen = set() + duplicate_member_ids = {member.member for member in members if member.member in seen or seen.add(member.member)}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plane_mcp/tools/projects.py` around lines 429 - 434, Update duplicate detection in the member validation block to use a single-pass seen-set approach, collecting repeated member IDs without calling list.count() for each item. Preserve the existing sorted duplicate_list formatting and ValueError message.
440-448: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueConsider documenting partial failure behavior during bulk addition.
Because these API calls are executed sequentially, if an error occurs mid-loop (e.g., the second member addition fails), the function will raise an exception. Any successfully created memberships prior to the failure will remain in Plane, but their generated
ids will not be returned to the client. The caller will have to filter out the already-added members before retrying to avoid active duplicate errors.If bulk atomicity is not supported by the underlying API, consider noting this partial-failure behavior in the docstring.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plane_mcp/tools/projects.py` around lines 440 - 448, Document in the enclosing bulk membership-addition function’s docstring that calls execute sequentially and may partially succeed: an exception can leave earlier memberships created while their generated IDs are not returned, requiring callers to exclude them before retrying.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@plane_mcp/tools/projects.py`:
- Around line 386-388: Update the project-member listing tool’s signature and
docstring to describe a list of member items rather than paginated response
metadata, and change its return statement to return only response.results.
Preserve the existing member retrieval behavior and field mappings.
- Around line 429-434: Update duplicate detection in the member validation block
to use a single-pass seen-set approach, collecting repeated member IDs without
calling list.count() for each item. Preserve the existing sorted duplicate_list
formatting and ValueError message.
- Around line 440-448: Document in the enclosing bulk membership-addition
function’s docstring that calls execute sequentially and may partially succeed:
an exception can leave earlier memberships created while their generated IDs are
not returned, requiring callers to exclude them before retrying.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1eac21b8-4790-4808-b97f-8ad332bf0f8c
📒 Files selected for processing (4)
README.mdplane_mcp/tools/projects.pytests/test_integration.pytests/test_project_memberships.py
Description
Adds project membership mutation tools for administrative automation:
add_project_membersadds one or more existing workspace users to a project with Guest, Member, or Admin roles.update_project_memberchanges a project membership record's role when the caller has a project-membership record UUID.remove_project_memberdeactivates a project membership when the caller has a project-membership record UUID.Verified identifier contract:
idis the workspace-user UUID.idis the project-membership record UUID andmemberis the workspace-user UUID.update_project_memberandremove_project_membertherefore accept the membershipidreturned byadd_project_membersor another public mutation response; they do not claim thatget_project_memberscan discover arbitrary existing membership IDs.This uses a small adapter around the SDK resource's lower-level HTTP methods because
plane-sdk==0.2.19exposes project member listing but not public mutation helpers.Type of Change
Test Scenarios
Unit tests cover:
get_project_members5,15, and20Nonereturn behaviorCommands run:
.venv/bin/ruff format plane_mcp/ tests/.venv/bin/ruff check plane_mcp/tools/projects.py tests/test_project_memberships.py.venv/bin/pytest tests/test_project_memberships.py -v.venv/bin/python -m compileall plane_mcpgit diff --checkReferences
Addresses #175
Summary by CodeRabbit
New Features
Documentation
Tests