# MCP tools reference

> All @paca-ai/paca-mcp tool names by category, input schemas, agent-mode constraints, and dynamically loaded plugin tools.

- Repository: Paca-AI/paca
- GitHub: https://github.com/Paca-AI/paca
- Human docs: https://grok-wiki.com/public/docs/paca-ai-paca-f238b2ab3d25
- Complete Markdown: https://grok-wiki.com/public/docs/paca-ai-paca-f238b2ab3d25/llms-full.txt

## Source Files

- `apps/mcp/ALL_TOOLS.md`
- `apps/mcp/src/tools/index.ts`
- `apps/mcp/src/tools/task-tools.ts`
- `apps/mcp/src/tools/project-tools.ts`
- `apps/mcp/src/api/client.ts`
- `apps/mcp/src/permissions.ts`

---

---
title: "MCP tools reference"
description: "All @paca-ai/paca-mcp tool names by category, input schemas, agent-mode constraints, and dynamically loaded plugin tools."
---

The `@paca-ai/paca-mcp` package (`apps/mcp`) exposes **62 core MCP tools** over stdio, backed by the Paca REST API at `/api/v1`. At startup the server fetches agent or user permissions, filters core tools, loads enabled plugin modules from `GET /api/v1/plugins`, and merges plugin tool definitions into a single flat `tools/list` response. Tool calls route to the plugin registry first, then to core handlers in `apps/mcp/src/tools/index.ts`.

## Runtime configuration

| Variable | Required | Default | Effect |
|---|---|---|---|
| `PACA_API_KEY` | Yes | — | Sent as `X-API-Key` on every API request |
| `PACA_API_URL` | No | `http://localhost:8080` | API base URL |
| `PACA_GATEWAY_URL` | No | `PACA_API_URL` | Resolves relative plugin `remoteEntryUrl` paths (nginx gateway in Docker) |
| `PACA_AGENT_ID` | No | — | Agent UUID; sent as `X-Agent-ID`; requires `PACA_PROJECT_ID` |
| `PACA_PROJECT_ID` | When `PACA_AGENT_ID` set | — | Locks tool calls to one project; drives permission fetch |

<ParamField body="PACA_API_KEY" type="string" required>
API key for authentication. In agent mode, use the server-configured global `AGENT_API_KEY`.
</ParamField>

<ParamField body="PACA_AGENT_ID" type="string">
Agent UUID to impersonate. Startup fails if set without `PACA_PROJECT_ID`.
</ParamField>

<ParamField body="PACA_PROJECT_ID" type="string">
Project UUID for single-project mode. When set with agent mode, every tool argument `projectId` must match this value or the call returns an error.
</ParamField>

## Operating modes

| Mode | Env vars | Permission source | Core tool visibility |
|---|---|---|---|
| Personal (legacy) | `PACA_API_KEY` only | None — all core tools listed | Full catalog |
| User single-project | `PACA_API_KEY` + `PACA_PROJECT_ID` | `GET /api/v1/projects/{id}/members/me/permissions` + optional global perms | Filtered to project permissions |
| User global | `PACA_API_KEY` (no project) | `GET /api/v1/users/me/global-permissions` | Global tools only; project-scoped tools hidden |
| Agent single-project | `PACA_API_KEY` + `PACA_AGENT_ID` + `PACA_PROJECT_ID` | Agent permissions in the bound project | Filtered; `projectId` enforced |

<Warning>
In agent mode, if a tool call passes `projectId` that differs from `PACA_PROJECT_ID`, the server returns `Error: projectId must be {id} in single-project agent mode` with `isError: true` — before any API request is made.
</Warning>

<Info>
Plugin tools are **not** filtered at the MCP list-tools layer. Authorization for plugin routes is enforced by the API at `/api/v1/plugins/{pluginId}/…`.
</Info>

## Tool call flow

```mermaid
sequenceDiagram
    participant Client as MCP client
    participant Server as paca-mcp server
    participant Plugins as PluginRegistry
    participant Core as Core handlers
    participant API as Paca API

    Client->>Server: tools/call { name, arguments }
    alt projectId mismatch in agent mode
        Server-->>Client: isError text response
    else plugin owns tool name
        Server->>Plugins: handleToolCall
        Plugins->>API: /api/v1/plugins/{pluginId}/…
        API-->>Plugins: result
        Plugins-->>Client: text content
    else core tool
        Server->>Core: handleToolCall
        Core->>API: /api/v1/…
        API-->>Core: SuccessEnvelope data
        Core-->>Client: formatted text content
    end
```

## Shared input conventions

<ParamField body="projectId" type="string" required>
Technical project UUID. Use `list_projects` to resolve IDs. **Do not** pass the project display name.
</ParamField>

- **Markdown ↔ BlockNote**: `description` on tasks, `content` on docs and comments is accepted as Markdown on write and returned as Markdown on read.
- **Pagination**: `list_tasks` supports `cursor` (opaque, from `next_cursor`) and `pageSize` (1–200, default 20).
- **Dates**: ISO 8601 strings (`startDate`, `endDate`, `dueDate`).
- **Path-based docs**: Filesystem doc tools use `/`-separated paths (e.g. `Architecture/API Design`); folder segments are created automatically on write.

## Response format

All tools return MCP `content` arrays with `type: "text"`. Successful operations return human-readable formatted text (lists, detail blocks, success messages). Failures return:

```json
{
  "content": [{ "type": "text", "text": "Error: …" }],
  "isError": true
}
```

Zod validation errors and API `4xx`/`5xx` responses surface through the same envelope.

## Permission keys

Core tools map to permission keys in `apps/mcp/src/permissions.ts`. Wildcards (`*`, `tasks.*`) are supported at global and project scope.

| Permission key | Grants |
|---|---|
| `projects.read` | `list_projects`, `get_project` |
| `projects.create` | `create_project` |
| `projects.write` | `update_project` |
| `projects.delete` | `delete_project` |
| `tasks.read` | Task, type, status, view, custom field, attachment, and activity **read** tools |
| `tasks.write` | Task, type, status, view, custom field, attachment, and activity **write** tools |
| `sprints.read` | `list_sprints`, `get_sprint` |
| `sprints.write` | `create_sprint`, `update_sprint`, `delete_sprint`, `complete_sprint` |
| `docs.read` | `list_docs`, `read_doc` |
| `docs.write` | `write_doc`, `delete_doc`, `move_doc` |
| `project.members.read` | `list_project_members`, `get_my_project_permissions` |
| `project.members.write` | `add_project_member`, `update_project_member_role`, `remove_project_member` |
| `project.roles.read` | `list_project_roles` |
| `project.roles.write` | `create_project_role`, `update_project_role`, `delete_project_role` |

<Tip>
Call `get_my_project_permissions` to inspect the effective permission set for the authenticated user or agent in a project.
</Tip>

## Core tools by category

### Projects (5)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_projects` | List accessible projects | — | — |
| `get_project` | Get one project | `projectId` | — |
| `create_project` | Create project | `name` | `description` |
| `update_project` | Update project | `projectId` | `name`, `description` |
| `delete_project` | Delete project | `projectId` | — |

### Tasks (6)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_tasks` | List tasks (cursor pagination) | `projectId` | `cursor`, `pageSize` |
| `get_task` | Full task detail (subtasks, attachments, activities) | `projectId`, `taskId` | — |
| `get_task_by_number` | Task detail by number | `projectId`, `taskNumber` | — |
| `create_task` | Create task | `projectId`, `title` | `description`, `statusId`, `typeId`, `sprintId`, `assigneeId`, `parentTaskId`, `importance`, `storyPoints`, `tags`, `startDate`, `dueDate` |
| `update_task` | Update task | `projectId`, `taskId` | Same as create; `parentTaskId` nullable to clear |
| `delete_task` | Delete task | `projectId`, `taskId` | — |

### Sprints (6)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_sprints` | List sprints | `projectId` | — |
| `get_sprint` | Get sprint | `projectId`, `sprintId` | — |
| `create_sprint` | Create sprint | `projectId`, `name`, `startDate`, `endDate` | — |
| `update_sprint` | Update sprint | `projectId`, `sprintId` | `name`, `startDate`, `endDate` |
| `delete_sprint` | Delete sprint | `projectId`, `sprintId` | — |
| `complete_sprint` | Mark sprint completed | `projectId`, `sprintId` | — |

### Documentation — filesystem model (5)

Path-oriented tools over folders and documents. Prefer these over local files for project documentation.

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_docs` | Tree listing of folders and docs | `projectId` | `path` (folder root) |
| `read_doc` | Read doc as Markdown | `projectId`, `path` | — |
| `write_doc` | Create or update doc at path | `projectId`, `path`, `content` | — |
| `delete_doc` | Delete doc or folder (recursive) | `projectId`, `path` | — |
| `move_doc` | Move or rename doc/folder | `projectId`, `sourcePath`, `destPath` | — |

### Project members (5)

| Tool | Description | Required inputs |
|---|---|---|
| `list_project_members` | List members | `projectId` |
| `add_project_member` | Add member | `projectId`, `userId`, `roleId` |
| `get_my_project_permissions` | Current user/agent permissions | `projectId` |
| `update_project_member_role` | Change member role | `projectId`, `userId`, `roleId` |
| `remove_project_member` | Remove member | `projectId`, `userId` |

### Project roles (4)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_project_roles` | List roles | `projectId` | — |
| `create_project_role` | Create role | `projectId`, `name`, `permissions` | `description` |
| `update_project_role` | Update role | `projectId`, `roleId` | `name`, `description`, `permissions` |
| `delete_project_role` | Delete role | `projectId`, `roleId` | — |

### Task types (5)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_task_types` | List types | `projectId` | — |
| `create_task_type` | Create type | `projectId`, `name` | `icon`, `color`, `description` |
| `update_task_type` | Update type | `projectId`, `typeId` | `name`, `icon`, `color`, `description` |
| `delete_task_type` | Delete type | `projectId`, `typeId` | — |
| `set_default_task_type` | Set project default | `projectId`, `typeId` | — |

### Task statuses (5)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_task_statuses` | List statuses | `projectId` | — |
| `create_task_status` | Create status | `projectId`, `name`, `category` | `color` |
| `update_task_status` | Update status | `projectId`, `statusId` | `name`, `color`, `category`, `position` |
| `delete_task_status` | Delete status | `projectId`, `statusId` | — |
| `set_default_task_status` | Set project default | `projectId`, `statusId` | — |

`category` values: `backlog`, `refinement`, `ready`, `todo`, `inprogress`, `done`.

### Views and task positioning (9)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_views` | List views | `projectId` | `context` (`sprint` \| `backlog` \| `timeline`), `sprintId` |
| `create_view` | Create view | `projectId`, `name`, `context`, `viewType` | `sprintId` |
| `reorder_views` | Reorder views | `projectId`, `viewIds` | — |
| `get_view` | Get view | `projectId`, `viewId` | — |
| `update_view` | Update view | `projectId`, `viewId` | `name`, `context`, `viewType`, `sprintId` |
| `delete_view` | Delete view | `projectId`, `viewId` | — |
| `list_task_positions` | Positions in a view | `projectId`, `viewId` | — |
| `bulk_move_tasks` | Move task in view | `projectId`, `viewId`, `taskId`, `targetViewId` | `targetStatusId`, `targetPosition` |
| `move_task` | Move task in view | `projectId`, `viewId`, `taskId`, `targetViewId` | `targetStatusId`, `targetPosition` |

`viewType` values: `table`, `board`, `roadmap`.

### Custom fields (5)

| Tool | Description | Required inputs | Optional inputs |
|---|---|---|---|
| `list_custom_fields` | List field definitions | `projectId` | — |
| `create_custom_field` | Create field | `projectId`, `fieldKey`, `displayName`, `fieldType` | `options`, `isRequired` |
| `get_custom_field` | Get field | `projectId`, `fieldId` | — |
| `update_custom_field` | Update field | `projectId`, `fieldId` | `displayName`, `fieldType`, `options`, `isRequired` |
| `delete_custom_field` | Delete field | `projectId`, `fieldId` | — |

`fieldType` values: `text`, `number`, `date`, `select`, `multi_select`, `boolean`, `url`.

### Attachments (3)

| Tool | Description | Required inputs |
|---|---|---|
| `list_task_attachments` | List task attachments | `projectId`, `taskId` |
| `get_attachment_download_url` | Presigned download URL | `projectId`, `taskId`, `attachmentId` |
| `delete_task_attachment` | Delete attachment | `projectId`, `taskId`, `attachmentId` |

<Note>
There is no MCP upload tool. File uploads use the REST two-step initiate → complete flow documented on the REST API reference page.
</Note>

### Task activities and comments (4)

| Tool | Description | Required inputs |
|---|---|---|
| `list_task_activities` | Activity feed for a task | `projectId`, `taskId` |
| `add_task_comment` | Add comment | `projectId`, `taskId`, `content` |
| `update_task_comment` | Update comment | `projectId`, `taskId`, `commentId`, `content` |
| `delete_task_comment` | Delete comment | `projectId`, `taskId`, `commentId` |

## Example tool calls

<RequestExample>

```json
{
  "name": "create_task",
  "arguments": {
    "projectId": "550e8400-e29b-41d4-a716-446655440000",
    "title": "Implement MCP filtering",
    "description": "## Scope\n\nFilter tools by agent permissions at startup.",
    "typeId": "660e8400-e29b-41d4-a716-446655440001"
  }
}
```

</RequestExample>

<ResponseExample>

```text
Task created successfully:

Task #42: Implement MCP filtering
ID: 770e8400-e29b-41d4-a716-446655440002
Status: Backlog
...
```

</ResponseExample>

<RequestExample>

```json
{
  "name": "list_tasks",
  "arguments": {
    "projectId": "550e8400-e29b-41d4-a716-446655440000",
    "pageSize": 10,
    "cursor": "eyJjcmVhdGVkX2F0Ijoi..."
  }
}
```

</ResponseExample>

## Plugin-contributed tools

Enabled plugins with `manifest.mcp.remoteEntryUrl` in `plugin.json` load at server startup via dynamic ESM `import()`. Their tools appear in the same `tools/list` response as core tools.

### Loading behavior

1. `GET /api/v1/plugins` with `PACA_API_KEY`
2. Skip `enabled: false` and plugins without `mcp.remoteEntryUrl`
3. Import each entry module; validate default export shape (`tools: Tool[]`, `handleToolCall: function`)
4. Register tool name → plugin ID mapping; skip duplicate names with a warning
5. Failed plugins log to stderr; core tools still start

### Plugin entry contract

```ts
interface PluginMCPEntry {
  tools: Tool[];
  handleToolCall(
    name: string,
    args: Record<string, unknown>,
    context: { pluginId: string; baseURL: string; apiKey: string }
  ): Promise<{ content: Array<{ type: string }>; isError?: boolean }>;
}
```

Build plugin MCP modules with `@paca-ai/plugin-sdk-mcp` (`PluginAPIClient`, `textResult`, `errorResult`). Plugin handlers call scoped routes under `/api/v1/plugins/{pluginId}/…`.

### Naming rules

| Rule | Detail |
|---|---|
| Uniqueness | Tool names must be unique across all loaded plugins |
| Pattern | `[a-z][a-z0-9_]*` |
| Prefix | Use a plugin-specific prefix (e.g. `checklist_list_items`, `bdd_list_scenarios`) |

### URL resolution

| `remoteEntryUrl` form | Resolution |
|---|---|
| Absolute `https://…` | Imported directly |
| Relative `/plugins-mcp/{id}/mcp.js` | Resolved against `PACA_GATEWAY_URL` or `PACA_API_URL` |
| `http://localhost:…` | Allowed for local development only |

<Warning>
Plugin MCP modules run in the same Node.js process as the MCP server without sandboxing. Only install plugins from trusted sources.
</Warning>

### Discovering plugin tools

Plugin tool names are not fixed in core — they depend on installed marketplace plugins. After connecting the MCP server, call `tools/list` (or use your client's tool picker) to see the merged catalog. Installed plugin manifests and `remoteEntryUrl` values are visible via the admin UI or `GET /api/v1/plugins`.

## Tool inventory summary

| Category | Count |
|---|---|
| Projects | 5 |
| Tasks | 6 |
| Sprints | 6 |
| Documentation (filesystem) | 5 |
| Project members | 5 |
| Project roles | 4 |
| Task types | 5 |
| Task statuses | 5 |
| Views | 9 |
| Custom fields | 5 |
| Attachments | 3 |
| Task activities | 4 |
| **Core total** | **62** |
| Plugin tools | Variable (per installed plugins) |

## Related pages

<CardGroup>
<Card title="Connect MCP server" href="/connect-mcp">
Configure `npx @paca-ai/paca-mcp`, environment variables, and client-specific setup.
</Card>
<Card title="Plugin system" href="/plugin-system">
WASM backend, frontend extensions, MCP plugin tools, and capability permissions.
</Card>
<Card title="Plugin SDK reference" href="/plugin-sdk-reference">
`@paca-ai/plugin-sdk-mcp` types, `PluginAPIClient`, and extension points.
</Card>
<Card title="REST API reference" href="/rest-api">
Underlying `/api/v1` endpoints, auth, and response envelopes.
</Card>
<Card title="Configure AI agents" href="/configure-ai-agents">
Create agents, assign roles, and wire MCP config for project teammates.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
MCP connection errors, permission gaps, and gateway URL misconfiguration.
</Card>
</CardGroup>
