Skip to main content
Glama
bhflm

plane-mcp

by bhflm

plane-mcp

Local MCP server for a self-hosted Plane instance. Exposes tickets (work items), cycles, modules, labels, and states as MCP tools, plus a small set of mutation tools (label add/remove, state changes, ticket create/update, module attach).

The Plane API key is read only from the PLANE_API_KEY environment variable. It is never logged, never printed, and never included in tool output — errors are redacted before being returned.

Setup

npm install
npm run build

export PLANE_BASE_URL="https://your-plane-instance.example.com"
export PLANE_API_KEY="..."
export PLANE_DEFAULT_WORKSPACE="..."          # optional
export PLANE_DEFAULT_PROJECT_ID="..."         # optional
export PLANE_DEFAULT_PROJECT_IDENTIFIER="..." # optional
export PLANE_ENABLE_WRITES="false"            # optional; must be true for mutations

Copy .env.example to .env for reference (placeholders only — never commit a real .env).

Run

npm start
# or during development:
npm run dev

The server speaks MCP over stdio.

MCP client config (stdio)

{
  "mcpServers": {
    "plane": {
      "command": "node",
      "args": ["/absolute/path/to/plane-mcp/dist/src/index.js"],
      "env": {
        "PLANE_BASE_URL": "https://your-plane-instance.example.com",
        "PLANE_API_KEY": "${PLANE_API_KEY}",
        "PLANE_DEFAULT_WORKSPACE": "${PLANE_DEFAULT_WORKSPACE}",
        "PLANE_DEFAULT_PROJECT_ID": "${PLANE_DEFAULT_PROJECT_ID}",
        "PLANE_ENABLE_WRITES": "false"
      }
    }
  }
}

Exposed tools

Tool

Purpose

plane_list_workspaces

List accessible workspaces

plane_list_projects

List projects in a workspace

plane_resolve_project

Resolve a project identifier (e.g. SDK) to its UUID

plane_search_tickets

Search work items by query/key

plane_get_ticket

Fetch a full ticket by UUID or key (e.g. SDK-250)

plane_list_cycles

List cycles (sprints/milestones)

plane_get_current_cycle

Fetch the current active cycle

plane_list_cycle_tickets

List tickets in a cycle

plane_list_current_cycle_tickets

One-shot "what's in the current cycle"; link summaries by default

plane_list_modules

List modules (epics/milestones)

plane_list_module_tickets

List tickets in a module

plane_list_labels

List labels for a project

plane_add_labels_to_ticket

Add labels without clobbering existing ones

plane_remove_labels_from_ticket

Remove labels from a ticket

plane_update_ticket

Patch basic ticket fields

plane_add_comment

Add a comment to a ticket/work item

plane_list_states

List states/statuses

plane_set_ticket_state

Move a ticket to a state by name or id

plane_create_ticket

Create a ticket, optionally attach to cycle/module

plane_add_ticket_to_module

Attach an existing ticket to a module

plane_get_ticket_children

List child tickets by filtering on parent

Tools return normalized, allowlisted summaries rather than raw Plane API records. Mutating tools accept dry_run: boolean for previews. Real writes are disabled unless PLANE_ENABLE_WRITES=true is set, and each mutating call must also pass confirm: true; successful ticket updates are verified by re-fetching the record afterward, while comment creation returns the created comment from Plane.

plane_add_comment accepts either comment_text or comment_html. comment_text is escaped and converted to simple paragraph HTML before it is sent to Plane. Comments default to access: "INTERNAL" unless supplied.

Testing

npm test

Unit tests mock fetch — no real Plane API key is required. Coverage includes: auth header presence without leaking the key, redaction of secrets from errors and result payloads, safe path construction, bounded cursor pagination, schema limits, ticket-key normalization, and label-union (non-clobbering) behavior.

Smoke test

With real credentials exported (see Setup), you can drive the server directly with the MCP inspector, or manually via any MCP-compatible client pointed at node dist/src/index.js. A minimal manual check:

node --input-type=module -e "
import { PlaneClient } from './dist/src/planeClient.js';
const client = new PlaneClient({
  baseUrl: process.env.PLANE_BASE_URL,
  apiKey: process.env.PLANE_API_KEY,
  defaultWorkspace: process.env.PLANE_DEFAULT_WORKSPACE,
});
console.log(await client.paginate('/api/v1/workspaces/'));
"

Known quirks (self-hosted Plane)

  • GET /api/v1/workspaces/ may 404 (no cross-workspace listing endpoint on some self-hosted deployments). Set PLANE_DEFAULT_WORKSPACE and use workspace-scoped tools directly instead of relying on plane_list_workspaces.

  • Advanced search may return no results when project_id is included; the client retries workspace-wide and filters client-side.

  • Cycle-issue and module-issue list endpoints may return link objects ({ issue: <uuid> }) rather than full ticket records. Current-cycle tools keep link summaries by default; pass include_full_tickets: true to join normalized ticket summaries.

Security

  • Credentials are read only from environment variables (PLANE_API_KEY, PLANE_BASE_URL).

  • The API key is never printed, logged, or embedded in responses.

  • Errors (HTTP failures, network failures, JSON parse failures) are passed through a redactor before being surfaced to the MCP client.

  • Tool arguments used in Plane URL paths are validated and encoded before request construction.

  • Tool outputs are allowlisted and redacted; raw Plane API records are not returned to MCP clients.

  • Writes are off by default and require both PLANE_ENABLE_WRITES=true and confirm: true on each mutating call.

  • .env is gitignored; only .env.example with placeholders is committed.

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

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/bhflm/plane-mcp'

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