Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion plane_mcp/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@


def register_tools(mcp: FastMCP) -> None:
"""Register all tools with the MCP server."""
"""
Register all Plane MCP tools onto the provided MCP server.

Registers each feature-specific toolset (unified, project, work items, work item activity, work item comments, work item links, work item relations, work logs, cycles, users, modules, initiatives, intake, labels, pages, work item properties, work item types, states, workspaces, epics, and milestones) in a fixed sequence. Exceptions raised by individual registration functions are not caught and will propagate.

Parameters:
mcp (FastMCP): The MCP server instance on which to register all tools.
"""
register_unified_tools(mcp)
register_project_tools(mcp)
register_work_item_tools(mcp)
Expand Down
197 changes: 138 additions & 59 deletions plane_mcp/tools/cycles.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,92 @@


def register_cycle_tools(mcp: FastMCP) -> None:
"""Register all cycle-related tools with the MCP server."""
"""
Create a new cycle in the specified project.

Parameters:
project_id (str): UUID of the project to create the cycle in.
name (str): Cycle name.
owned_by (str): UUID of the user who will own the cycle.
description (str | None): Optional cycle description.
start_date (str | None): Optional start date in ISO 8601 format.
end_date (str | None): Optional end date in ISO 8601 format.
external_source (str | None): Optional external system source name.
external_id (str | None): Optional external system identifier.
timezone (str | None): Optional timezone identifier.

Returns:
Cycle: The created Cycle object.
"""
"""
Update fields of an existing cycle.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to update.
name (str | None): New cycle name, if updating.
description (str | None): New description, if updating.
start_date (str | None): New start date in ISO 8601 format, if updating.
end_date (str | None): New end date in ISO 8601 format, if updating.
owned_by (str | None): UUID of the new owner, if updating.
external_source (str | None): External system source name, if updating.
external_id (str | None): External system identifier, if updating.
timezone (str | None): Timezone identifier, if updating.

Returns:
Cycle: The updated Cycle object.
"""
"""
Delete a cycle by its ID within the given project.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to delete.
"""
"""
Add one or more work items (issues) to a cycle.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to add work items to.
issue_ids (list[str]): List of work item (issue) UUIDs to add.
"""
"""
Remove a single work item from a cycle.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to remove the work item from.
work_item_id (str): UUID of the work item to remove.
"""
"""
Transfer all work items from a source cycle to another target cycle.

Parameters:
project_id (str): UUID of the project containing the cycles.
cycle_id (str): UUID of the source cycle whose work items will be transferred.
new_cycle_id (str): UUID of the target cycle to receive the work items.
"""
"""
Archive a cycle.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to archive.

Returns:
bool: `True` if the cycle was archived successfully, `False` otherwise.
"""
"""
Unarchive a cycle.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to unarchive.

Returns:
bool: `True` if the cycle was unarchived successfully, `False` otherwise.
"""

@mcp.tool()
def create_cycle(
Expand All @@ -27,22 +112,21 @@ def create_cycle(
timezone: str | None = None,
) -> Cycle:
"""
Create a new cycle.

Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
name: Cycle name
owned_by: UUID of the user who owns the cycle
description: Cycle description
start_date: Cycle start date (ISO 8601 format)
end_date: Cycle end date (ISO 8601 format)
external_source: External system source name
external_id: External system identifier
timezone: Cycle timezone

Create a new cycle in the specified project.

Parameters:
project_id (str): UUID of the project to contain the cycle.
name (str): Cycle name.
owned_by (str): UUID of the user who owns the cycle.
description (str | None): Optional cycle description.
start_date (str | None): Optional cycle start date in ISO 8601 format (e.g., "YYYY-MM-DD" or full timestamp).
end_date (str | None): Optional cycle end date in ISO 8601 format.
external_source (str | None): Optional external system source name.
external_id (str | None): Optional identifier from the external system.
timezone (str | None): Optional IANA timezone name for the cycle (e.g., "UTC", "America/Los_Angeles").

Returns:
Created Cycle object
Cycle: The created Cycle.
"""
client, workspace_slug = get_plane_client_context()

Expand Down Expand Up @@ -74,23 +158,22 @@ def update_cycle(
timezone: str | None = None,
) -> Cycle:
"""
Update a cycle by ID.

Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
cycle_id: UUID of the cycle
name: Cycle name
description: Cycle description
start_date: Cycle start date (ISO 8601 format)
end_date: Cycle end date (ISO 8601 format)
owned_by: UUID of the user who owns the cycle
external_source: External system source name
external_id: External system identifier
timezone: Cycle timezone

Update a cycle by ID, applying only the fields that are provided.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to update.
name (str | None): New cycle name, or `None` to leave unchanged.
description (str | None): New cycle description, or `None` to leave unchanged.
start_date (str | None): New start date in ISO 8601 format, or `None` to leave unchanged.
end_date (str | None): New end date in ISO 8601 format, or `None` to leave unchanged.
owned_by (str | None): UUID of the user who will own the cycle, or `None` to leave unchanged.
external_source (str | None): External system source name, or `None` to leave unchanged.
external_id (str | None): External system identifier, or `None` to leave unchanged.
timezone (str | None): Cycle timezone, or `None` to leave unchanged.

Returns:
Updated Cycle object
Updated Cycle object
"""
client, workspace_slug = get_plane_client_context()

Expand All @@ -110,12 +193,11 @@ def update_cycle(
@mcp.tool()
def delete_cycle(project_id: str, cycle_id: str) -> None:
"""
Delete a cycle by ID.

Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
cycle_id: UUID of the cycle
Delete the cycle identified by `cycle_id` within the specified project.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the cycle to delete.
"""
client, workspace_slug = get_plane_client_context()
client.cycles.delete(workspace_slug=workspace_slug, project_id=project_id, cycle_id=cycle_id)
Expand All @@ -127,13 +209,12 @@ def add_work_items_to_cycle(
issue_ids: list[str],
) -> None:
"""
Add work items to a cycle.

Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
cycle_id: UUID of the cycle
issue_ids: List of work item IDs to add to the cycle
Add the specified work items to the given cycle in the project.

Parameters:
project_id (str): UUID of the project containing the cycle.
cycle_id (str): UUID of the target cycle.
issue_ids (list[str]): List of work item IDs to add to the cycle.
"""
client, workspace_slug = get_plane_client_context()
client.cycles.add_work_items(
Expand All @@ -150,13 +231,12 @@ def remove_work_item_from_cycle(
work_item_id: str,
) -> None:
"""
Remove a work item from a cycle.

Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
cycle_id: UUID of the cycle
work_item_id: UUID of the work item to remove
Remove a work item from the specified cycle in a project.

Parameters:
project_id (str): UUID of the project.
cycle_id (str): UUID of the cycle.
work_item_id (str): UUID of the work item to remove.
"""
client, workspace_slug = get_plane_client_context()
client.cycles.remove_work_item(
Expand All @@ -173,13 +253,12 @@ def transfer_cycle_work_items(
new_cycle_id: str,
) -> None:
"""
Transfer work items from one cycle to another.

Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
cycle_id: UUID of the source cycle
new_cycle_id: UUID of the target cycle to transfer issues to
Transfer all work items from one cycle to another within a project.

Parameters:
project_id (str): UUID of the project containing the cycles.
cycle_id (str): UUID of the source cycle whose work items will be moved.
new_cycle_id (str): UUID of the destination cycle that will receive the work items.
"""
client, workspace_slug = get_plane_client_context()

Expand Down
59 changes: 26 additions & 33 deletions plane_mcp/tools/epics.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ def register_epic_tools(mcp: FastMCP) -> None:
"""Register all epic-related tools with the MCP server."""

def _get_epic_work_item_type(client: PlaneClient, workspace_slug: str, project_id: str) -> WorkItemType | None:
"""Helper function to get the work item type ID for epics."""
"""
Finds the project's work item type that is marked as an epic.

Searches the work item types for the given workspace and project and returns the first type whose `is_epic` attribute is truthy.

Returns:
WorkItemType | None: The work item type designated as an epic if found, `None` otherwise.
"""
response = client.work_item_types.list(
workspace_slug=workspace_slug,
project_id=project_id,
Expand Down Expand Up @@ -52,31 +59,20 @@ def create_epic(
estimate_point: str | None = None,
) -> Epic:
"""
Create a new epic.

Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
name: Epic name (required)
assignees: List of user IDs to assign to the epic
labels: List of label IDs to attach to the epic
type_id: UUID of the epic type
point: Story point value
description_html: HTML description of the epic
description_stripped: Plain text description (stripped of HTML)
priority: Priority level (urgent, high, medium, low, none)
start_date: Start date (ISO 8601 format)
target_date: Target/end date (ISO 8601 format)
sort_order: Sort order value
is_draft: Whether the epic is a draft
external_source: External system source name
external_id: External system identifier
parent: UUID of the parent epic
state: UUID of the state
estimate_point: Estimate point value

Create a new epic work item in the specified project.

If `priority` is provided but not one of the allowed PriorityEnum values, it will be ignored (treated as no priority). Raises ValueError if the project has no work item type marked as an epic.

Parameters:
project_id: UUID of the project where the epic will be created.
name: Title of the epic.
priority: Desired priority value; ignored if not one of the allowed PriorityEnum literals.

Returns:
Created WorkItem object
Epic: The created epic resource.

Raises:
ValueError: If no work item type with `is_epic=True` exists in the project.
"""
client, workspace_slug = get_plane_client_context()

Expand Down Expand Up @@ -208,14 +204,11 @@ def delete_epic(
epic_id: str,
) -> None:
"""
Delete an epic by ID.

Args:
project_id: UUID of the project
epic_id: UUID of the epic

Returns:
None
Delete the epic identified by epic_id from the given project.

Parameters:
project_id (str): UUID of the project containing the epic.
epic_id (str): UUID of the epic to delete.
"""
client, workspace_slug = get_plane_client_context()

Expand Down
Loading