update_epic
Update an existing epic in Plane by providing its project and epic IDs, with optional changes to name, assignees, labels, priority, dates, and other fields.
Instructions
Update an epic by ID.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | UUID of the project | |
| epic_id | Yes | UUID of the epic | |
| name | No | Epic name | |
| assignees | No | List of user IDs to assign to the epic | |
| labels | No | List of label IDs to attach to the epic | |
| point | No | Story point value | |
| description_html | No | HTML description of the epic | |
| description_stripped | No | Plain text description (stripped of HTML) | |
| priority | No | Priority level (urgent, high, medium, low, none) | |
| start_date | No | Start date (ISO 8601 format) | |
| target_date | No | Target/end date (ISO 8601 format) | |
| sort_order | No | Sort order value | |
| is_draft | No | Whether the epic is a draft | |
| external_source | No | External system source name | |
| external_id | No | External system identifier | |
| state | No | UUID of the state | |
| estimate_point | No | Estimate point value |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | ||
| deleted_at | No | ||
| created_at | No | ||
| updated_at | No | ||
| point | No | ||
| name | Yes | ||
| description | No | ||
| description_html | No | ||
| description_stripped | No | ||
| description_binary | No | ||
| priority | No | ||
| start_date | No | ||
| target_date | No | ||
| sequence_id | No | ||
| sort_order | No | ||
| completed_at | No | ||
| archived_at | No | ||
| is_draft | No | ||
| external_source | No | ||
| external_id | No | ||
| created_by | No | ||
| updated_by | No | ||
| project | Yes | ||
| workspace | Yes | ||
| parent | No | ||
| state | No | ||
| estimate_point | No | ||
| type | No | ||
| assignees | No | ||
| labels | No |
Implementation Reference
- plane_mcp/tools/epics.py:154-236 (handler)The main handler function for the 'update_epic' tool. It takes project_id, epic_id, and various optional fields, validates priority, constructs an UpdateWorkItem payload, calls client.work_items.update() to update the epic, and then retrieves and returns the updated Epic via client.epics.retrieve().
@mcp.tool() def update_epic( project_id: str, epic_id: str, name: str | None = None, assignees: list[str] | None = None, labels: list[str] | None = None, point: int | None = None, description_html: str | None = None, description_stripped: str | None = None, priority: 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, state: str | None = None, estimate_point: str | None = None, ) -> Epic: """ Update an epic by ID. Args: project_id: UUID of the project epic_id: UUID of the epic name: Epic name assignees: List of user IDs to assign to the epic labels: List of label IDs to attach to the epic 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 state: UUID of the state estimate_point: Estimate point value Returns: Updated Epic object """ client, workspace_slug = get_plane_client_context() # Validate priority against allowed literal values valid_priorities = get_args(PriorityEnum) if priority is not None and priority not in valid_priorities: raise ValueError(f"Invalid priority '{priority}'. Must be one of: {valid_priorities}") validated_priority: PriorityEnum | None = priority # type: ignore[assignment] data = UpdateWorkItem( name=name, assignees=assignees, labels=labels, point=point, description_html=description_html, description_stripped=description_stripped, priority=validated_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, state=state, estimate_point=estimate_point, ) work_item = client.work_items.update( workspace_slug=workspace_slug, project_id=project_id, work_item_id=epic_id, data=data, ) return client.epics.retrieve( workspace_slug=workspace_slug, project_id=project_id, epic_id=work_item.id, ) - plane_mcp/tools/epics.py:11-14 (schema)Import of UpdateWorkItem from plane.models.work_items, which is the schema/model used to structure the data payload for the update.
from plane.models.work_items import ( CreateWorkItem, UpdateWorkItem, ) - plane_mcp/tools/epics.py:19-19 (registration)The register_epic_tools function that registers all epic tools (including update_epic) with the FastMCP server via the @mcp.tool() decorator.
def register_epic_tools(mcp: FastMCP) -> None: - plane_mcp/tools/__init__.py:47-47 (registration)The call to register_epic_tools(mcp) inside the register_tools function, which is the top-level registration entry point.
register_epic_tools(mcp) - plane_mcp/tools/__init__.py:6-6 (registration)Import of register_epic_tools from plane_mcp.tools.epics in the tools package __init__.py.
from plane_mcp.tools.epics import register_epic_tools