Metadata-Version: 2.4
Name: plane-mcp-server-ce
Version: 0.3.0
Summary: Community Edition and self-hosted focused MCP server for Plane
Author-email: Surya Prashanth <surya.prashanth@plane.so>, Plane Engineering <support@plane.so>, tancou <commun@app.optimis.io>
License-Expression: MIT
Project-URL: Homepage, https://github.com/tancou/plane-mcp-server-ce
Project-URL: Repository, https://github.com/tancou/plane-mcp-server-ce
Project-URL: Issues, https://github.com/tancou/plane-mcp-server-ce/issues
Keywords: mcp,plane,fastmcp,ai,automation
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastmcp==3.2.0
Requires-Dist: plane-sdk==0.2.19
Requires-Dist: py-key-value-aio[redis]<0.5.0,>=0.4.4
Requires-Dist: mcp==1.26.0
Requires-Dist: PyJWT>=2.12.0
Requires-Dist: authlib>=1.6.9
Requires-Dist: boto3>=1.34.0
Requires-Dist: fakeredis[lua]<2.35.0,>=2.32.1
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Dynamic: license-file

# Plane MCP Server CE

> [!IMPORTANT]
> ## Community Edition and self-hosted first
>
> This fork exists to provide the broadest possible MCP compatibility with the
> free, self-hosted **Plane Community Edition**. It is not intended for upstream
> contribution: its focus is making every capability that CE actually exposes
> usable by AI agents, while keeping Cloud-only and paid features out of their
> tool list.
>
> Issues and pull requests that improve Plane CE or self-hosted compatibility
> are warmly welcome. Contributions authored with AI coding agents are welcome
> too, provided they are clean, reviewed, and remain aligned with this CE and
> self-hosted focus.

A Model Context Protocol (MCP) server for Plane integration. This package is
published on PyPI as `plane-mcp-server-ce` and provides tools and resources for
interacting with self-hosted Plane CE through AI agents.

## Features

* 🔧 **Plane Integration**: Interact with Plane APIs and services
* 🔌 **Multiple Transports**: Supports stdio, SSE, and streamable HTTP transports
* 🌐 **Remote & Local**: Works both locally and as a remote service
* 🛠️ **Extensible**: Easy to add new tools and resources

## Usage

The server supports three transport methods. **We recommend using `uvx`** as it doesn't require installation.

**Requirements**:
- **Python 3.10+** (for stdio transport, via `uvx`)
- **Node.js 22+** (for remote transports, via `npx`)

### 1. Stdio Transport (for local use)

**MCP Client Configuration** (using uvx - recommended):

```json
{
  "mcpServers": {
    "plane": {
      "command": "uvx",
      "args": ["plane-mcp-server-ce", "stdio"],
      "env": {
        "PLANE_API_KEY": "<your-api-key>",
        "PLANE_WORKSPACE_SLUG": "<your-workspace-slug>",
        "PLANE_BASE_URL": "https://<your-self-hosted-plane-url>",
        "PLANE_MCP_EDITION": "community"
      }
    }
  }
}
```

### 2. Remote HTTP Transport with OAuth

Connect to the hosted Plane MCP server using OAuth authentication.

**URL**: `https://mcp.plane.so/http/mcp`

**MCP Client Configuration** (for tools like Claude Desktop without native remote MCP support):

```json
{
  "mcpServers": {
    "plane": {
      "command": "npx",
      "args": ["mcp-remote@latest", "https://mcp.plane.so/http/mcp"]
    }
  }
}
```

**Note**: OAuth authentication will be handled automatically when connecting to the remote server.

### 3. Remote HTTP Transport using PAT Token

Connect to the hosted Plane MCP server using a Personal Access Token (PAT).

**URL**: `https://mcp.plane.so/http/api-key/mcp`

**Headers**:
- `Authorization: Bearer <PAT_TOKEN>`
- `X-Workspace-slug: <SLUG>`

**MCP Client Configuration** (for tools like Claude Desktop without native remote MCP support):

```json
{
  "mcpServers": {
    "plane": {
      "command": "npx",
      "args": ["mcp-remote@latest", "https://mcp.plane.so/http/api-key/mcp"],
      "headers": {
        "Authorization": "Bearer <PAT_TOKEN>",
        "X-Workspace-slug": "<SLUG>"
      }
    }
  }
}
```

### 4. SSE Transport (Legacy)

⚠️ **Legacy Transport**: SSE (Server-Sent Events) transport is maintained for backward compatibility. New implementations should use the HTTP transport (sections 2 or 3) instead.

Connect to the hosted Plane MCP server using OAuth authentication via Server-Sent Events.

**URL**: `https://mcp.plane.so/sse`

**MCP Client Configuration** (for tools that support SSE transport):

```json
{
  "mcpServers": {
    "plane": {
      "command": "npx",
      "args": ["mcp-remote@latest", "https://mcp.plane.so/sse"]
    }
  }
}
```

**Note**: OAuth authentication will be handled automatically when connecting to the remote server. This transport is deprecated in favor of the HTTP transport.


## Configuration

### Authentication

The server requires authentication via environment variables:

- `PLANE_BASE_URL`: Base URL for Plane API (default: `https://api.plane.so`) - Optional
- `PLANE_API_KEY`: API key for authentication (required for stdio transport)
- `PLANE_WORKSPACE_SLUG`: Workspace slug identifier (required for stdio transport)
- `PLANE_ACCESS_TOKEN`: Access token for authentication (alternative to API key)
- `PLANE_MCP_EDITION`: Tool discovery mode: `community` (or `ce`) exposes only
  tools verified against Plane CE; `cloud` (or `all`) exposes the complete SDK
  surface; `auto` is the default and treats a configured non-`*.plane.so` API
  URL as self-hosted. Set `community` explicitly for predictable self-hosted
  deployments, especially if you use a custom Cloud domain.

**Example** (for stdio transport):
```bash
export PLANE_BASE_URL="https://api.plane.so"
export PLANE_API_KEY="your-api-key"
export PLANE_WORKSPACE_SLUG="your-workspace-slug"
export PLANE_MCP_EDITION="community"
```

**Note**: For remote HTTP transports (OAuth or PAT), authentication is handled via the connection method (OAuth flow or PAT headers) and does not require these environment variables.

### OAuth redirect URIs

For the OAuth HTTP/SSE transports, the server validates each client's redirect URI against an allowlist. Common MCP clients (Cursor, VS Code, Claude.ai, ChatGPT connectors, localhost) are allowed by default.

To onboard a new client without a code change or release, append extra patterns via an environment variable:

- `PLANE_OAUTH_ALLOWED_REDIRECT_URIS`: Comma-separated redirect URI patterns appended to the built-in allowlist.

```bash
export PLANE_OAUTH_ALLOWED_REDIRECT_URIS="https://newclient.com/cb,https://other.app/oauth/*"
```

Patterns support glob matching (`*` matches any port, path segment, or subdomain). For security, keep the host pinned and wildcard only the port/path.

### Logging

The server emits structured JSON logs. Each tool call is logged with its tool name, duration, status, and (when available) the opaque user id and workspace slug.

- `LOG_USER_INFO`: When `true`, include user info (PII such as the display name) in logs alongside the opaque user id. Defaults to `false` so PII is never logged unless explicitly opted in. Only the OAuth and PAT (header) HTTP transports carry a display name; stdio is unaffected.

```bash
export LOG_USER_INFO="true"
```

## Available Tools

The server provides comprehensive tools for interacting with Plane. All tools use Pydantic models from the Plane SDK for type safety and validation.

### Community Edition availability

Set `PLANE_MCP_EDITION=community` to prevent unavailable tools from being
advertised to an agent. This keeps the MCP tool list focused on functionality
that exists on the free, self-hosted edition instead of returning cryptic 404
errors. The detailed endpoint evidence is maintained in [CE_COMPAT.md](CE_COMPAT.md).

| Capability group | Available in CE mode | Notes |
|---|---:|---|
| Projects, members, cycles, modules, labels, states, intake items | Yes | CE-compatible endpoints, including the CE fallback for `*-lite` lists. |
| Work items, search, activities, comments, links, attachments | Yes | Detail reads automatically expand assignees and labels. |
| Work item relations | Partial | Listing and creating the eight built-in relation types work; CE stable exposes no deletion route. |
| Work item property definitions and options | Partial | Definition tools remain exposed; per-item property values are not available. |
| Feature flags, roles, initiatives, milestones | No | Cloud-only / paid API surface. |
| Work logs, archived work items, estimates | No | Endpoints are absent from the tested CE API. |
| Pages, work item types, custom relation definitions | No | Pages exist in the CE UI, but only through legacy session-authenticated `/api/...` routes; PAT-based MCP access is unavailable. The other endpoints are absent. |

The category tables below describe the full SDK surface. Rows marked **No** or
**Partial** above are deliberately omitted from MCP discovery in Community
Edition mode.

### Projects

| Tool Name | Description |
|-----------|-------------|
| `list_projects` | List all projects in a workspace with optional pagination and filtering |
| `create_project` | Create a new project with name, identifier, and optional configuration |
| `retrieve_project` | Retrieve a project by ID |
| `update_project` | Update a project with partial data |
| `delete_project` | Delete a project by ID |
| `get_project_worklog_summary` | Get work log summary for a project |
| `get_project_members` | Get all members of a project |
| `update_project_features` | Update features configuration of a project |

### Work Items

| Tool Name | Description |
|-----------|-------------|
| `list_work_items` | List all work items in a project with optional filtering and pagination |
| `create_work_item` | Create a new work item with name, assignees, labels, and other attributes |
| `retrieve_work_item` | Retrieve a work item by ID with optional field expansion |
| `retrieve_work_item_by_identifier` | Retrieve a work item by project identifier and issue sequence number |
| `update_work_item` | Update a work item with partial data |
| `delete_work_item` | Delete a work item by ID |
| `search_work_items` | Search work items across a workspace with query string |

### Cycles

| Tool Name | Description |
|-----------|-------------|
| `list_cycles` | List cycles in a project (set `archived=true` for archived) |
| `create_cycle` | Create a new cycle with name, dates, and owner |
| `retrieve_cycle` | Retrieve a cycle by ID |
| `update_cycle` | Update a cycle with partial data |
| `delete_cycle` | Delete a cycle by ID |
| `manage_cycle_work_items` | Add and/or remove work items on a cycle |
| `list_cycle_work_items` | List work items in a cycle |
| `transfer_cycle_work_items` | Transfer work items from one cycle to another |
| `manage_cycle_archive` | Archive or unarchive a cycle |

### Modules

| Tool Name | Description |
|-----------|-------------|
| `list_modules` | List modules in a project (set `archived=true` for archived) |
| `create_module` | Create a new module with name, dates, status, and members |
| `retrieve_module` | Retrieve a module by ID |
| `update_module` | Update a module with partial data |
| `delete_module` | Delete a module by ID |
| `manage_module_work_items` | Add and/or remove work items on a module |
| `list_module_work_items` | List work items in a module |
| `manage_module_archive` | Archive or unarchive a module |

### Initiatives

| Tool Name | Description |
|-----------|-------------|
| `list_initiatives` | List all initiatives in a workspace |
| `create_initiative` | Create a new initiative with name, dates, state, and lead |
| `retrieve_initiative` | Retrieve an initiative by ID |
| `update_initiative` | Update an initiative with partial data |
| `delete_initiative` | Delete an initiative by ID |

### Intake Work Items

| Tool Name | Description |
|-----------|-------------|
| `list_intake_work_items` | List all intake work items in a project with optional pagination |
| `create_intake_work_item` | Create a new intake work item in a project |
| `retrieve_intake_work_item` | Retrieve an intake work item by work item ID with optional field expansion |
| `update_intake_work_item` | Update an intake work item with partial data |
| `delete_intake_work_item` | Delete an intake work item by work item ID |

### Work Item Properties

| Tool Name | Description |
|-----------|-------------|
| `list_work_item_properties` | List work item properties for a work item type |
| `create_work_item_property` | Create a new work item property with type, settings, and validation rules |
| `retrieve_work_item_property` | Retrieve a work item property by ID |
| `update_work_item_property` | Update a work item property with partial data |
| `delete_work_item_property` | Delete a work item property by ID |

### Milestones

| Tool Name | Description |
|-----------|-------------|
| `list_milestones` | List all milestones in a project |
| `create_milestone` | Create a new milestone |
| `retrieve_milestone` | Retrieve a milestone by ID |
| `update_milestone` | Update a milestone by ID |
| `delete_milestone` | Delete a milestone by ID |
| `manage_milestone_work_items` | Add and/or remove work items on a milestone |
| `list_milestone_work_items` | List work items in a milestone |

### Labels

| Tool Name | Description |
|-----------|-------------|
| `list_labels` | List all labels in a project |
| `create_label` | Create a new label |
| `retrieve_label` | Retrieve a label by ID |
| `update_label` | Update a label by ID |
| `delete_label` | Delete a label by ID |

### States

| Tool Name | Description |
|-----------|-------------|
| `list_states` | List all states in a project |
| `create_state` | Create a new state |
| `retrieve_state` | Retrieve a state by ID |
| `update_state` | Update a state by ID |
| `delete_state` | Delete a state by ID |

### Work Item Comments

| Tool Name | Description |
|-----------|-------------|
| `list_work_item_comments` | List comments for a work item |
| `retrieve_work_item_comment` | Retrieve a specific comment for a work item |
| `create_work_item_comment` | Create a comment for a work item |
| `update_work_item_comment` | Update a comment for a work item |
| `delete_work_item_comment` | Delete a comment for a work item |

### Work Item Links

| Tool Name | Description |
|-----------|-------------|
| `list_work_item_links` | List links for a work item |
| `retrieve_work_item_link` | Retrieve a specific link for a work item |
| `create_work_item_link` | Create a link for a work item |
| `update_work_item_link` | Update a link for a work item |
| `delete_work_item_link` | Delete a link for a work item |

### Work Item Types

| Tool Name | Description |
|-----------|-------------|
| `list_work_item_types` | List all work item types in a project |
| `create_work_item_type` | Create a new work item type |
| `retrieve_work_item_type` | Retrieve a work item type by ID |
| `update_work_item_type` | Update a work item type by ID |
| `delete_work_item_type` | Delete a work item type by ID |
| `import_work_item_types_to_project` | Bulk-link workspace-level work item types to a project |
| `resolve_work_item_type` | Find or create a named type for a project, auto-handling workspace vs project scope and import |

### Work Item Relations

| Tool Name | Description |
|-----------|-------------|
| `list_work_item_relations` | List relations for a work item |
| `create_work_item_relation` | Create relations for a work item |
| `remove_work_item_relation` | Remove a relation from a work item |

### Work Item Relation Definitions

| Tool Name | Description |
|-----------|-------------|
| `list_work_item_relation_definitions` | List workspace custom relation definitions |
| `create_work_item_relation_definition` | Create a workspace relation definition |
| `update_work_item_relation_definition` | Update a relation definition |
| `delete_work_item_relation_definition` | Delete a relation definition |

### Work Item Activities

| Tool Name | Description |
|-----------|-------------|
| `list_work_item_activities` | List activities for a work item |
| `retrieve_work_item_activity` | Retrieve a specific activity for a work item |

### Work Logs

| Tool Name | Description |
|-----------|-------------|
| `list_work_logs` | List work logs for a work item |
| `create_work_log` | Create a work log for a work item |
| `update_work_log` | Update a work log for a work item |
| `delete_work_log` | Delete a work log for a work item |

### Pages

| Tool Name | Description |
|-----------|-------------|
| `list_pages` | List pages (workspace, or a project's if `project_id` given) |
| `retrieve_page` | Retrieve a page by ID (workspace, or project's if `project_id` given) |
| `create_page` | Create a workspace or project page |

### Workspaces

| Tool Name | Description |
|-----------|-------------|
| `get_workspace_members` | Get all members of the current workspace |
| `get_features` | Get feature flags (workspace, or a project's if `project_id` given) |
| `update_workspace_features` | Update features of the current workspace |

### Users

| Tool Name | Description |
|-----------|-------------|
| `get_me` | Get current authenticated user information |

**Total Tools**: 100+ tools across 20 categories

## Development

### Running Tests

```bash
pytest
```

### Code Formatting

```bash
black plane_mcp/
ruff check plane_mcp/
```

## License

MIT License - see LICENSE for details.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Deprecation Notice

⚠️ **The Node.js-based `plane-mcp-server` is deprecated and no longer maintained.**

This repository represents the new Python+FastMCP based implementation of the Plane MCP server. If you were using the previous Node.js version, please migrate to this Python-based version for continued support and updates.

The new implementation offers:
- Better type safety with Pydantic models
- Improved performance with FastMCP
- Enhanced tool coverage
- Active maintenance and development

For migration assistance, please refer to the configuration examples in this README or open an issue for support.

**Old Node.js Configuration (Deprecated):**

If you were using the previous Node.js-based `@makeplane/plane-mcp-server`, your configuration looked like this:

```json
{
  "mcpServers": {
    "plane": {
      "command": "npx",
      "args": [
        "-y",
        "@makeplane/plane-mcp-server"
      ],
      "env": {
        "PLANE_API_KEY": "<YOUR_API_KEY>",
        "PLANE_API_HOST_URL": "<HOST_URL_FOR_SELF_HOSTED>",
        "PLANE_WORKSPACE_SLUG": "<YOUR_WORKSPACE_SLUG>"
      }
    }
  }
}
```

**Please migrate to the new Python-based configuration shown in the Usage section above.**

## Releasing `plane-mcp-server-ce`

Maintainers should follow [RELEASING.md](RELEASING.md). The first publication
creates the PyPI project; never commit a PyPI token to this repository.
