Skip to main content
Glama

Plane MCP

A Model Context Protocol server for Plane (self-hosted or Cloud). It lets an LLM client — Claude Desktop, Claude Code, Cursor, etc. — fully drive your Plane workspace: discover projects, and create / read / update / delete / re-organize work items, states, labels, cycles, modules, and comments.

Verified against a self-hosted instance at plane.nzminds.com (workspace nzmt).

What it can do

Resource

Tools

Projects

list_projects, find_project, get_project, create_project, update_project, delete_project

Work items

list_work_items, get_work_item, get_work_item_by_number, search_work_items, create_work_item, update_work_item, set_work_item_status, delete_work_item

States (statuses)

list_states, find_state, create_state, update_state, delete_state

Labels

list_labels, create_label, update_label, delete_label

Cycles (sprints)

list_cycles, get_cycle, create_cycle, update_cycle, delete_cycle, list_cycle_work_items, add_work_items_to_cycle, remove_work_item_from_cycle

Modules

list_modules, get_module, create_module, update_module, delete_module, list_module_work_items, add_work_items_to_module, remove_work_item_from_module

Comments

list_comments, add_comment, update_comment, delete_comment

Members

list_members, find_member

Related MCP server: Plane MCP Server

How Plane's model works (quick mental model)

Workspace (slug, e.g. "nzmt")
 └─ Project (UUID)           ← discover with list_projects
     ├─ Work Items / Issues  ← the tickets; have a UUID + human number (TRAVELXS-391)
     ├─ States               ← the statuses (Backlog/Todo/In Progress/Done…), each a UUID
     ├─ Labels               ← UUIDs
     ├─ Cycles               ← time-boxed sprints
     └─ Modules              ← feature groupings

Everything in a request body is a UUID, not a name. So the normal flow is:

  1. list_projects → pick a project UUID.

  2. list_states → map "In Progress" → its UUID. list_members / list_labels likewise.

  3. Create/update the work item. To change status, set state to the target state UUID (or use set_work_item_status).

Most tools take an optional project_id; if omitted they fall back to PLANE_DEFAULT_PROJECT_ID from your .env.

Setup

1. Get an API key

See SETUP.md for step-by-step instructions (Profile Settings → Personal Access Tokens).

2. Configure

cp .env.example .env
# edit .env: PLANE_BASE_URL, PLANE_API_KEY, PLANE_WORKSPACE_SLUG

3. Install

Requires Python ≥ 3.10.

python -m pip install -e .

(or with uv: uv pip install -e .)

4. Run

plane-mcp          # or:  python -m plane_mcp

It speaks MCP over stdio, so you normally don't run it by hand — your MCP client launches it.

Connecting to a client

Claude Desktop / Claude Code

Add to your MCP config (claude_desktop_config.json, or via claude mcp add):

{
  "mcpServers": {
    "plane": {
      "command": "plane-mcp",
      "env": {
        "PLANE_BASE_URL": "https://plane.nzminds.com",
        "PLANE_API_KEY": "plane_api_xxxxxxxx",
        "PLANE_WORKSPACE_SLUG": "nzmt"
      }
    }
  }
}

Or, if you'd rather rely on the .env file, drop the env block and use the absolute interpreter:

{
  "mcpServers": {
    "plane": {
      "command": "python",
      "args": ["-m", "plane_mcp"],
      "cwd": "d:/Govind/Plane MCP"
    }
  }
}

Claude Code one-liner:

claude mcp add plane -- python -m plane_mcp

Example prompts once connected

  • "List my projects in Plane."

  • "In TravelXS, create a high-priority bug 'Login fails on Safari' and assign it to govind.kumar."

  • "Move TRAVELXS-391 to In Progress."

  • "Create a cycle 'Sprint 12' from 2026-07-01 to 2026-07-14 and add TRAVELXS-394 and -376 to it."

  • "Add a comment to TRAVELXS-308 saying the fix is deployed."

Notes & limits

  • Rate limit: 60 requests/min per key. The client auto-retries on 429 with backoff.

  • Pagination: list tools follow Plane's cursor pagination and return all results.

  • Destructive ops: the hard delete_* tools (project, work item, state, label, cycle, module, comment) are disabled by default. Set PLANE_ALLOW_DELETE=true in .env to expose them. Relationship removals (remove_work_item_from_cycle / _module) are always available since they're reversible.

  • Self-hosted path quirk: cycle/module work-item sub-resources are /cycle-issues/ and /module-issues/ (the public docs say work_items, which 404s on self-hosted). This server uses the verified paths.

Project layout

src/plane_mcp/
├── config.py        # env loading & validation
├── client.py        # async HTTP client: pagination, 429 retry, errors
├── server.py        # FastMCP instance + tool registration
├── __main__.py      # entry point (stdio)
└── tools/           # one module per resource
    ├── projects.py  issues.py  states.py  labels.py
    ├── cycles.py    modules.py comments.py members.py

License

MIT

Available Tools

38 tools
add_commentB

Add a comment to a work item. comment_html accepts HTML, e.g. 'Looks good'. access: INTERNAL or EXTERNAL.

Inputs: issue_id (required), comment_html (required), access, project_id. Returns: object

add_work_items_to_cycleC

Add one or more work items (by UUID) to a cycle.

Inputs: cycle_id (required), issue_ids (required), project_id. Returns: object

add_work_items_to_moduleB

Add one or more work items (by UUID) to a module.

Inputs: issue_ids (required), module_id (required), project_id. Returns: object

create_cycleC

Create a cycle. Dates are 'YYYY-MM-DD'. owned_by is a member UUID.

Inputs: name (required), end_date, owned_by, project_id, +2 more. Returns: object

create_labelB

Create a label. color is a hex like '#FF0000'.

Inputs: name (required), color, project_id, description. Returns: object

create_moduleB

Create a module. status: backlog|planned|in-progress|paused|completed|cancelled. lead/members are member UUIDs.

Inputs: name (required), lead, status, members, +4 more. Returns: object

create_projectB

Create a project. identifier is the short code (e.g. 'WEB'), uppercase and unique in the workspace. network: 0=secret, 2=public.

Inputs: name (required), identifier (required), network, description, +2 more. Returns: object

create_stateC

Create a state. color is a hex like '#60646C'. group must be one of: backlog, unstarted, started, completed, cancelled.

Inputs: name (required), color (required), group (required), project_id, +1 more. Returns: object

create_work_itemB

Create a work item. Only name is required.

  • priority: none|urgent|high|medium|low

  • state: a STATE UUID (use list_states to find it)

  • assignees/labels: lists of UUIDs (use list_members / list_labels)

  • dates: 'YYYY-MM-DD'

Inputs: name (required), state, labels, parent, +7 more. Returns: object

find_memberA

Find members whose email or display name contains query (case-insensitive). Returns matches so you can pick the right UUID.

Inputs: query (required). Returns: result

find_projectA

Find projects whose name or identifier contains query (case-insensitive). Handy when you only know the project name.

Inputs: query (required). Returns: result

find_stateA

Find a state by (case-insensitive) name and return it, or None.

Inputs: name (required), project_id. Returns: result

get_cycleB

Get a single cycle by UUID.

Inputs: cycle_id (required), project_id. Returns: object

get_moduleB

Get a single module by UUID.

Inputs: module_id (required), project_id. Returns: object

get_projectA

Get full details of a single project by its UUID.

Inputs: project_id (required). Returns: object

get_work_itemA

Get a single work item by its UUID.

Inputs: issue_id (required), expand, project_id. Returns: object

get_work_item_by_numberA

Look up a work item by its human number (e.g. 391 for TRAVELXS-391).

Inputs: sequence_id (required), project_id.

list_commentsA

List all comments on a work item.

Inputs: issue_id (required), project_id. Returns: result

list_cyclesA

List a project's cycles (sprints) with their UUIDs and dates.

Inputs: project_id. Returns: result

list_cycle_work_itemsB

List the work items assigned to a cycle.

Inputs: cycle_id (required), project_id. Returns: result

list_labelsA

List a project's labels with their UUIDs (needed to tag work items).

Inputs: project_id. Returns: result

list_membersA

List workspace members with their UUIDs, emails, and display names. Use the returned member UUID for assignees, owned_by, lead, etc.

Inputs: no named parameters. Returns: result

list_modulesA

List a project's modules with their UUIDs.

Inputs: project_id. Returns: result

list_module_work_itemsB

List the work items assigned to a module.

Inputs: module_id (required), project_id. Returns: result

list_projectsA

List all projects in the workspace. Use this to discover project IDs, names, and identifiers (the short code like 'TRAVELXS').

Inputs: no named parameters. Returns: result

list_statesA

List a project's states (statuses) with their UUIDs, names, and groups. Call this first to map a status name like 'In Progress' to its UUID before creating/updating work items.

Inputs: project_id. Returns: result

list_work_itemsA

List all work items in a project (paginated automatically). expand inlines related objects; default expands state/assignees/labels. Omit project_id to use PLANE_DEFAULT_PROJECT_ID.

Inputs: expand, project_id. Returns: result

remove_work_item_from_cycleC

Remove a single work item from a cycle.

Inputs: cycle_id (required), issue_id (required), project_id. Returns: object

remove_work_item_from_moduleB

Remove a single work item from a module.

Inputs: issue_id (required), module_id (required), project_id. Returns: object

search_work_itemsB

Full-text search work items in a project by name/content.

Inputs: query (required), project_id.

set_work_item_statusA

Change a work item's status by setting its state UUID. Convenience wrapper around update_work_item. Use list_states to map a status name (Backlog/Todo/In Progress/Done...) to its UUID.

Inputs: state (required), issue_id (required), project_id. Returns: object

update_commentC

Edit an existing comment.

Inputs: issue_id (required), comment_id (required), comment_html (required), project_id. Returns: object

update_cycleC

Update a cycle. Only provided fields change.

Inputs: cycle_id (required), name, end_date, project_id, +2 more. Returns: object

update_labelA

Update a label. Only provided fields change.

Inputs: label_id (required), name, color, project_id, +1 more. Returns: object

update_moduleB

Update a module. Only provided fields change.

Inputs: module_id (required), lead, name, status, +5 more. Returns: object

update_projectB

Update a project's editable fields. Only provided fields change.

Inputs: project_id (required), name, description, project_lead, +1 more. Returns: object

update_stateB

Update a state. Only provided fields change.

Inputs: state_id (required), name, color, group, +2 more. Returns: object

update_work_itemB

Update any fields of a work item. Only provided fields change. To change STATUS, pass state with the target state's UUID. To clear assignees/labels, pass an empty list [].

Inputs: issue_id (required), name, state, labels, +8 more. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.1/5.0

    Scored across 38 tools

    Disambiguation4/5

    Tools are generally distinct, with clear separation via resource type (project, work item, cycle, module, comment, label, member, state) and action. The main overlap is set_work_item_status being a convenience wrapper around update_work_item, but descriptions clarify the purpose. Some pairs like list_projects/find_project could be confused but are well-defined.

    Naming Consistency5/5

    Names follow a consistent verb_noun pattern (list_*, get_*, create_*, update_*, find_*, add_*, remove_*). Variations like get_work_item_by_number and set_work_item_status are logically extended forms, not inconsistent. The convention is uniform across all 38 tools.

    Tool Count2/5

    With 38 tools, the server is well over the 25+ threshold that typically indicates too many. While the scope is broad (multiple project management entities), the set includes many similar list/get/update tools per resource, making it feel heavy. A more streamlined set could consolidate some operations.

    Completeness3/5

    The server covers create, read, and update for most resources, plus work item status changes and assignment to cycles/modules. However, there are no delete operations for any entity (projects, work items, labels, cycles, modules, comments, states), which is a notable gap in CRUD coverage. Also missing get_label and get_comment, but these are less critical.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      D
      maintenance
      A Model Context Protocol (MCP) server that enables LLMs to interact with Plane.so, allowing them to manage projects and issues through Plane's API. Using this server, LLMs like Claude can directly interact with your project management workflows while maintaining user control and security.
      76
      13 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server for the Plane project management platform that enables users to manage workspaces, projects, and work items. It supports full CRUD operations for issues while providing access to cycles, modules, labels, and workflow states.
      MIT