Plane MCP server: setup, tools, auth and read-only use
The Plane MCP server is the official Model Context Protocol server for Plane, the open-source project-management tool. It lets an agent read and change projects, work items, cycles, modules, pages and more in your Plane workspace. Plane publishes it as makeplane/plane-mcp-server and also runs it hosted at https://mcp.plane.so/http/mcp.
Below: endpoints, auth, config for Claude Code, Codex, Cursor and ChatGPT, what the tools can change, and how to stop it changing more than you want. Details are as of 2026-11-07 and come from Plane’s docs and repo.
Official or community
The official server is the Python package plane-mcp-server in the makeplane GitHub org, MIT licensed, built on FastMCP and Plane’s plane-sdk. It needs Python 3.10+ and uv when you run it locally.
The older Node package @makeplane/plane-mcp-server is, in the repo’s words, deprecated and unmaintained. If an old blog post tells you to npx @makeplane/plane-mcp-server, use the Python server instead. If you migrate, rename PLANE_API_HOST_URL to PLANE_BASE_URL.
Endpoints
From Plane’s MCP server docs:
| Transport | Endpoint | Auth |
|---|---|---|
| Streamable HTTP (recommended) | https://mcp.plane.so/http/mcp |
OAuth |
| Streamable HTTP | https://mcp.plane.so/http/api-key/mcp |
Personal or workspace access token |
| Local stdio | uvx plane-mcp-server stdio |
PLANE_API_KEY + PLANE_WORKSPACE_SLUG |
| SSE | https://mcp.plane.so/sse |
Deprecated |
Auth: API key and workspace slug
OAuth. Your client sends you to Plane, you sign in and pick a workspace, and the connection is bound to that workspace. OAuth requests read and write scopes.
Access token. Create one under Profile Settings → Personal Access Tokens, or Workspace Settings → Access Tokens for automations. Every request carries two headers:
Authorization: Bearer <PAT>
x-workspace-slug: <workspace-slug>
The workspace slug is the path segment after app.plane.so/. Plane’s docs flag that the server now reads the standard Authorization: Bearer header, so configs that sent the token another way need updating.
Local stdio. Two required environment variables and one optional:
| Variable | Required | Meaning |
|---|---|---|
PLANE_API_KEY |
yes | Your access token |
PLANE_WORKSPACE_SLUG |
yes | The workspace to act in |
PLANE_BASE_URL |
no | Defaults to https://api.plane.so; set it for self-hosted Plane |
Whatever the method, the server acts as the authenticated user. Plane’s docs: “Plane enforces workspace and project roles, so a Guest cannot do more through MCP.”
Connect it to Claude Code
OAuth, then sign in from inside Claude Code with /mcp (or claude mcp login plane):
claude mcp add --transport http plane https://mcp.plane.so/http/mcp
Access token. The --header flags go after the URL:
claude mcp add --transport http plane https://mcp.plane.so/http/api-key/mcp \
--header "Authorization: Bearer <PAT>" \
--header "x-workspace-slug: <workspace-slug>"
Local stdio:
claude mcp add --transport stdio plane \
--env PLANE_API_KEY=<your-api-key> \
--env PLANE_WORKSPACE_SLUG=<your-workspace-slug> \
-- uvx plane-mcp-server stdio
Add --scope local, project or user to choose where the entry is saved. Check it with claude mcp list.
Connect it to Codex
OAuth:
codex mcp add plane --url https://mcp.plane.so/http/mcp
codex mcp login plane
codex mcp list
Access token, in ~/.codex/config.toml. Codex sends Authorization: Bearer $PLANE_PAT; other headers are config-file only:
[mcp_servers.plane]
url = "https://mcp.plane.so/http/api-key/mcp"
bearer_token_env_var = "PLANE_PAT"
http_headers = { "x-workspace-slug" = "<workspace-slug>" }
Connect it to Cursor
In ~/.cursor/mcp.json. Remote entries use url and must not include a type key.
{
"mcpServers": {
"plane": {
"url": "https://mcp.plane.so/http/mcp"
}
}
}
Access token:
{
"mcpServers": {
"plane": {
"url": "https://mcp.plane.so/http/api-key/mcp",
"headers": {
"Authorization": "Bearer ${env:PLANE_PAT}",
"x-workspace-slug": "<workspace-slug>"
}
}
}
}
Connect it to ChatGPT
Turn on Developer mode, then add a connector at chatgpt.com/plugins with the OAuth URL https://mcp.plane.so/http/mcp. Plane’s docs: “ChatGPT does not accept custom headers, so use OAuth.”
Any other client
The generic stdio entry, from the repo README:
{
"mcpServers": {
"plane": {
"command": "uvx",
"args": ["plane-mcp-server", "stdio"],
"env": {
"PLANE_API_KEY": "<your-api-key>",
"PLANE_WORKSPACE_SLUG": "<your-workspace-slug>"
}
}
}
}
A stdio-only client can reach the hosted server through mcp-remote (Node.js 22+):
{
"mcpServers": {
"plane": {
"command": "npx",
"args": ["mcp-remote@latest", "https://mcp.plane.so/http/mcp"]
}
}
}
Windsurf and Antigravity use serverUrl instead of url. VS Code uses .vscode/mcp.json with a servers key and "type": "http".
The tools it exposes
Since 0.3 the server exposes 30 tools, one per Plane resource, covering 207 operations. Each tool takes an action parameter. Creating a work item looks like workitem(action="create", project_id=..., name="Fix login").
The tool names, from the tools README:
| Area | Tools |
|---|---|
| Work items | workitem, workitem_comment, workitem_link, workitem_relation, workitem_attachment, workitem_activity, workitem_property, workitem_type, work_log, label, state, intake |
| Planning | cycle, module, milestone, initiative, project_estimate |
| Releases | release, release_label, release_tag |
| Projects and workspace | project, workspace, member, template |
| Docs | page, collection |
| Customers | customer, customer_property, customer_request |
| Query help | get_pql_reference |
There are no epic tools. Epics are work items of type “Epic”: resolve the type with workitem_type, then create or list with that type id.
If your config or prompts use the 0.2.x per-operation names (create_work_item, list_cycles and so on), 169 of the 177 old names still resolve as aliases. The other seven return a message naming their replacement.
What it can change versus read
Almost every tool can write. The workitem tool alone has list, retrieve, search and count, and also create, update, delete and archive. project can delete and archive projects. cycle can complete and transfer_workitems. page, module, release and the customer tools all have delete.
Three tools are read-only by their action list: get_pql_reference, workitem_activity (list, retrieve) and member (me, list_workspace, list_project, list_roles, retrieve_role).
Each action is declared with flags such as read=True or destructive=True, and the server derives its MCP annotations from them. Plane’s docs say read-only tools carry the readOnlyHint annotation and destructive ones carry destructiveHint.
Run it read-only or scoped to one project
Plane’s docs say it outright: “There is no separate read-only endpoint.” Your options, strongest first:
1. Use a role-limited Plane account. The server can do only what the authenticated user can do. A dedicated account with a Guest role, or with membership in only one project, caps what any agent can reach. Plane recommends a workspace access token “with the minimum role needed for automations.” This is also the only way to scope to one project: there is no per-project setting on the connection. OAuth binds one workspace, and a token connection is scoped by its x-workspace-slug.
2. Filter tools in the client. This works at tool level, and since one tool holds both reads and deletes, denying workitem removes work items entirely.
Claude Code accepts a deny or ask rule for a whole server or one tool. To be asked before any Plane call:
{
"permissions": {
"ask": ["mcp__plane__*"]
}
}
To block one action rather than the whole tool, Claude Code’s permissions docs say parameter rules on MCP tools must be passed with --disallowedTools; settings files skip any mcp__ rule that has parentheses:
claude --disallowedTools "mcp__plane__workitem(action:delete)"
Codex has an allow list, a deny list and approval modes per server (Codex MCP docs):
[mcp_servers.plane]
url = "https://mcp.plane.so/http/mcp"
enabled_tools = ["workitem", "cycle", "get_pql_reference", "member"]
disabled_tools = ["project"]
default_tools_approval_mode = "writes"
writes prompts only for tools not marked read-only. With Plane’s mixed tools, expect that to mean most calls prompt.
3. Turn the server off when you are not using it. enabled = false in Codex, or remove the entry.
Self-hosted Plane
The hosted server cannot reach a private instance. Run stdio with PLANE_BASE_URL pointing at your API, or deploy the server yourself. Check your key first:
curl -H "x-api-key: $PLANE_API_KEY" "https://plane.yourcompany.com/api/v1/users/me/"
A 200 means the key works. Plane’s docs say OAuth self-hosting needs Plane Cloud or Commercial Edition; Community Edition should use stdio.
Common errors
| Symptom | Cause | Fix |
|---|---|---|
| 401 on a token connection | Wrong or revoked token, or old header | Send Authorization: Bearer <PAT> |
| 401 on OAuth | Session expired | Re-authenticate (/mcp in Claude Code, codex mcp login plane) |
| “workspace slug missing” | Header left out | Add x-workspace-slug |
| 404 | Wrong slug or id | Check the segment after app.plane.so/ |
| 403 | Your Plane role is too low | Ask for the needed workspace or project role |
| 402 | Plan-gated feature | The message names the feature |
| 400 | Bad argument | Check the action’s required fields |
mcp-remote won’t start |
Old Node | Node.js 22+ and npx -y mcp-remote@latest |
| Server not listed | Bad JSON or wrong schema | Trailing commas; url vs serverUrl; no type in Cursor |
| Only the first page of projects | Pagination | Follow next_cursor or pass per_page |
For a stuck OAuth session through mcp-remote, rm -rf ~/.mcp-auth clears it, along with every other mcp-remote cache. Set MCP_REMOTE_CONFIG_DIR to keep Plane’s separate. To debug, claude --debug and claude mcp list show what Claude Code loaded.
What this does not cover
Client-side tool filters live in each agent’s own config. A filter written for Claude Code does nothing in Cursor, and Plane’s role model is the only limit that holds across every client. If you run ACP, its rules can allow, ask or deny an MCP tool by name, with the same rule on every harness whose hook sees MCP calls and one log of each call. See the coverage table for which harnesses those are. That is still tool-level, so it has the same limit as above: workitem is one tool, reads and deletes together. For how Plane’s controls compare with other MCP servers, see /mcp-controls.
Frequently asked questions
plane mcp server: is there an official one?
Yes. Plane publishes it as makeplane/plane-mcp-server on GitHub, a Python server run with uvx or used hosted at https://mcp.plane.so/http/mcp. The older Node package @makeplane/plane-mcp-server is deprecated and unmaintained.
plane mcp claude code: what is the command?
For OAuth: claude mcp add –transport http plane https://mcp.plane.so/http/mcp, then run /mcp in Claude Code to sign in. For a personal access token, point the same command at https://mcp.plane.so/http/api-key/mcp and add –header “Authorization: Bearer
Can I run the Plane MCP server read-only?
There is no read-only endpoint. Plane’s docs point you to your client’s tool allow-list or deny-list. Since 0.3 each tool bundles reads and writes behind an action parameter, so a tool-level deny removes a whole resource; a role-limited Plane account is the cleaner way to cap writes.
mcp plane: why do I get 401 or 'workspace slug missing'?
A 401 on a token connection means a wrong or revoked token, or the old header: send Authorization: Bearer
Where to read more
- Plane MCP server docs: endpoints, every client’s config, troubleshooting
- makeplane/plane-mcp-server: source, README, releases
- Tool and action list: all 30 tools and their actions
- Claude Code permissions:
mcp__rules and--disallowedTools - Codex MCP config:
enabled_tools,disabled_tools, approval modes
Running coding agents? ACP records each tool call its hook sees and makes the dangerous shell commands (a force-push, destructive SQL, curl | sh) wait for you. One command, free up to 5 agents:
curl -fsSL https://agenticcontrolplane.com/install.sh | bash
irm https://agenticcontrolplane.com/install.ps1 | iex