-
Notifications
You must be signed in to change notification settings - Fork 56
feat: Add Pages/Wiki API support #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: canary
Are you sure you want to change the base?
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.