| pingA | Smoke-test the MCP transport. Returns the literal string pong. |
| list_boardsA | List boards visible to the authenticated user. Use this to discover
board_id values for the other tools. |
| whoamiA | Fetch the authenticated user's profile. Returns the User you're acting as — id, name, role flags, locale,
timezone. Use this to resolve "me" / "myself" references in user
requests (assign to me → assigned_user_id from this response)
or to show the LLM whose perspective it's operating from. |
| get_userA | Fetch one user by id. Useful after list_board_collaborators finds
a candidate by name — call this to confirm role flags and active state
before assigning. Raises KanbanToolHTTPError(404) for unknown ids. |
| list_board_collaboratorsA | List the users with access to board_id. The Kanban Tool API v3 has no bulk list-users endpoint, so this is the
canonical way to discover user IDs for assigned_user_id on tasks.
Costs one HTTP call (the same as get_board — collaborators come
inline on the detail payload). For richer per-user fields, follow up
with get_user(id). |
| list_custom_field_definitionsA | List the per-board metadata for the 15 custom-field slots. Each task has up to 15 custom_field_N values surfaced as
Task.custom_fields["custom_field_N"]. The slot number alone tells
you nothing about what's IN it on a given board — call this tool once
per board to learn the labels, types, and enabled state, then
interpret task values accordingly. Returns the 15 definitions in slot order (1..15) regardless of which
are enabled. Slots with enabled=False are usually dormant on
that board's UI even if individual tasks happen to carry values. |
| get_boardA | Fetch one board with its columns, swimlanes, and custom-field definitions. Use this when you need column/lane ids for move_task or create_task.
Raises KanbanToolHTTPError(404) if the board id is unknown or hidden. |
| get_taskA | Fetch one task by id. Returns a Task with subtask/comment counts,
total tracked time, and inline subtasks. Subtasks live on Task.subtasks directly — no extra round-trip needed
(use list_subtasks only when you want just the list and not the rest
of the task). Raises KanbanToolHTTPError(404) if the task is unknown or inaccessible. |
| recent_changesA | Fetch a board's changelog (Kanban Tool has no webhooks; poll this instead). since is required. Pass the created_at of the newest entry you've
already seen; on the first poll, use datetime.now(UTC) - timedelta(hours=1)
(or whichever lookback window matches your use case). Entries come
newest-first. Poll sparingly: 30-120s cadence, not per-keystroke.
Raises ValueError if since is None (rather than fetching the
full history) — keeps responses bounded by construction. |
| search_tasksA | Search tasks across boards using Kanban Tool's query DSL. query is forwarded verbatim — do not URL-encode, do not wrap the whole
expression in quotes. Quote individual values only when they contain spaces
(e.g. name:"ship the thing"). Terms combine with spaces and are AND-ed.
Supported operators: @username — assignee, e.g. @alice
name:<text> — title contains
priority:<level> — e.g. priority:high
tags:<tag> — tag match
due_date=<iso-date> — e.g. due_date=2026-05-01
subtasks_count<N> — also >, =
archived:<bool> — include archived
Unknown operators silently return zero results, so don't invent syntax for
things the DSL doesn't cover (comment full-text, fuzzy match) — say so
instead. board_id scopes to one board (omit to search all visible).
limit is clamped to 50; paginate further with page (1-indexed). Returns a SearchResults wrapper: results — the list of matched Task objects on this page.
total_count — total matches across all pages (from the API's
pagination envelope; None if the API omits the envelope).
page — 1-indexed page number of this response.
has_more — True when at least one further page exists. Use
this to decide whether to bump page and call again, instead of
heuristics on len(results) == limit (which is wrong on the
last page).
|
| create_taskA | Create a new task on a board. Only name and board_id are required. lane_id is the target column (matches Task.lane_id on fetched tasks).
assigned_user_id sets the single assignee — Kanban Tool tasks have one
assignee, not a list. (The API silently ignores a legacy assignees: [int]
payload on writes, so this kwarg is the wire field name directly.)
priority accepts the string enum or the raw integer; tags is a
comma-separated string; due_date is an ISO 8601 string forwarded as-is.
Unset kwargs are omitted from the request, never sent as explicit null.
Common 422s (KanbanToolValidationError with parsed field_errors):
name empty/missing → fix by passing a non-empty string;
lane_id belongs to a different board → resolve column ids on the
target board first via get_board(board_id).columns;
assigned_user_id not a board collaborator → check via
list_board_collaborators(board_id). |
| update_taskA | Partially update a task's fields. Only the kwargs you pass are sent;
None means omit, not clear (the API ignores nulls, doesn't wipe). Field set mirrors create_task; same wire conventions for priority,
tags, and date fields. assigned_user_id sets the single assignee —
Kanban Tool tasks have one assignee, not a list. For column/lane/position
changes prefer move_task — it's the intent-revealing surface for that
workflow. Raises ValueError if every field is None (no-op guard). Common 422s (KanbanToolValidationError with parsed field_errors):
lane_id from a different board → use get_board(board_id).columns
on the destination board first; assigned_user_id not a board
collaborator → list_board_collaborators(board_id) to confirm. |
| move_taskA | Move a task between columns, swimlanes, or positions on its board. At least one of column_id / swimlane_id / position must be set,
otherwise raises ValueError before issuing HTTP. column_id matches
the Task.lane_id on fetched tasks. Moves are scoped to the task's
current board — there is no cross-board move surface. Common 422s (KanbanToolValidationError with parsed field_errors):
column_id doesn't belong to the task's board → fetch valid column
ids via get_board(get_task(task_id).board_id).columns and pick from
those; swimlane_id doesn't exist on the task's board → same fix via
.swimlanes on the same Board. |
| archive_taskA | Archive a task. Returns the updated Task (caller can confirm
is_archived=True). Idempotent: re-archiving an already-archived task succeeds. There is no
unarchive_task yet — archiving is currently one-way from this surface. Failure modes: KanbanToolHTTPError(404) when the task id is unknown
(verify via get_task(task_id) first if you're unsure);
KanbanToolPermissionError(403) when the authenticated user lacks
write access to the task's board. |
| set_custom_fieldA | Set or clear one of the 15 custom_field_* slots on a task. slot selects which numbered slot to write (1..15 inclusive — the
Kanban Tool API exposes exactly 15). Pair with
list_custom_field_definitions(board_id) to learn each slot's label
and type on a given board before writing.
value is sent verbatim — strings, numbers, and booleans all work.
Pass value=None to clear the slot: the wire body explicitly sends
null (not omits the key), and a subsequent get_task will see
custom_field_N: null. This differs from update_task semantics
where None means omit; for custom fields None means clear.
Common 422 (KanbanToolValidationError with parsed field_errors):
type mismatch — e.g. writing "hi" into a numeric slot, or a value
not in options for a dropdown-typed slot. Inspect the slot's
type/options via list_custom_field_definitions(board_id)
before writing if the slot purpose is uncertain. |
| add_commentA | Post a comment on a task. Returns the created Comment with id,
content, author, and timestamps. Common 422 (KanbanToolValidationError with parsed field_errors):
content empty or whitespace-only — fix by passing a non-empty
string; the field_errors key matches the parameter name. |
| delete_commentA | Delete a comment (soft-delete). Returns the deleted Comment with
deleted_at populated. Like subtasks, the Kanban Tool API soft-deletes — the comment record is
retained server-side with a deleted_at timestamp and stops appearing
on the parent task's comments. The MCP-visible effect is "the comment is
gone." There is no edit endpoint on the API; if you need to "fix" a
comment, delete it and post a replacement. Failure modes: KanbanToolHTTPError(404) when either id is unknown
or the comment isn't on that task — common cause is reusing a stale
comment_id from a previous list. Re-fetch the task's current
comments before retrying. |
| list_subtasksA | List subtasks on a task — id, name, completion state, position. Subtasks are returned inline on Task.subtasks whenever you fetch a
task; this tool is sugar for callers that only want the list. Costs one
HTTP call (the same as get_task) — the Kanban Tool API has no
dedicated list-subtasks endpoint. |
| add_subtaskA | Add a subtask to a task. Returns the created Subtask. name is the human-readable label. Mirrors the parameter name used
by update_subtask and the wire/model field on Subtask.name.
Common 422 (KanbanToolValidationError with parsed field_errors):
name empty or whitespace-only — fix by passing a non-empty string. |
| update_subtaskA | Partial update of an existing subtask. Returns the updated Subtask. Only kwargs the caller passes are sent — None means omit, not
clear. Use this to mark complete (is_completed=True), rename
(name="..."), or change the assignee (assigned_user_id=42).
The position field is read-only on this endpoint; use
reorder_subtasks to change ordering. Common 422 (KanbanToolValidationError with parsed field_errors):
assigned_user_id not a collaborator on the parent task's board —
use list_board_collaborators(board_id) to confirm before retrying. |
| delete_subtaskA | Delete a subtask (soft-delete). Returns the deleted Subtask with
deleted_at populated. The Kanban Tool API soft-deletes — the subtask record is retained
server-side with a deleted_at timestamp and stops appearing on the
parent task's subtasks array. This operation is not strictly
irreversible from an audit perspective, but the MCP-visible effect is
"the subtask is gone." Failure modes: KanbanToolHTTPError(404) when the subtask id is
unknown OR was already soft-deleted in a previous call (the API
returns 404 in both cases). Re-fetch the parent task's
subtasks list to confirm the current state before retrying. |
| reorder_subtasksA | Reorder subtasks under a task. Returns the subtasks in the new order. ids must be the full set of subtask ids on task_id in the
desired order.
Common 422s (KanbanToolValidationError with parsed field_errors):
ids is a partial set (missing some of the task's current subtask
ids) → list current ids via list_subtasks(task_id) and pass them
all in the new order; one or more ids belong to a different task →
same fix, since the API rejects cross-task references. |
| start_timerA | Start a new time tracker on a task for the authenticated user. Returns the created TimeTracker. The new timer starts in the
running state (ended_at is None); call stop_timer when
work pauses or ends. board_id is required by the Kanban Tool API but may be omitted
here — when not supplied the tool resolves it via an internal
get_task(task_id) call (one extra HTTP round-trip). Pass it
explicitly when you already have it (e.g. you just listed tasks for a
board) to avoid the second request. Either way, the resulting wire
body sends both ids.
Note: timers are per-user — starting one creates a record for the
authenticated user only. Use whoami if you need to know whose
timer it is. Common 422: the API rejects starting a timer on a task whose board
you don't have access to with a typed KanbanToolValidationError.
Verify the task is on a board you can list via list_boards. |
| stop_timerA | Stop a running time tracker. Returns the stopped TimeTracker. ended_at is an ISO 8601 timestamp; defaults to the current UTC
time if not provided. Stopping an already-stopped timer is harmless —
the API just updates the ended_at to the new value.
Wire shape: PUT /time_trackers/{id}.json with a flat
{"ended_at": ...} body. Same flat-body convention as the
subtask endpoints — no {"time_tracker": {...}} envelope. Raises KanbanToolHTTPError(404) if the timer id is unknown or
belongs to another user. |
| delete_timerA | Delete a time tracker entirely (e.g. cancel a mistakenly-started
one). Unlike subtasks, timer deletion is hard — the record is gone,
not soft-flagged. Returns None because the API responds with an empty body to
DELETE /time_trackers/{id}.json. The caller should treat the
timer id as invalidated after this call. Failure modes: KanbanToolHTTPError(404) when the timer id is
unknown, was already deleted, or belongs to another user (the API
scopes timer ids to the authenticated user). Use list_my_timers()
to confirm the current set of timer ids you own before retrying. |
| list_my_timersA | List the authenticated user's time trackers across all tasks. Returns one TimeTracker per active or finished timer the current
user owns; the wire data lives on the time_trackers field of the
/users/current.json response (no dedicated list endpoint). Use Task.time_trackers instead when you only want one task's
timers across all users. |