Skip to main content
Glama
goto-software

plane-mcp-server

list_work_items

List and search work items within a project or across the entire workspace. Filter by assignee, state, priority, labels, and more to find items matching your criteria.

Instructions

List work items in a project or search across the workspace.

When any filter parameter is provided (assignee_ids, state_ids, state_groups, priorities, label_ids, type_ids, cycle_ids, module_ids, is_archived, created_by_ids, or query), this uses the advanced search endpoint which supports powerful filtering. Otherwise it uses the standard list endpoint.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_idNoUUID of the project. Required when no filters are provided. Optional when using filters (omit for workspace-wide search).
queryNoFree-form text search across work item name and description
assignee_idsNoList of user UUIDs to filter by assignee
state_idsNoList of state UUIDs to filter by state
state_groupsNoList of state groups to filter by (backlog, unstarted, started, completed, cancelled)
prioritiesNoList of priority values to filter by (urgent, high, medium, low, none)
label_idsNoList of label UUIDs to filter by label
type_idsNoList of work item type UUIDs to filter by type
cycle_idsNoList of cycle UUIDs to filter by cycle
module_idsNoList of module UUIDs to filter by module
is_archivedNoFilter by archived status (true/false)
created_by_idsNoList of user UUIDs to filter by creator
workspace_searchNoWhen true, search across all projects in the workspace. Only used with filters. Defaults to false.
limitNoMaximum number of results (only used with filters, default 25)
cursorNoPagination cursor for getting next set of results (list only)
per_pageNoNumber of results per page, 1-100 (list only)
expandNoComma-separated list of related fields to expand in response (list only, e.g. "assignees,labels,state")
fieldsNoComma-separated list of fields to include in response (list only)
order_byNoField to order results by, prefix with '-' for descending (list only)
external_idNoExternal system identifier for filtering (list only)
external_sourceNoExternal system source name for filtering (list only)

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The main handler function for the 'list_work_items' tool. It uses advanced search if filters/query are provided, otherwise falls back to the standard list endpoint.
    def list_work_items(
        project_id: str | None = None,
        query: str | None = None,
        assignee_ids: list[str] | None = None,
        state_ids: list[str] | None = None,
        state_groups: list[str] | None = None,
        priorities: list[str] | None = None,
        label_ids: list[str] | None = None,
        type_ids: list[str] | None = None,
        cycle_ids: list[str] | None = None,
        module_ids: list[str] | None = None,
        is_archived: bool | None = None,
        created_by_ids: list[str] | None = None,
        workspace_search: bool = False,
        limit: int | None = None,
        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[AdvancedSearchResult]:
        """
        List work items in a project or search across the workspace.
    
        When any filter parameter is provided (assignee_ids, state_ids, state_groups,
        priorities, label_ids, type_ids, cycle_ids, module_ids, is_archived,
        created_by_ids, or query), this uses the advanced search endpoint which
        supports powerful filtering. Otherwise it uses the standard list endpoint.
    
        Args:
            project_id: UUID of the project. Required when no filters are provided.
                Optional when using filters (omit for workspace-wide search).
            query: Free-form text search across work item name and description
            assignee_ids: List of user UUIDs to filter by assignee
            state_ids: List of state UUIDs to filter by state
            state_groups: List of state groups to filter by
                (backlog, unstarted, started, completed, cancelled)
            priorities: List of priority values to filter by
                (urgent, high, medium, low, none)
            label_ids: List of label UUIDs to filter by label
            type_ids: List of work item type UUIDs to filter by type
            cycle_ids: List of cycle UUIDs to filter by cycle
            module_ids: List of module UUIDs to filter by module
            is_archived: Filter by archived status (true/false)
            created_by_ids: List of user UUIDs to filter by creator
            workspace_search: When true, search across all projects in the workspace.
                Only used with filters. Defaults to false.
            limit: Maximum number of results (only used with filters, default 25)
            cursor: Pagination cursor for getting next set of results (list only)
            per_page: Number of results per page, 1-100 (list only)
            expand: Comma-separated list of related fields to expand in response
                (list only, e.g. "assignees,labels,state")
            fields: Comma-separated list of fields to include in response (list only)
            order_by: Field to order results by, prefix with '-' for descending (list only)
            external_id: External system identifier for filtering (list only)
            external_source: External system source name for filtering (list only)
    
        Returns:
            List of WorkItem objects (unfiltered) or AdvancedSearchResult objects (filtered)
        """
        client, workspace_slug = get_plane_client_context()
    
        filters = _build_advanced_search_filters(
            assignee_ids=assignee_ids,
            state_ids=state_ids,
            state_groups=state_groups,
            priorities=priorities,
            label_ids=label_ids,
            type_ids=type_ids,
            cycle_ids=cycle_ids,
            module_ids=module_ids,
            is_archived=is_archived,
            created_by_ids=created_by_ids,
        )
    
        if filters is not None or query is not None:
            data = AdvancedSearchWorkItem(
                query=query,
                filters=filters,
                limit=limit,
                project_id=project_id,
                workspace_search=workspace_search or None,
            )
            return client.work_items.advanced_search(
                workspace_slug=workspace_slug,
                data=data,
            )
    
        if project_id is None:
            raise ValueError("project_id is required when no filters are provided")
    
        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
  • Helper function that builds AND filter conditions (assignee, state, priority, label, type, cycle, module, archived, created_by) used by list_work_items for advanced search.
    def _build_advanced_search_filters(
        *,
        assignee_ids: list[str] | None = None,
        state_ids: list[str] | None = None,
        state_groups: list[str] | None = None,
        priorities: list[str] | None = None,
        label_ids: list[str] | None = None,
        type_ids: list[str] | None = None,
        cycle_ids: list[str] | None = None,
        module_ids: list[str] | None = None,
        is_archived: bool | None = None,
        created_by_ids: list[str] | None = None,
    ) -> dict[str, Any] | None:
        """Build an AND filter dict from flat filter params."""
        conditions: list[dict[str, Any]] = []
        if assignee_ids:
            conditions.append({"assignee_id__in": assignee_ids})
        if state_ids:
            conditions.append({"state_id__in": state_ids})
        if state_groups:
            conditions.append({"state_group__in": state_groups})
        if priorities:
            conditions.append({"priority__in": priorities})
        if label_ids:
            conditions.append({"label_id__in": label_ids})
        if type_ids:
            conditions.append({"type_id__in": type_ids})
        if cycle_ids:
            conditions.append({"cycle_id__in": cycle_ids})
        if module_ids:
            conditions.append({"module_id__in": module_ids})
        if is_archived is not None:
            conditions.append({"is_archived": is_archived})
        if created_by_ids:
            conditions.append({"created_by_id__in": created_by_ids})
        if not conditions:
            return None
        if len(conditions) == 1:
            return conditions[0]
        return {"and": conditions}
  • The @mcp.tool() decorator on line 67 registers 'list_work_items' as an MCP tool via FastMCP.
    def register_work_item_tools(mcp: FastMCP) -> None:
        """Register all work item-related tools with the MCP server."""
    
        @mcp.tool()
  • Top-level registration: register_tools() calls register_work_item_tools(mcp) which registers the list_work_items tool.
    def register_tools(mcp: FastMCP) -> None:
        """Register all tools with the MCP server."""
        register_project_tools(mcp)
        register_work_item_tools(mcp)
        register_work_item_activity_tools(mcp)
        register_work_item_comment_tools(mcp)
        register_work_item_link_tools(mcp)
        register_work_item_relation_tools(mcp)
        register_work_log_tools(mcp)
        register_cycle_tools(mcp)
        register_user_tools(mcp)
        register_module_tools(mcp)
        register_initiative_tools(mcp)
        register_intake_tools(mcp)
        register_label_tools(mcp)
        register_page_tools(mcp)
        register_work_item_property_tools(mcp)
        register_work_item_type_tools(mcp)
        register_state_tools(mcp)
        register_workspace_tools(mcp)
        register_epic_tools(mcp)
        register_milestone_tools(mcp)
  • The function signature defines the input schema (project_id, filter params, pagination, etc.) and return type (list[WorkItem] | list[AdvancedSearchResult]).
    def list_work_items(
        project_id: str | None = None,
        query: str | None = None,
        assignee_ids: list[str] | None = None,
        state_ids: list[str] | None = None,
        state_groups: list[str] | None = None,
        priorities: list[str] | None = None,
        label_ids: list[str] | None = None,
        type_ids: list[str] | None = None,
        cycle_ids: list[str] | None = None,
        module_ids: list[str] | None = None,
        is_archived: bool | None = None,
        created_by_ids: list[str] | None = None,
        workspace_search: bool = False,
        limit: int | None = None,
        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[AdvancedSearchResult]:
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses the endpoint switching behavior but does not mention the read-only nature, authentication requirements, or rate limits. However, the output schema covers return values, and pagination details are present in the parameter schema, compensating partially. The description does not contradict any annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is only two sentences, efficiently conveying the key differentiator (endpoint selection based on filters) without any redundant information. It is front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a listing tool with 21 parameters and an output schema, the description adequately explains the two operating modes and the role of project_id. Pagination is detailed in the schema, so no further description needed. The description lacks mention of authentication or common limits, but these are often implicit and the output schema fills in return details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds value by explaining that any filter triggers the advanced search endpoint, which is not evident from the schema alone. This helps the agent understand the behavior change based on parameter presence.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists work items within a project or across the workspace, distinguishing two operational modes (with or without filters). It effectively differentiates from more specific sibling tools like list_cycle_work_items or list_milestone_work_items by being the general listing/search function.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains when to use the standard list endpoint (no filters) versus the advanced search endpoint (when any filter is provided). It also notes that project_id is required only when no filters are used. However, it does not differentiate from the sibling search_work_items, which may cause slight ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/goto-software/plane-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server