"""Work item-related tools for Plane MCP Server."""
from fastmcp import FastMCP
from plane.models.enums import PriorityEnum
from plane.models.query_params import RetrieveQueryParams, WorkItemQueryParams
from plane.models.work_items import (
CreateWorkItem,
PaginatedWorkItemResponse,
UpdateWorkItem,
WorkItem,
WorkItemDetail,
WorkItemSearch,
)
from plane_mcp.client import get_plane_client_context
def register_work_item_tools(mcp: FastMCP) -> None:
"""Register all work item-related tools with the MCP server."""
@mcp.tool()
def list_work_items(
project_id: str,
cursor: str | None = None,
per_page: int | None = None,
expand: str | None = None,
fields: str | None = None,
order_by: str | None = None,
external_id: str | None = None,
external_source: str | None = None,
) -> list[WorkItem]:
"""
List all work items in a project.
Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
cursor: Pagination cursor for getting next set of results
per_page: Number of results per page (1-100)
expand: Comma-separated list of related fields to expand in response
fields: Comma-separated list of fields to include in response
order_by: Field to order results by. Prefix with '-' for descending order
external_id: External system identifier for filtering or lookup
external_source: External system source name for filtering or lookup
Returns:
List of WorkItem objects
"""
client, workspace_slug = get_plane_client_context()
params = WorkItemQueryParams(
cursor=cursor,
per_page=per_page,
expand=expand,
fields=fields,
order_by=order_by,
external_id=external_id,
external_source=external_source,
)
response: PaginatedWorkItemResponse = client.work_items.list(
workspace_slug=workspace_slug,
project_id=project_id,
params=params,
)
return response.results
@mcp.tool()
def create_work_item(
project_id: str,
name: str,
assignees: list[str] | None = None,
labels: list[str] | None = None,
type_id: str | None = None,
point: int | None = None,
description_html: str | None = None,
description_stripped: str | None = None,
priority: PriorityEnum | str | None = None,
start_date: str | None = None,
target_date: str | None = None,
sort_order: float | None = None,
is_draft: bool | None = None,
external_source: str | None = None,
external_id: str | None = None,
parent: str | None = None,
state: str | None = None,
estimate_point: str | None = None,
type: str | None = None,
) -> WorkItem:
"""
Create a new work item.
Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
name: Work item name (required)
assignees: List of user IDs to assign to the work item
labels: List of label IDs to attach to the work item
type_id: UUID of the work item type
point: Story point value
description_html: HTML description of the work item
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 work item is a draft
external_source: External system source name
external_id: External system identifier
parent: UUID of the parent work item
state: UUID of the state
estimate_point: Estimate point value
type: Work item type identifier
Returns:
Created WorkItem object
"""
client, workspace_slug = get_plane_client_context()
data = CreateWorkItem(
name=name,
assignees=assignees,
labels=labels,
type_id=type_id,
point=point,
description_html=description_html,
description_stripped=description_stripped,
priority=priority,
start_date=start_date,
target_date=target_date,
sort_order=sort_order,
is_draft=is_draft,
external_source=external_source,
external_id=external_id,
parent=parent,
state=state,
estimate_point=estimate_point,
type=type,
)
return client.work_items.create(
workspace_slug=workspace_slug, project_id=project_id, data=data
)
@mcp.tool()
def retrieve_work_item(
project_id: str,
work_item_id: str,
expand: str | None = None,
fields: str | None = None,
external_id: str | None = None,
external_source: str | None = None,
order_by: str | None = None,
) -> WorkItemDetail:
"""
Retrieve a work item by ID.
Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
work_item_id: UUID of the work item
expand: Comma-separated fields to expand (e.g., "assignees,labels,state")
fields: Comma-separated fields to include in response
external_id: External system identifier for filtering
external_source: External system source name for filtering
order_by: Field to order results by (typically not used for single item retrieval)
Returns:
WorkItemDetail object with expanded relationships
"""
client, workspace_slug = get_plane_client_context()
params = RetrieveQueryParams(
expand=expand,
fields=fields,
external_id=external_id,
external_source=external_source,
order_by=order_by,
)
return client.work_items.retrieve(
workspace_slug=workspace_slug,
project_id=project_id,
work_item_id=work_item_id,
params=params,
)
@mcp.tool()
def retrieve_work_item_by_identifier(
project_identifier: str,
issue_identifier: int,
expand: str | None = None,
fields: str | None = None,
external_id: str | None = None,
external_source: str | None = None,
order_by: str | None = None,
) -> WorkItemDetail:
"""
Retrieve a work item by project identifier and issue sequence number.
Args:
workspace_slug: The workspace slug identifier
project_identifier: Project identifier string (e.g., "MP" for "My Project")
issue_identifier: Issue sequence number (e.g., 1, 2, 3)
expand: Comma-separated fields to expand (e.g., "assignees,labels,state")
fields: Comma-separated list of fields to include in response
external_id: External system identifier for filtering
external_source: External system source name for filtering
order_by: Field to order results by (typically not used for single item retrieval)
Returns:
WorkItemDetail object with expanded relationships
"""
client, workspace_slug = get_plane_client_context()
params = RetrieveQueryParams(
expand=expand,
fields=fields,
external_id=external_id,
external_source=external_source,
order_by=order_by,
)
return client.work_items.retrieve_by_identifier(
workspace_slug=workspace_slug,
project_identifier=project_identifier,
issue_identifier=issue_identifier,
params=params,
)
@mcp.tool()
def update_work_item(
project_id: str,
work_item_id: str,
name: str | None = None,
assignees: list[str] | None = None,
labels: list[str] | None = None,
type_id: str | None = None,
point: int | None = None,
description_html: str | None = None,
description_stripped: str | None = None,
priority: PriorityEnum | str | None = None,
start_date: str | None = None,
target_date: str | None = None,
sort_order: float | None = None,
is_draft: bool | None = None,
external_source: str | None = None,
external_id: str | None = None,
parent: str | None = None,
state: str | None = None,
estimate_point: str | None = None,
type: str | None = None,
) -> WorkItem:
"""
Update a work item by ID.
Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
work_item_id: UUID of the work item
name: Work item name
assignees: List of user IDs to assign to the work item
labels: List of label IDs to attach to the work item
type_id: UUID of the work item type
point: Story point value
description_html: HTML description of the work item
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 work item is a draft
external_source: External system source name
external_id: External system identifier
parent: UUID of the parent work item
state: UUID of the state
estimate_point: Estimate point value
type: Work item type identifier
Returns:
Updated WorkItem object
"""
client, workspace_slug = get_plane_client_context()
data = UpdateWorkItem(
name=name,
assignees=assignees,
labels=labels,
type_id=type_id,
point=point,
description_html=description_html,
description_stripped=description_stripped,
priority=priority,
start_date=start_date,
target_date=target_date,
sort_order=sort_order,
is_draft=is_draft,
external_source=external_source,
external_id=external_id,
parent=parent,
state=state,
estimate_point=estimate_point,
type=type,
)
return client.work_items.update(
workspace_slug=workspace_slug,
project_id=project_id,
work_item_id=work_item_id,
data=data,
)
@mcp.tool()
def delete_work_item(project_id: str, work_item_id: str) -> None:
"""
Delete a work item by ID.
Args:
workspace_slug: The workspace slug identifier
project_id: UUID of the project
work_item_id: UUID of the work item
"""
client, workspace_slug = get_plane_client_context()
client.work_items.delete(
workspace_slug=workspace_slug, project_id=project_id, work_item_id=work_item_id
)
@mcp.tool()
def search_work_items(
query: str,
expand: str | None = None,
fields: str | None = None,
external_id: str | None = None,
external_source: str | None = None,
order_by: str | None = None,
) -> WorkItemSearch:
"""
Search work items across a workspace.
Args:
workspace_slug: The workspace slug identifier
query: This is a free-form text search and will be used to search the work items
by name, description etc.
expand: Comma-separated list of related fields to expand in response
fields: Comma-separated list of fields to include in response
external_id: External system identifier for filtering
external_source: External system source name for filtering
order_by: Field to order results by. Prefix with '-' for descending order
Returns:
WorkItemSearch object containing search results
"""
client, workspace_slug = get_plane_client_context()
params = RetrieveQueryParams(
expand=expand,
fields=fields,
external_id=external_id,
external_source=external_source,
order_by=order_by,
)
return client.work_items.search(workspace_slug=workspace_slug, query=query, params=params)