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 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 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
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_*):
// 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 PUTs 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. 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. 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.