API reference

MCP API

Connect MCPlan to any MCP-compatible client — Claude Desktop, Claude Code, Cursor, or a script you write yourself — and let it read and write your projects, sections, tasks, and labels.

Looking for the full tool list? Browse the MCP tool catalog.

Getting connected

  1. Sign in and generate an API key under Settings → API keys. Personal keys act on your personal workspace; organization keys act on an org (optionally scoped to a team).
  2. Point your MCP client at https://api.mcplan.ai/mcp and pass the key as a bearer token.
  3. All tool calls run server-side through Firestore with the caller's permissions. Every tool call and resource read counts against the caller's monthly cap: Free 50, Pro 1,000, Team 1,000 per seat (pooled across the org). Counters reset on the 1st of each month (UTC).

Hand-off from the UI

Every task in the MCPlan web app exposes three quick agent actions — available from the kebab menu in the task dialog and as a one-click ClipboardList icon in the task header:

  • Copy agent prompt. Copies a self-contained prompt (task id, project id, title, description, sub-tasks, web link, plus step-by-step MCP instructions) to the clipboard. Paste into any MCP-aware agent — the agent fetches the task with list_tasks / search_tasks, optionally reads attachments, does the work, then calls complete_task.
  • Open in Claude. Opens claude.ai/new in a new tab with the same prompt pre-filled — zero copy/paste.
  • Copy task link. Copies a shareable web URL of the form https://mcplan.ai/projects/<projectId>?task=<taskId> — paste into Slack, email, or any tracker to deep-link straight into the task dialog.

The prompt is fully customisable per user under Settings → Agents → Agent prompt template using handlebars-style placeholders ({{taskId}}, {{title}}, {{description}}, {{subtasks}}, {{webUrl}}, etc.) and conditional blocks {{#description}}…{{/description}}.

Projects

ToolInputNotes
list_projects{ orgId?: string }

List active projects for the authenticated caller.

Returns: Array of projects with `activeTaskCount`.

Without `orgId`, returns personal projects. With `orgId`, returns org projects (team-scoped keys are limited to their team).

create_project{ name, color?, view?: 'list' | 'board', icon? }

Create a personal project.

Returns: The new project document.

update_project{ projectId, name?, color?, view? }

Rename or restyle a project.

delete_project{ projectId }

Delete a project and cascade-delete every task inside it.

Sections

Sections live on the parent project document, not as standalone records. Use them to group tasks within a project.

ToolInputNotes
list_sections{ projectId }

List sections in a project, sorted by `order`.

Returns: `[{ id, name, order, description? }]`. `description` only present if set.

create_section{ projectId, name, description? }

Add a new section to the end of the project.

update_section{ projectId, sectionId, name?, description? }

Rename a section or set/clear its description.

Pass `description: ''` or `null` to clear. Section descriptions are visible in the edit dialog and appear in `list_sections` — good place to store context for AI workflows.

delete_section{ projectId, sectionId }

Remove a section. Tasks currently in the section become unassigned (not deleted).

Tasks

Subtasks are regular tasks with parentTaskId set. There is no hard depth limit, but the web UI renders two levels.

ToolInputNotes
list_tasks{ projectId, sectionId?, status?: 'active' | 'completed' | 'all', priority?: 1–4 }

List tasks in a project with optional filters.

Org members see every task in shared org projects. Non-members only see tasks they created or were assigned to.

create_task{ projectId, title, sectionId?, priority?: 1–4, dueDate?: 'YYYY-MM-DD', labels?: string[], description?, parentTaskId?, assignedTo?: string[], orgId?, teamId? }

Create a task in a project, optionally as a subtask.

Labels on the caller's API key are merged into `labels` automatically, so calls from a scoped key stay tagged.

update_task{ taskId, title?, description?, priority?, dueDate?: string | null, labels?, sectionId?: string | null }

Partial update — only provided fields are written.

complete_task{ taskId }

Mark a task completed (stamps `completedAt`).

delete_task{ taskId }

Delete a task and every subtask under it.

Returns: `{ success, taskId, deletedSubtasks: number }`.

search_tasks{ query?, priority?, labels?: string[], dueBefore?: 'YYYY-MM-DD', dueAfter?: 'YYYY-MM-DD' }

Search across all active tasks for the caller.

Text match is case-insensitive title substring. Limited to 100 results.

Labels

Labels are stored on the user document as a Record<string, { name, color }>. Tasks reference labels by ID, not name.

ToolInputNotes
list_labels{ }

List all labels defined on the caller's user document.

create_label{ name, color }

Create a label. Returns the generated label ID.

update_label{ labelId, name?, color? }

Rename or recolor a label.

delete_label{ labelId }

Delete a label. Existing tasks keep the label ID — rename or remove them manually if needed.

Import / export

MCPlan plans are round-trippable markdown documents. AI agents can draft a whole project in markdown, call import_plan, and later re-read the current state via export_plan.

ToolInputNotes
import_plan{ markdown }

Create a new project from a markdown plan document (see the format below).

Returns: The new project ID plus counts of imported sections and tasks.

export_plan{ projectId }

Serialize a project back to markdown.

Returns: Markdown string round-trippable through `import_plan` (subtasks, labels, priorities, descriptions preserved).

Plan markdown format

---
project: Launch checklist
color: "#4f46e5"
view: list
---

## Design
- [ ] Create wireframes
  id: task_1
  priority: 1
  due: 2026-05-01
  labels: [ui, design]
  description: Need mobile and desktop variants.
  - [ ] Mobile version
  - [x] Desktop version

## Engineering
- [ ] Implement auth
  priority: 2
  labels: [backend]
- [x] Set up repo

# Unsectioned
- [ ] Buy domain
  • YAML frontmatter carries project, color, view, and optional id for round-tripping.
  • ## Heading defines a section; tasks under it inherit that section.
  • Task metadata lives indented under the bullet (two-space indent):id, priority, due, labels, description.
  • Nested bullets become subtasks. - [x] marks a task completed.
  • A trailing # Unsectioned heading groups tasks not assigned to any section.

Organizations

ToolInputNotes
list_org_members{ orgId, teamId? }

List members of an organization (optionally scoped to one team).

Common workflows

Draft a plan from a rough spec

Ask the AI to draft a markdown plan, then call import_plan. You get a real project with real task IDs you can iterate on later.

Daily review

Call search_tasks with dueBefore: today and priority: 1 to surface the day's priorities. Use complete_task as you work through them.

Keep AI context fresh

Put long-running context (definitions, conventions, links) in update_section descriptions. Agents read them via list_sections without polluting task titles.

Scoped automations

Issue an API key with labels like ai or automation. Everything the key creates gets tagged automatically, so you can filter for AI-generated work in the web UI.