Skip to main content

Plane MCP Server

CI License: MIT Python 3.10+ Built with FastMCP MCP

An MCP server that exposes the Plane REST API to AI clients (Claude, Cursor, VS Code, Codex, …). Built with FastMCP.

It authenticates as a Plane personal access token and acts on a single workspace, giving the model tools to read and manage projects, work items, states, labels, cycles, modules, members and comments.

Requirements

  • Python 3.10+
  • A Plane account and a personal access token: Plane → Profile settings → Personal access tokens → Add personal access token
  • Your workspace slug — the segment in your Plane URL: https://app.plane.so/<workspace-slug>/projects/

Install

From PyPI — package plane-mcp-oss:

uvx plane-mcp-oss            # run without installing
# or
pip install plane-mcp-oss    # installs the `plane-mcp` and `plane-mcp-oss` commands

From source:

uv sync            # installs fastmcp + httpx into .venv
# or, without uv:
pip install -e .

Configure

The server targets one Plane instance and one workspace. Settings are resolved with the following precedence (highest wins):

  1. CLI flags (--base-url, --workspace, --api-key)
  2. Process environment variables
  3. A .env file in the working directory (loaded automatically)
  4. Built-in defaults
Variable Alias Required Default Purpose
PLANE_API_KEY PLANE_TOKEN yes* — Personal access token, sent as X-API-Key.
PLANE_OAUTH_TOKEN — yes* — OAuth access token, sent as Authorization: Bearer ….
PLANE_WORKSPACE_SLUG PLANE_WORKSPACE yes — Target workspace slug.
PLANE_BASE_URL PLANE_URL no https://api.plane.so Plane instance URL.
PLANE_TIMEOUT — no 30 Request timeout (seconds).

* One of PLANE_API_KEY / PLANE_OAUTH_TOKEN is required.

Pointing at a self-hosted instance

PLANE_BASE_URL accepts whatever you copy from your browser. The /api/v1 suffix is added automatically when needed:

PLANE_BASE_URL=https://api.plane.so            # Plane Cloud (default)
PLANE_BASE_URL=https://plane.example.com       # self-hosted
PLANE_BASE_URL=https://example.com/plane       # self-hosted behind a subpath
PLANE_BASE_URL=https://plane.example.com/api/v1  # already versioned

CLI flags

plane-mcp --base-url https://plane.example.com/plane \
          --workspace my-team \
          --api-key plane_api_xxxx

Check what the server resolved — without leaking the token:

$ plane-mcp --show-config --base-url https://plane.example.com/plane --workspace my-team --api-key xxx
{
  "base_url": "https://plane.example.com/plane/api/v1",
  "workspace_slug": "my-team",
  "auth": "api_key",
  "timeout": 30.0
}

Copy .env.example for a template; a .env file is loaded from the working directory (change it with --env-file, or pass --env-file '' to skip).

Run

# stdio — how MCP clients launch it locally
PLANE_API_KEY=... PLANE_WORKSPACE_SLUG=my-team uv run plane-mcp

# streamable HTTP
PLANE_API_KEY=... PLANE_WORKSPACE_SLUG=my-team uv run plane-mcp --transport http --port 8000

python -m plane_mcp and python main.py are equivalent entry points.

Add to your MCP client

{
  "mcpServers": {
    "plane": {
      "command": "uv",
      "args": ["--directory", "/path/to/plane-mcp-oss", "run", "plane-mcp"],
      "env": {
        "PLANE_API_KEY": "<your-token>",
        "PLANE_WORKSPACE_SLUG": "<your-workspace-slug>",
        "PLANE_BASE_URL": "https://api.plane.so"
      }
    }
  }
}

Tools

Tool What it does
get_current_user Profile of the token's user.
list_workspace_members Workspace members (to resolve assignee UUIDs).
list_projects / get_project Browse projects (paginated).
create_project / update_project Create or edit a project.
list_work_items / get_work_item Browse work items in a project (paginated).
get_work_item_by_identifier Look up e.g. PROJ-123 directly.
search_work_items Text search across names/identifiers (works everywhere).
advanced_search_work_items Filter-based search; permission-gated, may return 403.
create_work_item / update_work_item / delete_work_item Manage work items.
list_states Workflow states — get the UUID before setting state.
list_labels / create_label Project labels.
list_cycles / list_modules Sprints and modules.
list_comments / add_comment / update_comment / delete_comment Work item comments.
list_pages / get_page / create_page / update_page Pages — workspace wiki or project (omit/ pass project_id).
archive_page / restore_page / delete_page Page lifecycle; delete requires archiving first.

List tools return {results, count, total_results, next_cursor}; pass next_cursor back to page through results.

Resources: plane://me, plane://projects, plane://projects/{id}/states. Prompts: triage_work_items.

Notes on the API

  • Work item state, assignees and labels take UUIDs, not names. Call list_states / list_labels / list_workspace_members first.
  • description is plain text and is converted to the description_html the API expects; description_html overrides it when supplied.
  • Priority is one of urgent, high, medium, low, none.
  • The API allows 60 requests/minute per key; the client surfaces 429 as a tool error so the model can retry.

Architecture

src/plane_mcp/
├── config.py   # env-driven Settings + validation
├── client.py   # async httpx wrapper: auth, URLs, error translation, pagination
├── server.py   # FastMCP instance, tool/resource/prompt definitions, CLI
└── __main__.py # `python -m plane_mcp`
tests/          # offline: httpx.MockTransport + in-memory FastMCP client

client.py has no FastMCP dependency, so it is reusable and easy to test; the server layer only maps tools to client calls and turns PlaneAPIError into ToolError for clean MCP error messages.

Known limitations

  • Pages are Plane Cloud only. The public Pages REST API is not part of the open-source Community Edition — it is absent from the API URL routing at v1.3.1, v1.4.2 and master (apps/api/plane/api/urls/ registers asset, cycle, intake, label, member, module, project, state, user, work_item, invite and sticky — no pages). On a self-hosted instance, pages exist in the UI behind an internal session API (/api/…) that rejects X-API-Key and Bearer tokens, so the page tools will 404 there. They work against Plane Cloud, where the documented /api/v1/…/pages/ routes exist. The page tools detect this and return an explanatory error rather than a bare 404.
  • advanced_search_work_items is permission-gated on some workspaces and editions and can return 403. Use search_work_items or list_work_items as a fallback.
  • Not implemented yet: work item links, attachments, activity feed, and custom properties/types, though the Plane API supports them.

Development

uv run pytest        # 12 offline tests, no credentials needed

Extending

Add a method to PlaneClient for the endpoint you need (see the API reference), then register a tool in server.py:

@mcp.tool
async def list_pages(project_id: str) -> dict[str, Any]:
    """List a project's pages."""
    client = get_client()
    data = await _call(client.request("GET", client._workspace("projects", project_id, "pages")))
    return summarize_paginated(data)

Contributing

Contributions are welcome! See CONTRIBUTING.md for the development setup, how to add a tool, and commit/PR guidelines. This project follows the Contributor Covenant Code of Conduct.

Security

Please report vulnerabilities privately — see SECURITY.md. Never commit real credentials; .env is git-ignored.

License

Released under the MIT License. © 2026 Abel Santillan Rodriguez.

See CHANGELOG.md for release history.

Release files for plane-mcp-oss 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for plane-mcp-oss 0.1.0
File Size Uploaded
plane_mcp_oss-0.1.0.tar.gz 143.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for plane-mcp-oss 0.1.0
File Interpreter ABI Platform
plane_mcp_oss-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 162.4 kB

Release files / plane_mcp_oss-0.1.0.tar.gz

Download URL plane_mcp_oss-0.1.0.tar.gz
Size 143.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d9ebaf7deb91629b11d8360d98de97ded6f06daf67285e22b241f45070b332c5
BLAKE2b-256 checksum
How to use checksums
767dc5bf4aa1655801e2ec78ae84038181a619289b70c09b60404a55d4d2f7ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.

Transparency log

Release files / plane_mcp_oss-0.1.0-py3-none-any.whl

Download URL plane_mcp_oss-0.1.0-py3-none-any.whl
Size 19.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
940a35e1d2f9201588946fa477c6eac38eba74297312f4842003065e0611ebf5
BLAKE2b-256 checksum
How to use checksums
30e68e3b7a7b96b62d042e52785c82ec5e380d4c244e177b02d12d1869e284fc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page