Conversation
- Add list_project_pages, list_workspace_pages tools - Add search_pages tool - Add update_page, delete_page tools - Use plane-sdk pages module Adds full Pages/Wiki API support to Plane MCP server.
📝 WalkthroughWalkthroughThe pages tool module has been refactored to replace single-page retrieval methods with paginated list operations ( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@plane_mcp/tools/pages.py`:
- Around line 164-191: The search_pages function currently defaults to
project-level (workspace_level=False) but returns a hardcoded error because it
lacks project_id; update the signature of search_pages to accept project_id: str
| None = None and adjust logic in search_pages (and any calls to
get_plane_client_context if needed) to: if workspace_level is True call
client.pages.list with workspace_slug and query; else if project_id is provided
call client.pages.list with project_id and query; else return a clear error
prompting the caller to supply project_id. Ensure references to the function
name search_pages and the parameter workspace_level are updated where used and
validate/handle project_id None appropriately before calling client.pages.list.
🧹 Nitpick comments (4)
plane_mcp/tools/pages.py (4)
3-8: Remove unused imports.
Optionalis imported but not used (the code uses| Nonesyntax instead). Similarly,CreatePageandPagefromplane.models.pagesare imported but never referenced in the code.♻️ Proposed fix
-from typing import Any, Optional +from typing import Any from fastmcp import FastMCP from plane_mcp.client import get_plane_client_context -from plane.models.pages import CreatePage, Page -
42-42: Redundantstr()wrapper aroundmodel_dump_json().
model_dump_json()already returns a string, so thestr()call is unnecessary. This pattern appears in all functions (lines 42, 69, 140, 162, 191).♻️ Proposed fix (apply to all occurrences)
- return str(result.model_dump_json()) + return result.model_dump_json()
103-104: Docstring return type is inconsistent with actual return.The docstring states "Returns: Updated Page object" but the function returns a JSON string. Update the docstring for accuracy.
♻️ Proposed fix
Returns: - Updated Page object + JSON string with updated page data """
152-153: Docstring return type is inconsistent with actual return.The docstring states "Returns: Success message" but the function returns
result.model_dump_json(). Update the docstring to accurately describe the return value.♻️ Proposed fix
Returns: - Success message + JSON string with deletion result """
| @mcp.tool() | ||
| def search_pages( | ||
| query: str, | ||
| workspace_level: bool = False, | ||
| ) -> str: | ||
| """ | ||
| Search for pages by query string. | ||
| Args: | ||
| query: Search query | ||
| workspace_level: Search workspace pages (True) or project pages (False) | ||
| Returns: | ||
| JSON string with search results | ||
| """ | ||
| client, workspace_slug = get_plane_client_context() | ||
|
|
||
| # Determine search endpoint based on level | ||
| if workspace_level: | ||
| result = client.pages.list( | ||
| workspace_slug=workspace_slug, | ||
| query=query, | ||
| ) | ||
| else: | ||
| # For project-level, we'd need project_id | ||
| # This is a limitation - let's return error for now | ||
| return '{"error": "Project page search requires project_id. Use workspace_level=True for workspace-wide search."}' | ||
|
|
There was a problem hiding this comment.
Incomplete implementation: project-level search defaults to error.
The workspace_level parameter defaults to False, but the project-level search path (lines 187-190) returns a hardcoded error because project_id is not accepted as a parameter. This is confusing UX since the default behavior returns an error.
Consider one of these approaches:
- Add
project_id: str | None = Noneparameter to support project-level search - Change the default to
workspace_level: bool = Trueso the working path is the default - Remove the
workspace_levelparameter entirely if project-level search isn't planned
♻️ Option 1: Add project_id parameter
`@mcp.tool`()
def search_pages(
query: str,
+ project_id: str | None = None,
workspace_level: bool = False,
) -> str:
"""
Search for pages by query string.
Args:
query: Search query
+ project_id: UUID of the project (required when workspace_level=False)
workspace_level: Search workspace pages (True) or project pages (False)
Returns:
JSON string with search results
"""
client, workspace_slug = get_plane_client_context()
# Determine search endpoint based on level
if workspace_level:
result = client.pages.list(
workspace_slug=workspace_slug,
query=query,
)
+ elif project_id:
+ result = client.projects.pages.list(
+ workspace_slug=workspace_slug,
+ project_id=project_id,
+ query=query,
+ )
else:
- # For project-level, we'd need project_id
- # This is a limitation - let's return error for now
return '{"error": "Project page search requires project_id. Use workspace_level=True for workspace-wide search."}'
return result.model_dump_json()♻️ Option 2: Default to workspace-level search
def search_pages(
query: str,
- workspace_level: bool = False,
+ workspace_level: bool = True,
) -> str:📝 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.
| @mcp.tool() | |
| def search_pages( | |
| query: str, | |
| workspace_level: bool = False, | |
| ) -> str: | |
| """ | |
| Search for pages by query string. | |
| Args: | |
| query: Search query | |
| workspace_level: Search workspace pages (True) or project pages (False) | |
| Returns: | |
| JSON string with search results | |
| """ | |
| client, workspace_slug = get_plane_client_context() | |
| # Determine search endpoint based on level | |
| if workspace_level: | |
| result = client.pages.list( | |
| workspace_slug=workspace_slug, | |
| query=query, | |
| ) | |
| else: | |
| # For project-level, we'd need project_id | |
| # This is a limitation - let's return error for now | |
| return '{"error": "Project page search requires project_id. Use workspace_level=True for workspace-wide search."}' | |
| `@mcp.tool`() | |
| def search_pages( | |
| query: str, | |
| workspace_level: bool = True, | |
| ) -> str: | |
| """ | |
| Search for pages by query string. | |
| Args: | |
| query: Search query | |
| workspace_level: Search workspace pages (True) or project pages (False) | |
| Returns: | |
| JSON string with search results | |
| """ | |
| client, workspace_slug = get_plane_client_context() | |
| # Determine search endpoint based on level | |
| if workspace_level: | |
| result = client.pages.list( | |
| workspace_slug=workspace_slug, | |
| query=query, | |
| ) | |
| else: | |
| # For project-level, we'd need project_id | |
| # This is a limitation - let's return error for now | |
| return '{"error": "Project page search requires project_id. Use workspace_level=True for workspace-wide search."}' | |
🤖 Prompt for AI Agents
In `@plane_mcp/tools/pages.py` around lines 164 - 191, The search_pages function
currently defaults to project-level (workspace_level=False) but returns a
hardcoded error because it lacks project_id; update the signature of
search_pages to accept project_id: str | None = None and adjust logic in
search_pages (and any calls to get_plane_client_context if needed) to: if
workspace_level is True call client.pages.list with workspace_slug and query;
else if project_id is provided call client.pages.list with project_id and query;
else return a clear error prompting the caller to supply project_id. Ensure
references to the function name search_pages and the parameter workspace_level
are updated where used and validate/handle project_id None appropriately before
calling client.pages.list.
|
Hello guys is there a reason we arn't merging this yet? this is really needed i was just about to do this myself before i came across this PR. @Prashant-Surya |
@obiMadu we don't have list and update endpoints for pages in sdk yet. I don't think these tools will work. Is this tested? |
Yeaa none of those endpoints on the sdk. I just saw, they only exist in the internal API. Guess we need to start there then 👍 |
Summary
Adds Pages/Wiki API support to Plane MCP server.
New Tools
Technical Details
Testing
Tested with:
Related
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.