Appearance
Issue Tools
Ten tools covering the full issue lifecycle on the board: create, create in bulk, update, delete, search, list-mine, prepare project/issue context, pick up an issue end-to-end, and return the daily Today snapshot.
create-issue
Create a new issue in a project.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | integer | Yes | The project to create the issue in |
title | string | Yes | Issue title (max 255 characters) |
description | string | Yes | Issue description (max 65,535 characters) |
lane_id | integer | No | Lane to place the issue in. Defaults to the first lane if omitted. |
priority | integer | No | 0 Highest, 1 High, 2 Medium (default), 3 Low, 4 Lowest |
type | integer | No | 0 Feature (default), 1 Bug, 2 Task |
assignee_id | integer | No | User ID to assign. Use project members to find IDs. |
sprint_id | integer | No | Sprint to add the issue to |
epic_id | integer | No | Epic to link the issue to. Bidirectional with update-epic's issue_ids. |
label_ids | array | No | Label IDs to attach (must belong to the same project, at most 500). Omit or pass [] for none. |
blocked_by_ids | array | No | Issue IDs that block this issue (must be in the same project, at most 500) |
blocks_ids | array | No | Issue IDs that this issue blocks (must be in the same project, at most 500) |
estimated_minutes | integer | No | Estimated time in minutes (minimum 0) |
Behavior
- If
lane_idis omitted, the issue is placed in the project's first lane automatically - The lane, sprint, and assignee are all validated to belong to the specified project
- Blocking relations must reference issues within the same project
- In the description, a plain
@Full Name(or unique first name) of a project member becomes a real mention and notifies that member. Ambiguous or unknown names stay literal text, and names inside code blocks are never matched - Returns the created issue with its generated key (e.g.,
KD-0042), ID, lane, assignee, sprint, blocking relations, andcreated_at/updated_at(ISO 8601)
Example Prompt
Create a high-priority bug in the kendo project: "Login form rejects valid email addresses". The form strips everything after a
+in the address. Assign it to Jasper.
bulk-create-issues
Create up to 25 issues in one call. Use this instead of calling create-issue repeatedly when importing or generating a backlog — 250 issues becomes 10 calls rather than 250.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | integer | Yes | The project to create the issues in |
lane_id | integer | No | Lane for every issue in the batch. Defaults to the project's first lane. One lane applies to the whole batch. |
rows | array | Yes | 1–25 issues to create. Each row: title (required, max 255), description (required, max 65,535), priority (optional), type (optional) |
Behavior
- Every issue lands in the backlog. No
sprint_idis accepted, so created issues appear on the Backlog tab, not the board. Assign them afterwards with assign-issues-to-sprint, or link them to an epic with update-epic. - One lane for the batch. Per-row lanes aren't supported; move individual issues afterwards if they need different columns.
- A malformed row rejects the entire call. Because every row field is validated up front, one row missing a
title— or carrying an out-of-rangepriority— means nothing is created. Fix the row and resend the whole batch; there is no risk of duplicates. - A row that fails during creation does not stop the others. Infrastructure faults (a database error, a lock timeout) are reported per row in
failedwhile its siblings still commit. Theerrortext is fixed guidance, not a diagnosis — the underlying cause is recorded server-side rather than returned, so retry a failed row once and report it if it fails again. - Batch-created issues are indistinguishable from individually created ones — same key format, ranks, watchers, audit entries and lane placement — because this tool reuses the same creation path as
create-issue. @Full Namementions in a description work exactly as they do oncreate-issue, and notify that member per issue.- Only these fields are supported per row. Assignee, sprint, epic, labels, blocking relations, estimates and attachments are deliberately out of scope — set them afterwards with update-issue or the bulk-assign tools.
Response Fields
| Field | Type | Description |
|---|---|---|
created_count | integer | How many issues were created |
failed_count | integer | How many rows failed |
complete | boolean | true when every row was created |
keys | array | Display keys of the created issues (e.g. KD-0142), in the order the rows were submitted |
failed | array | Rows that failed. Each entry has index — the 0-based position in the rows array you sent — and error, a fixed guidance string. Resend only those rows, once; the others exist. |
The response is deliberately thin: no descriptions are echoed back and no URLs are included, because mirroring create-issue's full payload across 25 rows would cost more tokens than the batching saves.
Rate Limits
A tenant may create up to 250 rows per minute (100 on the free plan). The batch is refused before anything is created, and the error names both the limit and when it resets. This is separate from the endpoint's own request limit — it exists because one bulk request carries 25× the writes of a single create.
Example Prompt
Take the twelve features from our roadmap doc and create them as issues in the kendo project backlog, with the two auth ones as Highest priority.
update-issue
Update an existing issue. Only provided fields are changed — omitted fields keep their current values.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
issue_id | integer | One of | The numeric ID of the issue (provide issue_id or issue_key, not both) |
issue_key | string | One of | The issue key, e.g. "KD-0042" (provide issue_id or issue_key, not both) |
title | string | No | New title (max 255 characters) |
description | string | No | New description (max 65,535 characters) |
lane_id | integer | No | Target lane ID to move the issue to (must be in the same project) |
priority | integer | No | 0 Highest, 1 High, 2 Medium, 3 Low, 4 Lowest |
type | integer | No | 0 Feature, 1 Bug, 2 Task |
assignee_id | integer | No | User ID to assign, or null to unassign |
sprint_id | integer | No | Sprint ID, or null to remove from sprint. For multiple issues at once, prefer assign-issues-to-sprint — one batched call instead of looping. |
epic_id | integer | No | Epic ID, or null to unlink from epic. Bidirectional with update-epic's issue_ids. An issue that leaves an epic loses its links to that epic's Done when wishes. |
blocked_by_ids | array | No | Replaces all "blocked by" relations (must be in the same project, at most 500). Omit to preserve, [] to clear. |
blocks_ids | array | No | Replaces all "blocks" relations (must be in the same project, at most 500). Omit to preserve, [] to clear. |
estimated_minutes | integer | No | Estimated time in minutes, or null to clear |
Behavior
- Partial updates: only fields you include are modified, like the API's
PATCH. The API'sPUTrequires all fields. - Lane changes: pass
lane_idto move an issue to a different lane on the board. The lane must belong to the same project. - Blocking relations: omitting
blocked_by_ids/blocks_idspreserves existing relations. Pass an empty array[]to explicitly clear them. - Mentions: in the description, a plain
@Full Name(or unique first name) of a project member becomes a real mention and notifies that member. Ambiguous or unknown names stay literal text. - Pass
nullforassignee_id,sprint_id, orestimated_minutesto clear those values. title,description,lane_id,priorityandtypecannot be cleared:nullon any of them is rejected. Omit a field to keep its value.- Response includes
created_atandupdated_at(ISO 8601)
Example Prompt
Bump KD-42 to highest priority and assign it to Sarah
delete-issue
Permanently delete an issue and all its comments.
Destructive
This action cannot be undone. The issue and all associated comments are permanently removed.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
issue_id | integer | One of | The numeric ID of the issue (provide issue_id or issue_key, not both) |
issue_key | string | One of | The issue key, e.g. "KD-0042" (provide issue_id or issue_key, not both) |
Example Prompt
Delete the duplicate issue KD-38, it's the same as KD-42
search-issues
Search, filter or count issues within a project by text query and/or filters. This tool is read-only and safe to call repeatedly.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | integer | Yes | The project to search in |
query | string | No | Text search across title, description, and issue key (max 200 characters) |
lane_ids | integer[] | No | Issues in any of these lanes. All IDs must belong to the project |
assignee_ids | integer[] | No | Issues assigned to any of these users. 0 means unassigned, so [0, 12] is unassigned or user 12 |
sprint_ids | integer[] | No | Issues in any of these sprints. 0 means no sprint (backlog). Other IDs must belong to the project |
epic_ids | integer[] | No | Issues in any of these epics. 0 means no epic. Other IDs must belong to the project |
priorities | integer[] | No | Issues with any of these priorities (0–4) |
types | integer[] | No | Issues of any of these types (0 Feature, 1 Bug, 2 Task) |
label_ids | array | No | Filter by label IDs — returns issues carrying ANY of these labels (OR). All IDs must belong to the project. |
exclude_lane_ids | integer[] | No | Leave out issues in these lanes |
exclude_assignee_ids | integer[] | No | Leave out issues assigned to these users. Unassigned issues stay unless 0 is in the list |
exclude_sprint_ids | integer[] | No | Leave out issues in these sprints. Backlog issues stay unless 0 is in the list |
exclude_epic_ids | integer[] | No | Leave out issues in these epics. Issues without an epic stay unless 0 is in the list, so [0] returns only issues that have an epic |
exclude_label_ids | integer[] | No | Leave out issues carrying any of these labels |
exclude_priorities | integer[] | No | Leave out issues with these priorities |
exclude_types | integer[] | No | Leave out issues of these types |
lane_id, assignee_id, sprint_id, epic_id, priority, type | integer | No | One value for the same filter; the tool adds it to the matching list, so assignee_id, sprint_id or epic_id of 0 means none, as 0 does in the list. lane_id must be at least 1 |
group_by | string | No | lane, assignee, sprint, epic, priority, type or label. Returns counts per value instead of issues |
include_description | boolean | No | Default true. Pass false to leave description out of each issue |
limit | integer | No | Max results (1–100, default 25) |
Behavior
- Results are ordered by most recently updated
- All filters are optional and combine with AND logic
- The values inside one list combine with OR. When a value is in an include list and in the exclude list for the same field, the exclusion wins
- A lane, sprint, epic or label ID that does not belong to the project returns an error. Assignee IDs are not checked: a user with no issues in the project matches nothing
- Returns matching issues with key, title, lane, assignee, sprint, epic, labels, priority, and type
- Each result names its lane, assignee, sprint and epic next to their IDs (
lane+lane_id,epic+epic_id, …), so the name answers the user and the ID feeds the next call - Each result carries
labelsas{id, name}objects, pluslabel_ids - Each result carries
priorityandtypeas numbers, pluspriority_name(Highest…Lowest) andtype_name(Feature,Bug,Task) - Each result includes
attachments_count— the number of files attached to the issue - Each result includes
created_atandupdated_at(ISO 8601) - Marked as
#[IsReadOnly]and#[IsIdempotent]— safe to call multiple times with no side effects
Response Fields
Alongside the issues array, the response surfaces truncation metadata so the caller knows when the result set was capped:
| Field | Type | Description |
|---|---|---|
count | integer | Number of issues returned, never above limit. It is not the number of matches: read truncated, or pass group_by for the uncapped total |
truncated | boolean | true when more issues matched than were returned; refine filters to see more matches |
limit | integer | Server-side cap applied to this request |
issues | object[] | Matching issues. description is left out when include_description is false |
Counting with group_by
With group_by, the tool answers a question such as "open issues per lane, without Tasks" in one call, and no issue rows are returned. limit and include_description are ignored. The response carries project, project_id and:
| Field | Type | Description |
|---|---|---|
group_by | string | The field the counts are grouped on |
total | integer | Number of issues that match the filters (not capped) |
groups | object[] | {key, label, count} per value, highest count first. key is the lane, user, sprint, epic or label ID, or the priority / type number. key 0 is the group without a value for assignee, sprint, epic and label |
With group_by: "label" an issue with several labels is counted in each of its label groups, so the group counts can add up to more than total.
Example Prompt
Show me all high-priority bugs assigned to Jasper in the kendo project
get-my-issues
Get issues assigned to you — your current work, tasks, and tickets. Excludes issues in the "done" lane (last lane per project).
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | integer | No | Filter to a specific project (omit for all accessible projects) |
priority | integer | No | Filter by priority (0–4) |
type | integer | No | Filter by type (0 Feature, 1 Bug, 2 Task) |
query | string | No | Text search across issue title and key (max 200 characters) |
Behavior
- Returns only issues assigned to the authenticated user
- Excludes issues in the last lane (done) of each project
- Results ordered by most recently updated
- Each result includes
created_atandupdated_at(ISO 8601) - Each result names its lane, project, sprint and epic next to their IDs (
lane+lane_id,project+project_id, …), so the name answers the user and the ID feeds the next call - Each result carries
labelsas{id, name}objects, pluslabel_ids - Each result carries
priorityandtypeas numbers, pluspriority_name(Highest…Lowest) andtype_name(Feature,Bug,Task) - Respects project accessibility — non-admin users only see issues in projects they can access
- Marked as
#[IsReadOnly]and#[IsIdempotent]
Response Fields
Alongside the issues array, the response surfaces truncation metadata so the caller knows when the result set was capped at the server-side cap (currently 500):
| Field | Type | Description |
|---|---|---|
count | integer | Number of issues actually returned |
truncated | boolean | true when the result set was capped at limit; refine filters to see more matches |
limit | integer | Server-side cap applied to this request |
issues | object[] | List of assigned issues |
Example Prompts
What am I working on right now?
Show me my high-priority bugs across all projects
What tickets do I have in the kendo project?
prepare-project-context
Bundle the project's structural meta into one read: the project itself, all its lanes (board columns), all Planned and Active sprints (with active_sprint as a shortcut to the currently Active one), the project's labels, the project members (for assignee lookup), and the calling user. Use this as the gather step for any project-scoped flow — triage, board sync, branch creation, picking up an issue. Replaces separate reads of kendo://projects/{id}, kendo://projects/{id}/lanes, kendo://projects/{id}/sprints, and kendo://projects/{id}/members. For Completed sprints, use get-sprints with status=2.
Pair with prepare-issue-context
When you also need a specific issue's payload (comments, branch links, attachments), fire prepare-project-context and prepare-issue-context in parallel — same wall-clock as one round-trip. See Workflows → Prepare an issue.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | integer | yes | The numeric ID of the project |
Behavior
- Marked as
#[IsReadOnly]and#[IsIdempotent]— safe to call repeatedly with no side effects sprintscontains only Planned (0) and Active (1) sprints, ordered by start date. Completed sprints are excluded — useget-sprintswithstatus=2for thoseactive_sprintis a shortcut to the Active sprint fromsprints, ornullwhen none is Activemembersreturns every user who reaches the project via team membership or direct membership, ordered by first name then last namemembers_countcompanion field lets you shortcut without iteratingcurrent_useris the authenticated MCP user — use this instead of guessing fromgit config user.emailwhen deciding the assignee for a "start working on this" flow- The full issue list is not included; for a single issue's payload (comments, branches, attachments), call
prepare-issue-context— typically in parallel
Response Fields
| Field | Type | Description |
|---|---|---|
project | object | Project payload — the same fields as kendo://projects/{id}, including its archived state |
lanes | object[] | Project lanes ordered by position (id, title, color, order, issues_count) |
sprints | object[] | Planned and Active sprints ordered by start date (id, title, status, status_name, start, end, issues_count). Completed sprints excluded. |
active_sprint | object | null | Shortcut to the currently Active sprint from sprints (id, title, status, status_name, start, end, issues_count), or null |
labels | object[] | Project labels ordered by position (id, name, color, order) — use label.id as label_ids in search-issues or sync-issue-labels |
members | object[] | Project members ordered by first_name, then last_name (id, name, email) — use member.id as assignee_id |
members_count | integer | Total number of members returned |
current_user | object | The authenticated MCP user (id, name, email) |
Example Prompt
Pull together the project context for kendo: lanes, sprints, labels, members, and tell me who I am.
prepare-issue-context
Bundle a single issue's full payload into one read: the issue (with comments, branch links, time spent, attachments) and its linked epic. For project meta (lanes, active sprint, members, calling user), call prepare-project-context — typically in parallel with this tool.
Pair with start-work-on-issue
Call prepare-issue-context and prepare-project-context in parallel to gather, then start-work-on-issue to act (assign, move lane, link branch) in one idempotent write. See Workflows → Prepare an issue.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
issue_id | integer | One of | The numeric ID of the issue (provide issue_id or issue_key, not both) |
issue_key | string | One of | The issue key, e.g. "KD-0042" (provide issue_id or issue_key, not both) |
Behavior
- Marked as
#[IsReadOnly]and#[IsIdempotent]— safe to call repeatedly with no side effects epicisnullwhen the issue has no linked epic- Project meta (lanes, active sprint, members, current user) is not included by design — use
prepare-project-contextfor that, in parallel when you need both
Response Fields
| Field | Type | Description |
|---|---|---|
issue | object | Full issue payload — same shape as kendo://issues/{key} (id, key, title, description, priority, type, project, lane, assignee, sprint, comments — each with created_at/updated_at, blocked_by_ids, blocks_ids, labels — each {id, name, color}, epic_id, user_id, branch_links — each with created_at/updated_at, estimated_minutes, total_minutes_spent, attachments, created_at, updated_at) |
epic | object | null | Epic linked to the issue (id, title, goal, description, status, status_name, color, color_name, start, end, checks — its What done looks like checks in order, each {id, text}, wishes — its Done when wishes in order, each {id, text, issues, checked_at, checked_by_id} with issues as {id, key}, created_at, updated_at), or null |
Example Prompt
I want to start working on KD-42. Fire prepare-issue-context and prepare-project-context in parallel and tell me what I'm picking up.
start-work-on-issue
Pick up an issue in one idempotent call — assign it, move it to the target lane (e.g. "In Progress"), optionally add it to a sprint, and link a git branch. Re-running with the same values is a no-op. The GitHub repository is auto-resolved from the project's primary repo.
Pair with the prepare-context tools
Call prepare-issue-context and prepare-project-context in parallel to gather the issue payload and project meta, then start-work-on-issue to act — assign, move lane, link branch — in one write. See Workflows → Prepare an issue.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
issue_id | integer | One of | The numeric ID of the issue (provide issue_id or issue_key, not both) |
issue_key | string | One of | The issue key, e.g. "KD-0042" (provide issue_id or issue_key, not both) |
branch_name | string | Yes | The git branch name to link to the issue |
assignee_id | integer | No | User ID to assign the issue to |
lane_id | integer | No | Target lane ID to move the issue to (must be in the same project) |
sprint_id | integer | No | Sprint ID. Omit to preserve existing; pass null to remove from sprint; pass an ID to set. |
repo_id | integer | Conditional | Target GitHub repo ID. Omit on single-repo projects. On multi-repo projects, omit on the first attempt; if you get a candidate-listing error, retry with one of the listed repo IDs (look up IDs via the kendo://projects/{id}/github-repos resource) or ask the human to pick. |
Behavior
- Idempotent — re-running with the same
branch_name,assignee_id,lane_id, andsprint_idproduces no further state change - The branch is linked against the project's only GitHub repo when there is exactly one — no
repo_idneeded - On multi-repo projects without
repo_id, the tool returns a candidate-listing error rather than guessing — retry with the rightrepo_id - Returns the updated issue (with lane, assignee, sprint,
created_at/updated_at) and the branch-link record (existing on replay, otherwise newly created; carriesstatusas the int,status_namebeside it, andcreated_at/updated_at)
Example Prompt
Start work on KD-0042: assign it to me, move it to "In Progress", add it to the active sprint, and link branch
KD-0042-fix-login-form.
kendo-today
Returns the user's active sprints, open issues grouped per project, and today's logged minutes as a single atomic snapshot. Prefer this over get-my-issues for daily-overview questions like "what's on my plate today".
Parameters
No parameters — operates on the authenticated user.
Response Fields
| Field | Type | Description |
|---|---|---|
activeSprints | object[] | Active sprints across accessible projects — each with id, title, projectId, projectName, myOpenIssuesCount, created_at, updated_at, projectAvatar |
myIssues | object[] | User's open issues (excluding final-lane) — each with id, key, title, type (feature | bug | task), projectId, projectName, created_at, updated_at, projectAvatar |
todayMinutes | integer | Total minutes logged by the user today across accessible projects |
projectAvatar is the row's project avatar as absolute avif and webp URLs, the same object as the REST API's project avatar, or null when the project has none.
Example Prompt
What's on my plate today?
See Also
- Resources — Read issue data via
kendo://issues/{id}andkendo://projects/{id}/issues - Issues & Board Guide — Understanding the board, lanes, and blocking relationships
- Issues API — REST endpoints for issue management