# API reference

> Every MCP tool with its parameters, and how to call the same tools over the REST API.

Agents reach planpage through the MCP server at `https://app.planpa.ge/mcp`. Scripts and CI can call the same tools over HTTPS. Both act as an agent connection, so the connection's workspaces and access levels apply; see [Agents and access](https://planpage.dev/docs/agents-and-access.md).

Tools marked *Read only* work at every access level. The rest need **Publish only** or **Publish and run**. Tools that carry out plans (`claim_step`, `release_step`, `update_step`, `link_ref`, `complete_plan` and `pick_up_brief`) need **Publish and run**.

Errors come back as a plain message saying what went wrong and, where it helps, what to do, for example "This plan has no approved version yet." Over REST, the HTTP status also says what kind of error it is: 400 for invalid arguments, 403 when the connection isn't allowed to do it, 404 for something that doesn't exist (including an unknown tool), 409 when the document changed since you read it, and 500 for a fault on planpage's side, which is worth retrying.

## Docs for agents

These docs are also available as plain markdown, so agents don't have to read rendered pages:

- `https://planpa.ge/llms.txt` lists every page with a one-line description, in the [llms.txt](https://llmstxt.org) format.
- `https://planpa.ge/llms-full.txt` is every page in one file.
- Any page as markdown: add `.md` to its address, such as `https://planpa.ge/docs/connect-an-agent.md`, or request the normal address with `Accept: text/markdown`.

Each docs page also links its markdown version in its `<head>` and in a `Link` header. All of it is built from the same source as these pages, so it is always current.

## REST API

Every MCP tool is also available over HTTPS, for scripts and CI.

| Request | What it does |
| --- | --- |
| `GET https://app.planpage.dev/api/v1/tools` | Lists every tool with its JSON schema. |
| `POST https://app.planpage.dev/api/v1/tools/<name>` | Calls a tool. The JSON body is the tool's arguments; the response is `{ "result": … }` or `{ "error": … }`. |

Authenticate with an API token from **Your account → Agent connections**:

```sh
curl -s https://app.planpage.dev/api/v1/tools/whoami -X POST \
  -H "Authorization: Bearer pp_…" -H "content-type: application/json" -d '{}'
```

The token acts with the access levels it was given in each workspace.

## MCP tools

planpage has 44 tools. Agents see the same names and descriptions.

### `ask_human`

**Ask a human.** Add a blocking question to the document and notify the reviewers. Read the answer later with get_feedback.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `prompt` | string | Yes |  |
| `options` | list of string | No |  |

### `claim_step`

**Claim step.** Claim a step so other agents don't work on it. Claims expire (default 30 min) and renew when you update the step.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `step` | string | Yes | Step block id, e.g. s1 |
| `ttl_seconds` | integer | No |  |

### `comment`

**Comment.** Start a comment thread, optionally anchored to a block.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `body` | string | Yes |  |
| `block_id` | string | No |  |

### `complete_plan`

**Complete plan.** Finish an approved plan with a report: steps done, skipped and added, and how the result differs from the plan.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `report_markdown` | string | Yes |  |
| `title` | string | No |  |

### `create_project`

**Create project.** Create a project in your personal workspace or an organization you can write to. In a folder without a usable git remote, list_repositories suggests GitHub repositories (and their names) to link.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes |  |
| `repo_url` | string | No |  |
| `organization_id` | string | No | From whoami's workspaces. Omit for your personal workspace. |

### `delete_image`

**Delete image.** Delete an image uploaded by you or one of your agents. Its URL stops working everywhere it's used, including GitHub, and documents show a placeholder. Copies already cached by browsers or GitHub's image proxy may linger until they expire. Only do this when the user asks.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `image_id` | string | Yes |  |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |

### `diff_versions`

**Diff versions.** Unified diff between two versions (or a version and the working copy). *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |
| `from` | integer | Yes |  |
| `to` | integer | No |  |

### `edit_blocks`

**Edit blocks.** Targeted edits by block id (from read_document_blocks): replace, insert_after, insert_before, delete, append. Leaves the rest of the document untouched.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `edits` | list of value | Yes |  |
| `base_revision` | integer | No |  |
| `save_version` | boolean | Yes |  |
| `summary` | string | No |  |

### `find_people`

**Find people.** Look people up to invite or share with. People you already work with match by name or username; anyone else only by their exact username#0000. Needs the connection to be allowed to invite people and share documents. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `query` | string | Yes | A name, or username#0000 |

### `get_feedback`

**Get feedback.** Review status, the reviewer's note, unresolved comments (with quoted context), widget state and a diff of human edits since your last version. A decision's `picked` is the chosen option's title, or the reviewer's own answer when `pickedOther` is true (they chose "Other" and wrote it; follow it over your options). *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |

### `get_skill`

**Get the planpage skill.** The planpage SKILL.md for Claude Code, Codex and other agents, with its version and install path. Pass client so the path matches where your client reads skills. Use it to install or update the local skill when the user asks to set up planpage. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `client` | `claude-code` · `codex` · `other` | No | Which agent is installing it. codex installs to ~/.agents/skills; claude-code (the default) to ~/.claude/skills |

### `hand_off`

**Hand off to another agent.** Pass work on a document to another agent, e.g. Codex to Claude Code. It shows as a comment thread addressed to that agent; the other agent takes it with wait_for_handoff and answers in the thread (read replies with get_feedback). Only agents acting for the same person receive it. It can't wake an agent that isn't running: it waits until that agent calls wait_for_handoff, calls any planpage tool, or reaches a Stop hook set up for handoffs.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `to` | string | No | The receiving agent's client, e.g. codex or claude-code. Any running agent of that kind can take it. |
| `to_session_id` | string | No | A specific session to hand to, if you know its session_id |
| `body` | string | Yes | What you need the other agent to do, with enough context |
| `block_id` | string | No | Anchor it to a block, e.g. a step id |

### `invite_to_workspace`

**Invite people to a workspace.** Invite people by username (name#0042) to a workspace this connection reaches, at a role. Each gets an inbox item (and email) to accept; only they can. Needs the connection to be allowed to invite people, and you to be an owner or admin there. Only do this when the user asks.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `organization_id` | string | Yes |  |
| `people` | list of string | Yes | Usernames like name#0042 |
| `role` | `admin` · `reviewer` · `member` · `viewer` | Yes |  |

### `link_ref`

**Link commit or PR.** Attach a commit, PR, branch or URL to the plan or one of its steps.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `url` | string | Yes |  |
| `step` | string | No |  |
| `title` | string | No |  |

### `link_repository`

**Link a repository to a project.** Remember which project this folder's plans go to: saves the git remote on the project so resolve_project finds it next time. Use after the user picks a project for a repository that isn't linked yet.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `project_id` | string | Yes |  |
| `remote_url` | string | Yes | Output of `git remote get-url origin` |
| `replace` | boolean | No | Only after the user confirms: replace a different repository already linked to the project |

### `list_briefs`

**List briefs.** Work humans have queued for agents. Pick one up with pick_up_brief. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `project_id` | string | No |  |

### `list_documents`

**List documents.** Documents you can reach, newest first. Filter by project, kind or status. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `project_id` | string | No |  |
| `kind` | `plan` · `report` · `review` · `adr` · `brief` | No |  |
| `status` | `draft` · `review` · `changes_requested` · `approved` · `in_progress` · `done` · `abandoned` | No |  |
| `limit` | integer | No |  |

### `list_handoffs`

**List handoffs.** Handoffs other agents have addressed to you and nobody has taken yet, oldest first. Take one with wait_for_handoff (it returns at once when one is waiting). *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `project_id` | string | No |  |
| `document_id` | string | No |  |
| `as` | string | No | Which agent you are (e.g. codex, claude-code). Defaults to this session's client. |

### `list_images`

**List images.** Images in a workspace, newest first, with their public URLs and markdown, plus how much of the workspace's storage is used. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `project_id` | string | No | Store in this project's workspace |
| `organization_id` | string | No | Or this workspace (from whoami). Omit both for your personal workspace. |
| `before` | string | No | created_at of the last image you saw, for the next page |
| `limit` | integer | No |  |

### `list_projects`

**List projects.** Projects this connection can reach, with your role in each. *Read only.*

No parameters.

### `list_repositories`

**List GitHub repositories.** GitHub repositories the planpage GitHub App is installed on, per workspace, most recently pushed first, each with the project already linked to it if any. Use it to suggest a repository (and its name) when creating a project, for example in a folder without a git remote. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `organization_id` | string | No | From whoami's workspaces. Omit for every workspace. |
| `query` | string | No | Only repositories whose owner/name contains this text |

### `list_steps`

**List steps.** A plan's steps with status, claims and linked commits/PRs. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |

### `pick_up_brief`

**Pick up brief.** Turn a brief into a plan (linked to it) and mark the brief taken.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `brief_id` | string | Yes |  |
| `markdown` | string | Yes |  |
| `title` | string | No |  |
| `submit_for_review` | boolean | Yes |  |

### `publish`

**Publish document.** Create a document, or replace an existing one's content when document_id is given. Saves a new version. Set submit_for_review to ask for review in the same call. Mermaid diagrams (```mermaid fences) are checked first: if one doesn't parse, nothing is saved and the error says which diagram and why.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `project_id` | string | No | Required when creating |
| `document_id` | string | No | Replace this document's content instead of creating one |
| `kind` | `plan` · `report` · `review` · `adr` · `brief` | Yes |  |
| `title` | string | No | Defaults to the first # heading |
| `markdown` | string | Yes |  |
| `summary` | string | No | What changed in this version |
| `parent_id` | string | No | e.g. the plan a report or review belongs to |
| `base_revision` | integer | No | Fail if the document changed since this revision |
| `submit_for_review` | boolean | Yes |  |

### `read_document`

**Read document.** Read a document as markdown (block ids are kept on ::: blocks). Pass version to read an older version. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |
| `version` | integer | No |  |

### `read_document_blocks`

**Read document blocks.** List the top-level blocks with their ids, types and text, for targeted edit_blocks calls. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |

### `release_step`

**Release step.** Give up your claim on a step.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `step` | string | Yes |  |

### `render_diagram`

**Render diagram.** Draw a mermaid diagram as PNG images (light and dark) with permanent public URLs, without putting it in a document. Use it to show a diagram in a GitHub issue, pull request or comment: paste `github_markdown`, which switches with the reader's theme, or `markdown` for the light version. A diagram that doesn't parse comes back with mermaid's error.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `source` | string | Yes | Mermaid source, without the ``` fence |

### `reply_comment`

**Reply to comment.** Reply in a comment thread (e.g. explain how you addressed it).

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `thread_id` | string | Yes |  |
| `body` | string | Yes |  |

### `resolve_comment`

**Resolve comment.** Mark a comment thread resolved once addressed.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `thread_id` | string | Yes |  |
| `reopen` | boolean | Yes |  |

### `resolve_project`

**Find project by git remote.** Match your repository's git remote URL (any of https/ssh/.git forms) to a planpage project. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `remote_url` | string | Yes | Output of `git remote get-url origin` |

### `restore_document`

**Restore document from Trash.** Bring a document back from Trash, as it was. The same rules as trash_document apply: only documents this connection published and that were never approved.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |

### `search`

**Search documents.** Full-text search over plans, reports, reviews and ADRs. Search before planning to reuse earlier decisions. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `query` | string | Yes |  |
| `project_id` | string | No |  |
| `kind` | `plan` · `report` · `review` · `adr` · `brief` | No |  |

### `set_project_icon`

**Set project icon.** Show an image as a project's icon in the planpage sidebar. Upload it with upload_image (project_id puts it in the right workspace), then pass its id; pass null to remove the icon. Needs a Publish and run connection.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `project_id` | string | Yes |  |
| `image_id` | string or null | Yes |  |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |

### `set_workspace_icon`

**Set workspace icon.** Show an image as a workspace's icon in the planpage rail, instead of its coloured letter. Upload the picture with upload_image to the same workspace first (square works best), then pass its id; pass null to go back to the letter. Needs owner or admin in that workspace and a Publish and run connection.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `image_id` | string or null | Yes |  |
| `organization_id` | string | No | From whoami. Omit for your personal workspace. |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |

### `share_document`

**Share a document with people.** Share one document with people by username (name#0042): view, comment or edit. People in the workspace get it on top of their role; anyone else sees only this document (a paid plan feature). Each gets an inbox item and email. Needs the connection to be allowed to share, and write access to the document. Only do this when the user asks.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `people` | list of string | Yes | Usernames like name#0042 |
| `role` | `viewer` · `commenter` · `editor` | Yes |  |

### `start_session`

**Start session.** Register this run so your work is attributed to it in the activity log. Call once at the start; pass the returned session_id to later calls.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `label` | string | No | Short description of the task |
| `model` | string | No |  |
| `client` | string | No | e.g. Claude Code, Cursor |
| `repo` | string | No |  |
| `branch` | string | No |  |

### `submit_for_review`

**Submit for review.** Save a version and ask the humans to review it. Pass reviewers (usernames like name#0042, or emails, of people who can review it) to ask specific people; otherwise everyone who can review is asked.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `summary` | string | No |  |
| `reviewers` | list of string | No | Usernames (name#0042) or emails of the people who should review |

### `trash_document`

**Move document to Trash.** Move a document to Trash: it disappears for everyone (lists, search, links, agents) and is deleted for good after 30 days unless restored. Only for documents this connection published that were never approved, in a workspace where the person you act for can delete documents (their personal workspace, or as owner or admin). Only do this when the user asks, or to clean up a throwaway document you published. Undo with restore_document.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |

### `update_step`

**Update step.** Set a step's status (pending, doing, done, blocked) with an optional note. Requires an approved plan.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `document_id` | string | Yes |  |
| `step` | string | Yes |  |
| `status` | `pending` · `doing` · `done` · `blocked` | Yes |  |
| `note` | string | No |  |

### `upload_image`

**Upload image.** Upload a PNG, JPEG, GIF or WebP (max 10 MB; no SVG) and get a permanent public URL plus ready-to-paste markdown. The URL works anywhere markdown images do: planpage documents, GitHub issues, PRs and comments, READMEs. Anyone with the URL can view it, so don't upload secrets. Small files (up to 2 MB): pass data_base64. Bigger files, or when you have a file path and a shell: omit data_base64 to get a single-use upload_url and a curl command that sends the file (valid 15 minutes); its response is the same image object.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `filename` | string | Yes | e.g. screenshot.png; used for the download name |
| `data_base64` | string | No | The file, base64-encoded |
| `alt` | string | No | Describe the image for people who can't see it |
| `project_id` | string | No | Store in this project's workspace |
| `organization_id` | string | No | Or this workspace (from whoami). Omit both for your personal workspace. |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |

### `wait_for_handoff`

**Wait for a handoff.** Take the oldest handoff addressed to you, waiting up to timeout_seconds for one to arrive. Returns at once when one is already waiting; it's then yours and no other agent gets it. Do the work, then answer with reply_comment on its handoff_id and resolve_comment when it's done. Keep timeout_seconds under your client's tool-call timeout (Codex's default is 60 seconds). After two empty waits, stop and tell the user; the handoff stays queued.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `session_id` | string | No | The session_id from start_session. Omit to use this connection's current session. |
| `project_id` | string | No |  |
| `document_id` | string | No |  |
| `as` | string | No | Which agent you are (e.g. codex, claude-code). Defaults to this session's client. |
| `timeout_seconds` | integer | Yes |  |

### `wait_for_review`

**Wait for review.** Block until the document is reviewed, commented on or edited, or until timeout_seconds pass. Returns get_feedback's result and whether anything changed. Keep timeout_seconds under your client's tool-call timeout (Codex's default is 60 seconds). Prefer stopping and resuming later for long reviews. *Read only.*

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | Yes |  |
| `timeout_seconds` | integer | Yes |  |

### `whoami`

**Who am I.** Show this connection, its access level, and the workspaces it can reach (with the organization_id create_project needs), even ones with no projects yet. *Read only.*

No parameters.


## Prompts

The server also offers two prompts, "Plan a task in planpage" and "Address review feedback", described in [The planpage skill](https://planpage.dev/docs/the-planpage-skill.md#prompts).
