Skip to content

feat: replace work item relations with dedicated dependency and custom relation tools#148

Merged
Prashant-Surya merged 14 commits into
mainfrom
chore-custom-relations
Jun 26, 2026
Merged

feat: replace work item relations with dedicated dependency and custom relation tools#148
Prashant-Surya merged 14 commits into
mainfrom
chore-custom-relations

Conversation

@akhil-vamshi-konam

@akhil-vamshi-konam akhil-vamshi-konam commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Description

Introduces dedicated work item relation modules and improves structured logging for observability while tightening PII handling.

Work item relations

  • Replaces the legacy work_item_relations tools with dedicated modules:

    • work_item_relation_definitions (CRUD for workspace relation definitions)
    • work_item_dependencies (manage the six built-in dependency types)
    • work_item_custom_relations (manage definition-based custom relations)
  • Removes the legacy work_item_relations.py implementation backed by the deprecated /relations/ endpoint.

Logging improvements

  • Added PlaneLoggingMiddleware to include the tool name in tools/call log entries.
  • Added workspace_slug to all log records for workspace-level analytics.
  • Added LOG_USER_INFO (default: false) to optionally include user display names in logs while keeping PII disabled by default.
  • stdio logs only workspace_slug; LOG_USER_INFO is a no-op for stdio.

Type of Change

  • Feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Documentation update

Sample Logs

HTTP with user info (LOG_USER_INFO=truedisplay_name included)

{"timestamp": "2026-06-17T10:34:44.498814+00:00", "level": "INFO", "logger": "fastmcp.plane_mcp.auth.plane_oauth_provider", "message": "User verified: (4161e0f8-48a2-49b4-a43a-458465337135) - akhil.vamshi"}

{"timestamp": "2026-06-17T10:34:44.532392+00:00", "level": "INFO", "logger": "fastmcp.middleware.structured_logging", "event": "request_start", "method": "tools/call", "source": "client", "payload": "{\"task\":null,\"_meta\":null,\"name\":\"list_projects\",\"arguments\":{}}", "payload_type": "CallToolRequestParams", "user_id": "4161e0f8-48a2-49b4-a43a-458465337135", "workspace_slug": "bronze", "display_name": "akhil.vamshi"}

{"timestamp": "2026-06-17T10:34:44.630735+00:00", "level": "INFO", "logger": "fastmcp.middleware.structured_logging", "event": "request_success", "method": "tools/call", "source": "client", "duration_ms": 98.26, "tool": "list_projects", "user_id": "4161e0f8-48a2-49b4-a43a-458465337135", "workspace_slug": "bronze", "display_name": "akhil.vamshi"}

HTTP without user info (default → no display_name, user_id only)

{"timestamp": "2026-06-17T11:55:51.043796+00:00", "level": "INFO", "logger": "fastmcp.plane_mcp.auth.plane_oauth_provider", "message": "User verified: (4161e0f8-48a2-49b4-a43a-458465337135)"}

{"timestamp": "2026-06-17T11:55:51.084374+00:00", "level": "INFO", "logger": "fastmcp.middleware.structured_logging", "event": "request_start", "method": "tools/call", "source": "client", "payload": "{\"task\":null,\"_meta\":null,\"name\":\"list_projects\",\"arguments\":{}}", "payload_type": "CallToolRequestParams", "user_id": "4161e0f8-48a2-49b4-a43a-458465337135", "workspace_slug": "bronze"}

{"timestamp": "2026-06-17T11:55:51.175255+00:00", "level": "INFO", "logger": "fastmcp.middleware.structured_logging", "event": "request_success", "method": "tools/call", "source": "client", "duration_ms": 90.76, "tool": "list_projects", "user_id": "4161e0f8-48a2-49b4-a43a-458465337135", "workspace_slug": "bronze"}

Summary by CodeRabbit

  • New Features

    • Added tools to manage custom work item relation definitions.
    • Expanded role browsing and work item relation handling.
    • Added richer workspace and project member listing with filters and pagination.
  • Bug Fixes

    • Search now matches only work item name, sequence ID, and project identifier.
    • Relation tools now clearly separate built-in dependencies from custom relations.
  • Documentation

    • Updated setup and usage docs for structured logging and optional user-info logging.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds workspace relation-definition tools, rewrites relation handling to split built-in and custom backends, updates project/workspace member listing and role tools to paginated APIs, and expands structured logging with user context, tool metadata, and related documentation.

Changes

Work Item Relation Definitions and Dual-Mode Relation Tools

Layer / File(s) Summary
Tool registration and relation-definition CRUD
plane_mcp/tools/__init__.py, plane_mcp/tools/work_item_relation_definitions.py, tests/test_integration.py, README.md
Registers the new relation-definition tools and adds list/create/update/delete MCP tools for workspace relation definitions; the integration test expects the new tool names and the README documents them.
Dual-mode work item relation handling
plane_mcp/tools/work_item_relations.py
Lists built-in dependencies and custom relations separately, creates relations through either dependency or custom-definition inputs, and removes relations through dependency-aware or custom-aware client calls.
Instruction and doc updates
plane_mcp/instructions.py, plane_mcp/tools/work_items.py, pyproject.toml
SERVER_INSTRUCTIONS is reduced to an inline epics-only string, the work-item search and count docs are updated, and the plane-sdk dependency is bumped.

Role, project member, and workspace member pagination

Layer / File(s) Summary
Role tool registration
plane_mcp/tools/__init__.py, plane_mcp/tools/roles.py
Registers role tools and adds list/retrieve role MCP tools backed by the Plane client.
Project and workspace member listings
plane_mcp/tools/projects.py, plane_mcp/tools/workspaces.py
Project and workspace member tools now accept explicit filters and pagination inputs, construct member query parameters, and return paginated response types instead of unpaginated member lists.

Structured logging and transport middleware

Layer / File(s) Summary
User context and verification logging
plane_mcp/__main__.py, plane_mcp/auth/plane_oauth_provider.py
Logging enriches records with user and workspace context, optionally includes display name when LOG_USER_INFO is enabled, and token verification logging follows the same toggle.
Tool-name logging middleware and server wiring
plane_mcp/middleware.py, plane_mcp/server.py
A logging middleware adds tool names to structured tool-call logs, and the server factory installs it for OAuth, header, and stdio transports.
Logging documentation and test config
README.md, .env.test, CLAUDE.md
Documentation and sample environment configuration add LOG_USER_INFO guidance and describe the structured logging output.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • makeplane/plane-mcp-server#92: Touches plane_mcp/tools/work_item_relations.py, which this PR rewrites for dual-mode dependency and custom relation handling.
  • makeplane/plane-mcp-server#111: Also updates pyproject.toml by bumping the plane-sdk dependency version.
  • makeplane/plane-mcp-server#155: Overlaps with the logging changes in plane_mcp/__main__.py, plane_mcp/middleware.py, plane_mcp/server.py, and plane_mcp/auth/plane_oauth_provider.py.

Suggested reviewers

  • Prashant-Surya
  • Saurabhkmr98

Poem

🐇 I hop through tools, all neat and bright,
Relations split by custom, built-in light.
Logs now whisper names when asked to show,
And members page with tidy rows to go.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main shift from legacy relations to dedicated dependency and custom relation tools.
Docstring Coverage ✅ Passed Docstring coverage is 89.58% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore-custom-relations

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@akhil-vamshi-konam akhil-vamshi-konam marked this pull request as ready for review June 15, 2026 06:38
@akhil-vamshi-konam akhil-vamshi-konam marked this pull request as draft June 16, 2026 03:41
@akhil-vamshi-konam akhil-vamshi-konam marked this pull request as ready for review June 16, 2026 06:27

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plane_mcp/tools/work_item_relation_definitions.py (1)

138-142: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add missing Returns sections to tool docstrings.

Both modified tool docstrings include Args but omit Returns, which violates the tool docstring standard.

  • plane_mcp/tools/work_item_relation_definitions.py#L138-L142: add a Returns section (even if it is explicit None/ack behavior).
  • plane_mcp/tools/work_item_relations.py#L136-L150: add a Returns section documenting the remove tool’s output contract.
    As per coding guidelines, “Tool docstrings must include Args and Returns sections.”
🤖 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/work_item_relation_definitions.py` around lines 138 - 142,
Add missing `Returns` sections to both tool docstrings to comply with the tool
docstring standard. In `plane_mcp/tools/work_item_relation_definitions.py` lines
138-142, add a `Returns` section to the docstring for the delete method
documenting what it returns (e.g., None or acknowledgment behavior). In
`plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section
to the docstring for the remove tool documenting its output contract. Both
sections should clearly describe the return value or behavior to ensure complete
documentation per coding guidelines.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@plane_mcp/tools/work_item_relations.py`:
- Around line 96-127: The function currently silently chooses dependency
creation if relation_type is provided, even if custom relation fields
(relation_definition_id and relation_definition_label) are also passed. Since
these modes are mutually exclusive per the API contract, add early validation
before the existing if statements to check if both relation_type and the custom
relation fields are provided together. If this ambiguous combination is
detected, raise a ValueError explaining that these parameters are mutually
exclusive and the caller must choose only one mode.

In `@tests/test_integration.py`:
- Around line 193-200: The extract_result call for the epics_result is
incorrectly assuming the payload is wrapped in a dict with a "results" key, but
list_work_items returns the item list directly. Remove the ["results"] indexing
from the epics assignment where extract_result(epics_result) is called, so that
epics is assigned the extracted list directly rather than attempting to access a
non-existent "results" key within it.
- Around line 142-158: Before creating a new workspace-level Epic type via the
create_work_item_type call, first check if an Epic type already exists in the
workspace_types list that was just retrieved. After extracting the
workspace_types from the result, search through that list for an existing type
with the name "Epic". If found, use that existing type for epic_type instead of
creating a duplicate. Only call create_work_item_type if no Epic type already
exists in the workspace_types. This prevents duplicate-name errors and avoids
unnecessary type creation when the type is already available.

---

Outside diff comments:
In `@plane_mcp/tools/work_item_relation_definitions.py`:
- Around line 138-142: Add missing `Returns` sections to both tool docstrings to
comply with the tool docstring standard. In
`plane_mcp/tools/work_item_relation_definitions.py` lines 138-142, add a
`Returns` section to the docstring for the delete method documenting what it
returns (e.g., None or acknowledgment behavior). In
`plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section
to the docstring for the remove tool documenting its output contract. Both
sections should clearly describe the return value or behavior to ensure complete
documentation per coding guidelines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f03418e5-4715-4273-8d89-b804cb6dc997

📥 Commits

Reviewing files that changed from the base of the PR and between 3abec05 and bd920fd.

📒 Files selected for processing (9)
  • README.md
  • plane_mcp/instructions.py
  • plane_mcp/tools/__init__.py
  • plane_mcp/tools/initiatives.py
  • plane_mcp/tools/work_item_relation_definitions.py
  • plane_mcp/tools/work_item_relations.py
  • plane_mcp/tools/work_item_types.py
  • plane_mcp/tools/work_items.py
  • tests/test_integration.py
✅ Files skipped from review due to trivial changes (2)
  • plane_mcp/tools/work_item_types.py
  • README.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plane_mcp/tools/work_item_relation_definitions.py (1)

138-142: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add missing Returns sections to tool docstrings.

Both modified tool docstrings include Args but omit Returns, which violates the tool docstring standard.

  • plane_mcp/tools/work_item_relation_definitions.py#L138-L142: add a Returns section (even if it is explicit None/ack behavior).
  • plane_mcp/tools/work_item_relations.py#L136-L150: add a Returns section documenting the remove tool’s output contract.
    As per coding guidelines, “Tool docstrings must include Args and Returns sections.”
🤖 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/work_item_relation_definitions.py` around lines 138 - 142,
Add missing `Returns` sections to both tool docstrings to comply with the tool
docstring standard. In `plane_mcp/tools/work_item_relation_definitions.py` lines
138-142, add a `Returns` section to the docstring for the delete method
documenting what it returns (e.g., None or acknowledgment behavior). In
`plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section
to the docstring for the remove tool documenting its output contract. Both
sections should clearly describe the return value or behavior to ensure complete
documentation per coding guidelines.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@plane_mcp/tools/work_item_relations.py`:
- Around line 96-127: The function currently silently chooses dependency
creation if relation_type is provided, even if custom relation fields
(relation_definition_id and relation_definition_label) are also passed. Since
these modes are mutually exclusive per the API contract, add early validation
before the existing if statements to check if both relation_type and the custom
relation fields are provided together. If this ambiguous combination is
detected, raise a ValueError explaining that these parameters are mutually
exclusive and the caller must choose only one mode.

In `@tests/test_integration.py`:
- Around line 193-200: The extract_result call for the epics_result is
incorrectly assuming the payload is wrapped in a dict with a "results" key, but
list_work_items returns the item list directly. Remove the ["results"] indexing
from the epics assignment where extract_result(epics_result) is called, so that
epics is assigned the extracted list directly rather than attempting to access a
non-existent "results" key within it.
- Around line 142-158: Before creating a new workspace-level Epic type via the
create_work_item_type call, first check if an Epic type already exists in the
workspace_types list that was just retrieved. After extracting the
workspace_types from the result, search through that list for an existing type
with the name "Epic". If found, use that existing type for epic_type instead of
creating a duplicate. Only call create_work_item_type if no Epic type already
exists in the workspace_types. This prevents duplicate-name errors and avoids
unnecessary type creation when the type is already available.

---

Outside diff comments:
In `@plane_mcp/tools/work_item_relation_definitions.py`:
- Around line 138-142: Add missing `Returns` sections to both tool docstrings to
comply with the tool docstring standard. In
`plane_mcp/tools/work_item_relation_definitions.py` lines 138-142, add a
`Returns` section to the docstring for the delete method documenting what it
returns (e.g., None or acknowledgment behavior). In
`plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section
to the docstring for the remove tool documenting its output contract. Both
sections should clearly describe the return value or behavior to ensure complete
documentation per coding guidelines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f03418e5-4715-4273-8d89-b804cb6dc997

📥 Commits

Reviewing files that changed from the base of the PR and between 3abec05 and bd920fd.

📒 Files selected for processing (9)
  • README.md
  • plane_mcp/instructions.py
  • plane_mcp/tools/__init__.py
  • plane_mcp/tools/initiatives.py
  • plane_mcp/tools/work_item_relation_definitions.py
  • plane_mcp/tools/work_item_relations.py
  • plane_mcp/tools/work_item_types.py
  • plane_mcp/tools/work_items.py
  • tests/test_integration.py
✅ Files skipped from review due to trivial changes (2)
  • plane_mcp/tools/work_item_types.py
  • README.md
🛑 Comments failed to post (3)
plane_mcp/tools/work_item_relations.py (1)

96-127: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject ambiguous create mode inputs.

If callers pass relation_type and custom relation fields together, dependency creation is chosen silently. This should fail fast because the API contract is mutually exclusive.

Suggested fix
         client, workspace_slug = get_plane_client_context()
+        if relation_type and (relation_definition_id or relation_definition_label):
+            raise ValueError(
+                "Use either relation_type (dependency) or relation_definition_id + "
+                "relation_definition_label (custom), not both."
+            )
         if relation_type:
             if relation_type not in _DEPENDENCY_TYPES:
                 raise ValueError(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        if relation_type and (relation_definition_id or relation_definition_label):
            raise ValueError(
                "Use either relation_type (dependency) or relation_definition_id + "
                "relation_definition_label (custom), not both."
            )
        if relation_type:
            if relation_type not in _DEPENDENCY_TYPES:
                raise ValueError(
                    f"relation_type must be one of {list(_DEPENDENCY_TYPES)}. For any "
                    "other relationship, pass relation_definition_id + "
                    "relation_definition_label from list_work_item_relation_definitions."
                )
            return client.work_items.dependencies.create(
                workspace_slug=workspace_slug,
                project_id=project_id,
                work_item_id=work_item_id,
                data=CreateWorkItemDependency(
                    relation_type=relation_type,  # type: ignore[arg-type]
                    work_item_ids=work_item_ids,
                ),
            )
        if relation_definition_id and relation_definition_label:
            return client.work_items.custom_relations.create(
                workspace_slug=workspace_slug,
                project_id=project_id,
                work_item_id=work_item_id,
                data=CreateWorkItemCustomRelation(
                    relation_definition_id=relation_definition_id,
                    relation_definition_type=relation_definition_label,
                    work_item_ids=work_item_ids,
                ),
            )
        raise ValueError(
            "Provide relation_type for a built-in dependency, or "
            "relation_definition_id + relation_definition_label for a custom "
            "relation (call list_work_item_relation_definitions to find one)."
        )
🤖 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/work_item_relations.py` around lines 96 - 127, The function
currently silently chooses dependency creation if relation_type is provided,
even if custom relation fields (relation_definition_id and
relation_definition_label) are also passed. Since these modes are mutually
exclusive per the API contract, add early validation before the existing if
statements to check if both relation_type and the custom relation fields are
provided together. If this ambiguous combination is detected, raise a ValueError
explaining that these parameters are mutually exclusive and the caller must
choose only one mode.
tests/test_integration.py (2)

142-158: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid duplicate “Epic” type creation in workspace scope.

The fallback path creates a new workspace-level Epic whenever workspace_types is non-empty, without first checking whether Epic already exists there. That can trigger duplicate-name errors or unnecessary type churn.

Suggested fix
-            if workspace_types:
-                new_type_result = await client.call_tool("create_work_item_type", {"name": "Epic"})
-                epic_type = extract_result(new_type_result)
-                created_workspace_epic_type = True
-                await client.call_tool(
-                    "import_work_item_types_to_project",
-                    {"project_id": project_id, "work_item_type_ids": [epic_type["id"]]},
-                )
+            if workspace_types:
+                epic_type = next((t for t in workspace_types if t.get("name", "").lower() == "epic"), None)
+                if epic_type is None:
+                    new_type_result = await client.call_tool("create_work_item_type", {"name": "Epic"})
+                    epic_type = extract_result(new_type_result)
+                    created_workspace_epic_type = True
+                await client.call_tool(
+                    "import_work_item_types_to_project",
+                    {"project_id": project_id, "work_item_type_ids": [epic_type["id"]]},
+                )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        if epic_type is None:
            workspace_types_result = await client.call_tool("list_work_item_types", {})
            workspace_types = extract_result(workspace_types_result)
            if workspace_types:
                epic_type = next((t for t in workspace_types if t.get("name", "").lower() == "epic"), None)
                if epic_type is None:
                    new_type_result = await client.call_tool("create_work_item_type", {"name": "Epic"})
                    epic_type = extract_result(new_type_result)
                    created_workspace_epic_type = True
                await client.call_tool(
                    "import_work_item_types_to_project",
                    {"project_id": project_id, "work_item_type_ids": [epic_type["id"]]},
                )
            else:
                new_type_result = await client.call_tool(
                    "create_work_item_type", {"name": "Epic", "project_id": project_id}
                )
                epic_type = extract_result(new_type_result)
🤖 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 `@tests/test_integration.py` around lines 142 - 158, Before creating a new
workspace-level Epic type via the create_work_item_type call, first check if an
Epic type already exists in the workspace_types list that was just retrieved.
After extracting the workspace_types from the result, search through that list
for an existing type with the name "Epic". If found, use that existing type for
epic_type instead of creating a duplicate. Only call create_work_item_type if no
Epic type already exists in the workspace_types. This prevents duplicate-name
errors and avoids unnecessary type creation when the type is already available.

193-200: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use list_work_items result as a list, not ["results"].

Line 199 assumes a wrapped payload shape and can fail with TypeError/KeyError when the tool returns the list directly.
Based on learnings, list endpoints should return only response.results (the item list), not pagination metadata wrappers.

Suggested fix
-        epics = extract_result(epics_result)["results"]
+        epics = extract_result(epics_result)
🤖 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 `@tests/test_integration.py` around lines 193 - 200, The extract_result call
for the epics_result is incorrectly assuming the payload is wrapped in a dict
with a "results" key, but list_work_items returns the item list directly. Remove
the ["results"] indexing from the epics assignment where
extract_result(epics_result) is called, so that epics is assigned the extracted
list directly rather than attempting to access a non-existent "results" key
within it.

Source: Learnings

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@plane_mcp/tools/projects.py`:
- Around line 311-355: The get_project_members tool is returning the full
PaginatedProjectMemberResponse instead of matching the list-tool contract used
by list_projects and similar helpers. Update get_project_members in
plane_mcp/tools/projects.py to call client.projects.get_members_lite as it does
now, but return only the response.results list rather than the pagination
wrapper, keeping the existing filters and parameters unchanged.

In `@plane_mcp/tools/roles.py`:
- Around line 15-42: list_roles currently returns the full paginated response
envelope instead of the standard results list. Update the list_roles function in
roles.py to match list_projects by returning only the results from
client.roles.list(...), and keep the existing workspace_slug, namespace,
per_page, and cursor handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0ae1ca4-abdf-455c-a33a-6b23150e7ecb

📥 Commits

Reviewing files that changed from the base of the PR and between 5aa19b1 and 66e6f08.

📒 Files selected for processing (13)
  • .env.test
  • CLAUDE.md
  • README.md
  • plane_mcp/__main__.py
  • plane_mcp/auth/plane_oauth_provider.py
  • plane_mcp/middleware.py
  • plane_mcp/server.py
  • plane_mcp/tools/__init__.py
  • plane_mcp/tools/projects.py
  • plane_mcp/tools/roles.py
  • plane_mcp/tools/workspaces.py
  • pyproject.toml
  • tests/test_integration.py
✅ Files skipped from review due to trivial changes (4)
  • CLAUDE.md
  • .env.test
  • pyproject.toml
  • README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_integration.py

Comment thread plane_mcp/tools/projects.py
Comment thread plane_mcp/tools/roles.py
@Prashant-Surya Prashant-Surya merged commit 954449a into main Jun 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants