# MCP Usage — From the Field

A hands-on field guide to the **iKanban MCP surface — 96 tools** — written from a real run where every tool below was driven against a live server. It covers what each category is for, the **exact parameters** (including the ones whose names will trip you up), and the gotchas that `400` you.

The authoritative, always-current tool list lives inside the app: **Settings → MCP Servers → MCP Capabilities** (served live from the server). This page is the _field_ companion — not an exhaustive index, but how the common tools actually behave.

---

## What the MCP server is (and isn't)

iKanban exposes a [Model Context Protocol](https://modelcontextprotocol.io) server for supported agent operations. Some agent workflows also use selected REST routes; a `vk_` key is restricted by a route deny-list, and many browser-management routes require a browser session. See [Setup and Access](/docs/getting-started/setup) before wiring REST calls.

- **Read + create + update only.** There is **no delete** over MCP — by design. Anything you create **persists**; remove it in the web UI.
- **You address things by human identifiers.** Team `ENG`, issue key `ENG-42`. You only need raw UUIDs for projects, sprints, releases, documents, and folders (get them from the matching `list_*` tool).

---

## 1. Connect

```bash
claude mcp add --scope user --transport http ikanban-remote \
  https://mcp.i-kanban.com/sse \
  --header "Authorization: Bearer vk_your_key_here"
```

Generate a key at **Settings → API Keys** (`vk_…`). Verify with `claude mcp get ikanban-remote` → expect `✓ Connected`.

> **Gotcha — transport must be `http`, not `sse`.** The URL path is `/sse` for history, but the transport is **Streamable HTTP**. Register it as `sse` and it **fails silently** — `✗ Failed to connect`, no tools appear.

---

## 2. The tool map

The server exposes **96 tools**. The commonly used ones are grouped below. For the complete, always-current list, open **Settings → MCP Servers** in the app — that is the authoritative catalogue; this table is a curated field subset.

| Category                  | Tools                                                                                                                                                                                                                              |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 👥 Teams & Issues         | `list_teams` `list_issues` `get_issue_by_key` `update_issue_by_key` `update_team`                                                                                                                                                  |
| 📋 Tasks & Projects       | `list_projects` `create_project` `get_project` `update_project` `list_features` `create_task` `update_task` `list_repos`                                                                                                           |
| ⚙️ Task Workflow          | `list_my_issues` `list_assignees` `assign_task` `move_task` `get_task_details`                                                                                                                                                     |
| 🏃 Sprints                | `list_sprints` `get_sprint` `create_sprint` `update_sprint` `get_sprint_tasks` `assign_task_to_sprint` `bulk_assign_tasks_to_sprint`                                                                                               |
| 🚀 Releases               | `create_release` `list_releases` `get_release`                                                                                                                                                                                     |
| 📄 Documents              | `list_documents` `get_document` `create_document` `update_document`                                                                                                                                                                |
| 📎 File Uploads           | `get_document_upload_url` `register_uploaded_document`                                                                                                                                                                             |
| 📁 Folders                | `list_folders` `get_folder` `create_folder` `update_folder`                                                                                                                                                                        |
| 💬 Comments               | `list_comments` `add_comment`                                                                                                                                                                                                      |
| 📊 Visibility & Analytics | `list_workspaces` `list_team_members` `get_team_dashboard` `get_team_graph` `get_team_chord` `list_inbox` `mark_inbox_read` `snooze_inbox` `get_pulse` `get_pulse_summary` `list_saved_views` `list_automations` `list_agent_runs` |
| 🏷️ Tags                   | `list_tags` `create_tag` `update_tag`                                                                                                                                                                                              |
| 🔧 Context                | `get_context`                                                                                                                                                                                                                      |

---

## 3. Read this first — the param surprises that cost you a round-trip

The tool _names_ are intuitive; several _parameters_ are not. These are the exact ones that `400`'d during the field run:

| Tool               | You'd reasonably pass…     | It actually wants…                                                            |
| ------------------ | -------------------------- | ----------------------------------------------------------------------------- |
| `get_issue_by_key` | a UUID                     | an **issue key** — `ENG-42` (a UUID errors: _"Use format like 'IKA-123'"_)    |
| `list_repos`       | a workspace                | **`project_id`**                                                              |
| `list_assignees`   | `team`                     | **`project_id`**                                                              |
| `list_saved_views` | `team`                     | **`project_id`**                                                              |
| `list_automations` | `team`                     | **`project_id`**                                                              |
| `create_document`  | `title`                    | **`name`**                                                                    |
| `add_comment`      | `body`                     | **`content`**                                                                 |
| `create_tag`       | just `name`                | **`tag_name` + `content`** — tags are name→text _expansions_, not bare labels |
| `create_task`      | `title`                    | + **`priority`, `estimate`, `task_type`, `feature_id`** (all required)        |
| `create_release`   | any release id will attach | only a **project-scoped** release attaches (see Releases)                     |
| `get_context`      | works over the network     | **stdio/session only** — it errors over the remote server                     |

Keep this table open the first time and the 400s never happen.

---

## 4. The mental model

```
Workspace  ──>  Team  ──>  Project  ──>  Issue
                 │           ▲
                 │           └── a Project must be ATTACHED to a Team to hold its issues
                 ├── Sprint   (time-boxed cycle — issues are ASSIGNED to it)
                 └── Release  (ship target — issues are FILED under it; project-scoped)
```

- **Workspace** — billing + member seats; plan caps enforced here.
- **Team** (`ENG`) — owns issues, projects, sprints, releases, members; has a system **AI Agent** member.
- **Project** — created at the _workspace_ level, then **attached** to a team.
- **Issue** (`ENG-42`) — the unit of work.
- **Sprint / Release** — overlays; issues are attached to them after creation (or, for a release, at creation via `release_id`).

---

## 5. The golden path — create → organize → verify

The end-to-end loop, all through MCP (team `ENG`, placeholder UUIDs — get real ones from `list_*`):

```jsonc
// 1. project  (create at workspace level, then ATTACH to the team in the UI)
create_project { "workspace_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name": "Backend" }
//    ⚠ a fresh project is NOT attached to a team → create_task 400s
//      "project does not belong to this team". Attach: Team → Projects → add.

// 2. issue  (priority + estimate + task_type REQUIRED; assignee omitted ⇒ team's AI Agent)
create_task { "feature_id": "<from list_features>", "team": "ENG", "project_id": "12345678-1234-1234-1234-123456789012",
              "title": "Wire up rate limiting", "priority": 2, "estimate": 3, "task_type": "feature" }

// 3. sprint  (dates are full ISO-8601 WITH timezone)
create_sprint { "team": "ENG", "name": "Sprint 30",
                "start_date": "2026-07-07T00:00:00Z", "end_date": "2026-07-21T00:00:00Z" }

// 4. assign issues to the sprint  (you CANNOT set a sprint on create_task)
bulk_assign_tasks_to_sprint { "team": "ENG", "sprint_id": "…", "task_ids": ["ENG-42","ENG-43"] }

// 5. project-scoped release, then file the issue under it
create_release { "team": "ENG", "name": "v1.4", "project_id": "12345678-…" }   // ← project_id!
create_task    { …, "release_id": "deadbeef-dead-beef-dead-beefdeadbeef" }

// 6. verify
get_sprint_tasks { "team": "ENG", "sprint_id": "…" }
```

> **Release gotcha.** `create_release` **without** `project_id` makes a _team-wide_ release (`project_id` NULL). Passing that release's id to `create_task` **silently nulls** — an issue only attaches to a release matching its own project. Always pass `project_id` when you intend to file issues under it. (Omit `release_id` entirely and the project's _active_ release is auto-assigned.)

---

## 6. Category reference — every tool

### 👥 Teams & Issues

| Tool                  | Required params        | Notes                                                |
| --------------------- | ---------------------- | ---------------------------------------------------- |
| `list_teams`          | —                      | your entry point: returns identifiers (`ENG`, `BLA`) |
| `list_issues`         | `team`                 | filterable by status/assignee                        |
| `get_issue_by_key`    | `issue_key` (`ENG-42`) | **not a UUID**                                       |
| `update_issue_by_key` | `issue_key` + fields   |                                                      |
| `update_team`         | `team`                 | name / identifier / icon / color                     |

### 📋 Tasks & Projects

| Tool             | Required params                                                                  | Notes                                                                                                          |
| ---------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `list_projects`  | —                                                                                | all projects the key can see                                                                                   |
| `create_project` | `workspace_id`, `name`                                                           | **workspace-level** — attach to a team before issues                                                           |
| `get_project`    | `project_id`                                                                     |                                                                                                                |
| `update_project` | `project_id`                                                                     | name / status / priority / lead / icon                                                                         |
| `create_task`    | `team`, `project_id`, `title`, `priority`, `estimate`, `task_type`, `feature_id` | the analytics gate. `feature_id` comes from `list_features` — **not** the same thing as `task_type: "feature"` |
| `update_task`    | `task_id`                                                                        | title / status / assignee / priority / …                                                                       |
| `list_repos`     | **`project_id`**                                                                 | linked Git repos                                                                                               |

### ⚙️ Task Workflow

| Tool               | Required params          | Notes                                    |
| ------------------ | ------------------------ | ---------------------------------------- |
| `list_my_issues`   | —                        | across all teams                         |
| `list_assignees`   | **`project_id`**         | who can be assigned                      |
| `assign_task`      | `task_id`, `assignee_id` | assignee is a **team member id**         |
| `move_task`        | `task_id`, `project_id`  | move to another project                  |
| `get_task_details` | `task_id`                | one-shot: task + comments + links + tags |

### 🏃 Sprints

| Tool                          | Required params                          | Notes                                            |
| ----------------------------- | ---------------------------------------- | ------------------------------------------------ |
| `list_sprints` / `get_sprint` | `team` (+ `sprint_id`)                   | `sprint_id` accepts a UUID or slug (`sprint-12`) |
| `create_sprint`               | `team`, `name`, `start_date`, `end_date` | dates: full ISO-8601 **with tz**                 |
| `update_sprint`               | `team`, `sprint_id`                      | fields / status                                  |
| `get_sprint_tasks`            | `team`, `sprint_id`                      | your verify step                                 |
| `assign_task_to_sprint`       | `team`, `sprint_id`, `task_id`           | id or issue key                                  |
| `bulk_assign_tasks_to_sprint` | `team`, `sprint_id`, `task_ids[]`        | (unlink via `update_task` `sprint:"none"`)       |

### 🚀 Releases

| Tool             | Required params                                          | Notes                                               |
| ---------------- | -------------------------------------------------------- | --------------------------------------------------- |
| `create_release` | `team`, `name` (+ **`project_id`** to be issue-linkable) | without `project_id` → team-wide, can't hold issues |
| `list_releases`  | `team`                                                   |                                                     |
| `get_release`    | `team`, `release_id`                                     |                                                     |

### 📄 Documents & 📎 File Uploads

| Tool                         | Required params                  | Notes                                           |
| ---------------------------- | -------------------------------- | ----------------------------------------------- |
| `list_documents`             | `team`                           |                                                 |
| `get_document`               | `document_id`                    |                                                 |
| `create_document`            | `team`, **`name`** (not `title`) | optional `content` (markdown), `folder_id`      |
| `update_document`            | `document_id`                    | title / content                                 |
| `get_document_upload_url`    | `workspace_id` (+ file info)     | **step 1** — returns a presigned S3 URL         |
| `register_uploaded_document` | upload ref                       | **step 2** — after your client `PUT`s the bytes |

> **Uploads are a 3-move dance:** `get_document_upload_url` → _your client PUTs the file to S3_ → `register_uploaded_document`. The MCP server never touches the bytes.

### 📁 Folders

| Tool            | Required params | Notes                            |
| --------------- | --------------- | -------------------------------- |
| `list_folders`  | `team`          |                                  |
| `get_folder`    | `folder_id`     |                                  |
| `create_folder` | `team`, `name`  | optional `parent_id` for nesting |
| `update_folder` | `folder_id`     | rename / move                    |

### 💬 Comments

| Tool            | Required params                       | Notes             |
| --------------- | ------------------------------------- | ----------------- |
| `list_comments` | `task_id`                             | UUID or issue key |
| `add_comment`   | `task_id`, **`content`** (not `body`) |                   |

### 📊 Visibility & Analytics

| Tool                                                       | Required params              | Notes                                    |
| ---------------------------------------------------------- | ---------------------------- | ---------------------------------------- |
| `list_workspaces`                                          | —                            | UUIDs + plan; needed for uploads/invites |
| `list_team_members`                                        | `team`                       | includes the AI Agent member             |
| `get_team_dashboard` / `get_team_graph` / `get_team_chord` | `team`                       | KPIs + collaboration graph/chord data    |
| `list_inbox` / `mark_inbox_read` / `snooze_inbox`          | — / item id / item id + time | your notifications                       |
| `get_pulse` / `get_pulse_summary`                          | —                            | recent-activity feed + rollup            |
| `list_saved_views`                                         | **`project_id`**             | saved filter views                       |
| `list_automations`                                         | **`project_id`**             | automation rules                         |
| `list_agent_runs`                                          | `team`                       | @claude/@copilot/@gemini run lifecycle   |

### 🏷️ Tags

| Tool         | Required params                   | Notes                                             |
| ------------ | --------------------------------- | ------------------------------------------------- |
| `list_tags`  | `team`                            |                                                   |
| `create_tag` | `team`, `tag_name`, **`content`** | tags are name→**expansion** text, not bare labels |
| `update_tag` | tag id                            | name / color / content                            |

### 🔧 Context

| Tool          | Required params | Notes                                                                                        |
| ------------- | --------------- | -------------------------------------------------------------------------------------------- |
| `get_context` | —               | **only works over stdio inside an active workspace session** — errors over the remote server |

---

## 7. Value cheat-sheet

| Field                                    | Allowed values                                              |
| ---------------------------------------- | ----------------------------------------------------------- |
| `priority`                               | `1` Urgent · `2` High · `3` Medium · `4` Low                |
| `estimate`                               | integer story points (e.g. `1`–`8`)                         |
| `task_type`                              | `feature` · `bug` · `chore`                                 |
| `status` (issue)                         | `todo` · `in-progress` · `in-review` · `done` · `cancelled` |
| `workspace_role` API field               | `owner` · `admin` · `member` · `viewer`                     |
| team role API field (`team_assignments`) | `viewer` · `contributor` · `maintainer` · `owner`           |

These are API values. The current workspace invite UI offers Admin/Member; team UI offers Contributor/Maintainer/Viewer/Owner. Workspace Owner/Admin representation is described in [Members and Roles](/docs/teams-projects/members-roles). Do not infer a one-to-one UI permission mapping from an API token.
| any date | full ISO-8601 **with timezone** — `2026-07-07T00:00:00Z` |

---

## 8. Troubleshooting — symptom → cause → fix

| You see…                                                          | Cause                                                                              | Fix                                                                                                                                                                                       |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `✗ Failed to connect`, no tools                                   | registered with `--transport sse`                                                  | re-add with `--transport http`                                                                                                                                                            |
| `400 "estimate/priority/task_type is required"`                   | analytics gate on `create_task`                                                    | pass all three                                                                                                                                                                            |
| `400 "feature is required — every task must belong to a Feature"` | no `feature_id` on `create_task`                                                   | call `list_features { "team": "ENG" }`, pick the closest `id`, pass it as `feature_id`. Without it the task lands in the **Unclassified** queue, which is why it is now rejected outright |
| `400 "project does not belong to this team"`                      | project not attached to the team                                                   | Team → Projects → add it                                                                                                                                                                  |
| `400 "Use format like 'IKA-123'"`                                 | passed a UUID to `get_issue_by_key`                                                | pass the **issue key**                                                                                                                                                                    |
| `missing field 'project_id'`                                      | used `team` on `list_repos`/`list_assignees`/`list_saved_views`/`list_automations` | pass `project_id`                                                                                                                                                                         |
| `missing field 'name'/'content'/'tag_name'`                       | `create_document`/`add_comment`/`create_tag` param naming                          | use `name` / `content` / `tag_name`+`content`                                                                                                                                             |
| created issue has `release_id: null` after you passed one         | team-wide release                                                                  | create a **project-scoped** release (`project_id`) and pass _its_ id                                                                                                                      |
| `get_context` errors                                              | remote server can't serve it                                                       | it's stdio/session-only — use `list_*` tools instead                                                                                                                                      |
| `402 "Plan limit reached…"`                                       | a create operation hit a plan cap; the response identifies the limited resource    | check **Settings → Billing** and [Plan Limits](/docs/billing/plan-limits). Current public paid plans do not cap projects.                                                                 |
| need to delete a test entity                                      | MCP has **no delete**                                                              | remove it in the web UI                                                                                                                                                                   |

That's the field guide — **96 tools live**, the common ones exercised above (full list in Settings → MCP Servers). Keep §3 and §7 handy and the tools do exactly what you'd expect.
