@k-system/tickr-mcp 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/formatters.js +1 -0
  2. package/dist/index.js +48 -0
  3. package/dist/tools/apply-preset.d.ts +4 -0
  4. package/dist/tools/apply-preset.js +26 -0
  5. package/dist/tools/complete-dev-task.js +3 -1
  6. package/dist/tools/create-cycle.d.ts +4 -0
  7. package/dist/tools/create-cycle.js +32 -0
  8. package/dist/tools/create-epic.d.ts +4 -0
  9. package/dist/tools/create-epic.js +36 -0
  10. package/dist/tools/create-implementation-item.d.ts +4 -0
  11. package/dist/tools/create-implementation-item.js +32 -0
  12. package/dist/tools/create-project.d.ts +4 -0
  13. package/dist/tools/create-project.js +33 -0
  14. package/dist/tools/create-status.d.ts +4 -0
  15. package/dist/tools/create-status.js +42 -0
  16. package/dist/tools/delete-attachment.d.ts +4 -0
  17. package/dist/tools/delete-attachment.js +26 -0
  18. package/dist/tools/delete-implementation-item.d.ts +4 -0
  19. package/dist/tools/delete-implementation-item.js +26 -0
  20. package/dist/tools/delete-status.d.ts +4 -0
  21. package/dist/tools/delete-status.js +26 -0
  22. package/dist/tools/delete-ticket.d.ts +4 -0
  23. package/dist/tools/delete-ticket.js +25 -0
  24. package/dist/tools/get-board.d.ts +4 -0
  25. package/dist/tools/get-board.js +37 -0
  26. package/dist/tools/get-my-tasks.d.ts +4 -0
  27. package/dist/tools/get-my-tasks.js +20 -0
  28. package/dist/tools/get-project.d.ts +4 -0
  29. package/dist/tools/get-project.js +20 -0
  30. package/dist/tools/list-attachments.d.ts +4 -0
  31. package/dist/tools/list-attachments.js +37 -0
  32. package/dist/tools/list-comments.d.ts +4 -0
  33. package/dist/tools/list-comments.js +31 -0
  34. package/dist/tools/list-projects.d.ts +4 -0
  35. package/dist/tools/list-projects.js +22 -0
  36. package/dist/tools/list-statuses.d.ts +4 -0
  37. package/dist/tools/list-statuses.js +25 -0
  38. package/dist/tools/list-transitions.d.ts +4 -0
  39. package/dist/tools/list-transitions.js +25 -0
  40. package/dist/tools/update-implementation-item.js +1 -1
  41. package/package.json +2 -2
@@ -5,6 +5,7 @@ export function formatTicketMarkdown(t) {
5
5
  "",
6
6
  `| Field | Value |`,
7
7
  `|-------|-------|`,
8
+ `| Id | ${t.id} |`,
8
9
  `| Type | ${t.type} |`,
9
10
  `| Status | ${t.status} |`,
10
11
  `| Priority | ${t.priority} |`,
package/dist/index.js CHANGED
@@ -26,6 +26,30 @@ import { registerCompleteDevTask } from "./tools/complete-dev-task.js";
26
26
  import { registerWhoami } from "./tools/whoami.js";
27
27
  import { registerAddRelation } from "./tools/add-relation.js";
28
28
  import { registerRemoveRelation } from "./tools/remove-relation.js";
29
+ // Phase 2 — Skupina A: Workflow & Status Management
30
+ import { registerListStatuses } from "./tools/list-statuses.js";
31
+ import { registerListTransitions } from "./tools/list-transitions.js";
32
+ import { registerCreateStatus } from "./tools/create-status.js";
33
+ import { registerDeleteStatus } from "./tools/delete-status.js";
34
+ import { registerApplyPreset } from "./tools/apply-preset.js";
35
+ // Phase 2 — Skupina B: Project Management
36
+ import { registerListProjects } from "./tools/list-projects.js";
37
+ import { registerGetProject } from "./tools/get-project.js";
38
+ import { registerCreateProject } from "./tools/create-project.js";
39
+ // Phase 2 — Skupina C: Ticket Operations
40
+ import { registerDeleteTicket } from "./tools/delete-ticket.js";
41
+ import { registerGetBoard } from "./tools/get-board.js";
42
+ import { registerGetMyTasks } from "./tools/get-my-tasks.js";
43
+ import { registerListComments } from "./tools/list-comments.js";
44
+ // Phase 2 — Skupina D: Attachments
45
+ import { registerListAttachments } from "./tools/list-attachments.js";
46
+ import { registerDeleteAttachment } from "./tools/delete-attachment.js";
47
+ // Phase 2 — Skupina E: Cycles & Epics CRUD
48
+ import { registerCreateCycle } from "./tools/create-cycle.js";
49
+ import { registerCreateEpic } from "./tools/create-epic.js";
50
+ // Phase 2 — Skupina F: Implementation Items
51
+ import { registerCreateImplementationItem } from "./tools/create-implementation-item.js";
52
+ import { registerDeleteImplementationItem } from "./tools/delete-implementation-item.js";
29
53
  // Resources
30
54
  import { registerTicketResource } from "./resources/ticket-resource.js";
31
55
  import { registerProjectResource } from "./resources/project-resource.js";
@@ -59,6 +83,30 @@ async function main() {
59
83
  registerWhoami(server, api);
60
84
  registerAddRelation(server, api);
61
85
  registerRemoveRelation(server, api);
86
+ // Phase 2 — Skupina A: Workflow & Status Management
87
+ registerListStatuses(server, api);
88
+ registerListTransitions(server, api);
89
+ registerCreateStatus(server, api);
90
+ registerDeleteStatus(server, api);
91
+ registerApplyPreset(server, api);
92
+ // Phase 2 — Skupina B: Project Management
93
+ registerListProjects(server, api);
94
+ registerGetProject(server, api);
95
+ registerCreateProject(server, api);
96
+ // Phase 2 — Skupina C: Ticket Operations
97
+ registerDeleteTicket(server, api);
98
+ registerGetBoard(server, api);
99
+ registerGetMyTasks(server, api);
100
+ registerListComments(server, api);
101
+ // Phase 2 — Skupina D: Attachments
102
+ registerListAttachments(server, api);
103
+ registerDeleteAttachment(server, api);
104
+ // Phase 2 — Skupina E: Cycles & Epics CRUD
105
+ registerCreateCycle(server, api);
106
+ registerCreateEpic(server, api);
107
+ // Phase 2 — Skupina F: Implementation Items
108
+ registerCreateImplementationItem(server, api);
109
+ registerDeleteImplementationItem(server, api);
62
110
  // Registrace resources
63
111
  registerTicketResource(server, api);
64
112
  registerProjectResource(server, api);
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerApplyPreset(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=apply-preset.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerApplyPreset(server, api) {
3
+ server.tool("apply_preset", "Apply a workflow preset to a project (replaces current statuses and transitions)", {
4
+ project: z.string().describe("Project slug"),
5
+ preset_id: z.string().describe("Preset ID to apply"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.post(`/api/projects/${params.project}/apply-preset`, { presetId: params.preset_id });
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Preset "${params.preset_id}" applied to project ${params.project}`,
14
+ },
15
+ ],
16
+ };
17
+ }
18
+ catch (err) {
19
+ return {
20
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
21
+ isError: true,
22
+ };
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=apply-preset.js.map
@@ -5,12 +5,14 @@ export function registerCompleteDevTask(server, api) {
5
5
  summary: z.string().describe("Summary of what was done"),
6
6
  branch: z.string().optional().describe("Git branch name"),
7
7
  commit_hash: z.string().optional().describe("Last commit SHA"),
8
+ files_changed: z.array(z.string()).optional().describe("List of changed file paths"),
8
9
  }, async (params) => {
9
10
  try {
10
11
  await api.post(`/api/dev-queue/complete/${params.assignment_id}`, {
11
- resultSummary: params.summary,
12
+ resultSummary: params.summary.replace(/\\n/g, "\n"),
12
13
  branchName: params.branch ?? null,
13
14
  commitHash: params.commit_hash ?? null,
15
+ filesChanged: params.files_changed ?? null,
14
16
  });
15
17
  return {
16
18
  content: [
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerCreateCycle(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=create-cycle.d.ts.map
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ export function registerCreateCycle(server, api) {
3
+ server.tool("create_cycle", "Create a new cycle (sprint) in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ name: z.string().describe("Cycle name"),
6
+ startDate: z.string().describe("Start date (ISO 8601, e.g. '2026-03-15')"),
7
+ endDate: z.string().describe("End date (ISO 8601, e.g. '2026-03-29')"),
8
+ }, async (params) => {
9
+ try {
10
+ const result = await api.post(`/api/projects/${params.project}/cycles`, {
11
+ name: params.name,
12
+ startDate: params.startDate,
13
+ endDate: params.endDate,
14
+ });
15
+ return {
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: `Created cycle #${result.number}${result.name ? ` "${result.name}"` : ""} (${result.id})`,
20
+ },
21
+ ],
22
+ };
23
+ }
24
+ catch (err) {
25
+ return {
26
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
27
+ isError: true,
28
+ };
29
+ }
30
+ });
31
+ }
32
+ //# sourceMappingURL=create-cycle.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerCreateEpic(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=create-epic.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ export function registerCreateEpic(server, api) {
3
+ server.tool("create_epic", "Create a new epic in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ name: z.string().describe("Epic name"),
6
+ description: z.string().optional().describe("Epic description"),
7
+ color: z.string().optional().describe("Epic color hex code (e.g. #6366f1)"),
8
+ start_date: z.string().optional().describe("Start date (YYYY-MM-DD)"),
9
+ target_date: z.string().optional().describe("Target date (YYYY-MM-DD)"),
10
+ }, async (params) => {
11
+ try {
12
+ const result = await api.post(`/api/projects/${params.project}/epics`, {
13
+ name: params.name,
14
+ description: params.description,
15
+ color: params.color,
16
+ startDate: params.start_date,
17
+ targetDate: params.target_date,
18
+ });
19
+ return {
20
+ content: [
21
+ {
22
+ type: "text",
23
+ text: `Created epic "${result.name}" (${result.id})`,
24
+ },
25
+ ],
26
+ };
27
+ }
28
+ catch (err) {
29
+ return {
30
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
31
+ isError: true,
32
+ };
33
+ }
34
+ });
35
+ }
36
+ //# sourceMappingURL=create-epic.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerCreateImplementationItem(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=create-implementation-item.d.ts.map
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ export function registerCreateImplementationItem(server, api) {
3
+ server.tool("create_implementation_item", "Add a new implementation item to a ticket", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' (legacy) or 'TKR-BUG-0042' (typed)"),
5
+ area: z.string().describe("Area: Database, API, Frontend, MCP, etc."),
6
+ fileOrDetail: z.string().describe("Specific file path or description of the work"),
7
+ note: z.string().optional().describe("Additional note"),
8
+ }, async (params) => {
9
+ try {
10
+ const result = await api.post(`/api/tickets/${params.number}/items`, {
11
+ area: params.area,
12
+ fileOrDetail: params.fileOrDetail,
13
+ note: params.note?.replace(/\\n/g, "\n"),
14
+ });
15
+ return {
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: `Added implementation item "${result.area}: ${result.fileOrDetail}" to ${params.number}`,
20
+ },
21
+ ],
22
+ };
23
+ }
24
+ catch (err) {
25
+ return {
26
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
27
+ isError: true,
28
+ };
29
+ }
30
+ });
31
+ }
32
+ //# sourceMappingURL=create-implementation-item.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerCreateProject(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=create-project.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ export function registerCreateProject(server, api) {
3
+ server.tool("create_project", "Create a new project", {
4
+ name: z.string().describe("Project display name"),
5
+ slug: z.string().describe("URL-safe project slug (unique)"),
6
+ prefix: z.string().describe("Ticket prefix, e.g. 'VLX', 'TKR'"),
7
+ description: z.string().optional().describe("Project description"),
8
+ }, async (params) => {
9
+ try {
10
+ const result = await api.post("/api/projects", {
11
+ name: params.name,
12
+ slug: params.slug,
13
+ prefix: params.prefix,
14
+ description: params.description,
15
+ });
16
+ return {
17
+ content: [
18
+ {
19
+ type: "text",
20
+ text: `Created project "${result.name}" (${result.slug})`,
21
+ },
22
+ ],
23
+ };
24
+ }
25
+ catch (err) {
26
+ return {
27
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
28
+ isError: true,
29
+ };
30
+ }
31
+ });
32
+ }
33
+ //# sourceMappingURL=create-project.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerCreateStatus(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=create-status.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ export function registerCreateStatus(server, api) {
3
+ server.tool("create_status", "Create a new workflow status in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ name: z.string().describe("Status display name"),
6
+ slug: z.string().describe("Status slug (URL-safe identifier)"),
7
+ emoji: z.string().optional().describe("Emoji icon for the status"),
8
+ color: z.string().describe("Hex color code, e.g. '#3b82f6'"),
9
+ category: z.string().describe("Category: backlog, active, done, cancelled"),
10
+ sortOrder: z.number().describe("Sort order (0-based)"),
11
+ isDefault: z.boolean().optional().default(false).describe("Whether this is the default status for new tickets"),
12
+ isTerminal: z.boolean().optional().default(false).describe("Whether this is a terminal (closed) status"),
13
+ }, async (params) => {
14
+ try {
15
+ const result = await api.post(`/api/projects/${params.project}/statuses`, {
16
+ name: params.name,
17
+ slug: params.slug,
18
+ emoji: params.emoji,
19
+ color: params.color,
20
+ category: params.category,
21
+ sortOrder: params.sortOrder,
22
+ isDefault: params.isDefault,
23
+ isTerminal: params.isTerminal,
24
+ });
25
+ return {
26
+ content: [
27
+ {
28
+ type: "text",
29
+ text: `Created status "${result.name}" (${result.id})`,
30
+ },
31
+ ],
32
+ };
33
+ }
34
+ catch (err) {
35
+ return {
36
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
37
+ isError: true,
38
+ };
39
+ }
40
+ });
41
+ }
42
+ //# sourceMappingURL=create-status.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerDeleteAttachment(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-attachment.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteAttachment(server, api) {
3
+ server.tool("delete_attachment", "Delete an attachment from a ticket", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' (legacy) or 'TKR-BUG-0042' (typed)"),
5
+ attachment_id: z.string().describe("Attachment ID to delete"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.delete(`/api/tickets/${params.number}/attachments/${params.attachment_id}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Attachment ${params.attachment_id} deleted from ${params.number}`,
14
+ },
15
+ ],
16
+ };
17
+ }
18
+ catch (err) {
19
+ return {
20
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
21
+ isError: true,
22
+ };
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=delete-attachment.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerDeleteImplementationItem(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-implementation-item.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteImplementationItem(server, api) {
3
+ server.tool("delete_implementation_item", "Delete an implementation item from a ticket", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' (legacy) or 'TKR-BUG-0042' (typed)"),
5
+ item_id: z.string().describe("Implementation item ID to delete"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.delete(`/api/tickets/${params.number}/items/${params.item_id}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Implementation item ${params.item_id} deleted from ${params.number}`,
14
+ },
15
+ ],
16
+ };
17
+ }
18
+ catch (err) {
19
+ return {
20
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
21
+ isError: true,
22
+ };
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=delete-implementation-item.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerDeleteStatus(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-status.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteStatus(server, api) {
3
+ server.tool("delete_status", "Delete a workflow status from a project", {
4
+ project: z.string().describe("Project slug"),
5
+ status_id: z.string().describe("Status ID to delete"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.delete(`/api/projects/${params.project}/statuses/${params.status_id}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Status ${params.status_id} deleted from project ${params.project}`,
14
+ },
15
+ ],
16
+ };
17
+ }
18
+ catch (err) {
19
+ return {
20
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
21
+ isError: true,
22
+ };
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=delete-status.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerDeleteTicket(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-ticket.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteTicket(server, api) {
3
+ server.tool("delete_ticket", "Delete a ticket by display number", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' (legacy) or 'TKR-BUG-0042' (typed)"),
5
+ }, async (params) => {
6
+ try {
7
+ await api.delete(`/api/tickets/${params.number}`);
8
+ return {
9
+ content: [
10
+ {
11
+ type: "text",
12
+ text: `Ticket ${params.number} deleted`,
13
+ },
14
+ ],
15
+ };
16
+ }
17
+ catch (err) {
18
+ return {
19
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
20
+ isError: true,
21
+ };
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=delete-ticket.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerGetBoard(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=get-board.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ export function registerGetBoard(server, api) {
3
+ server.tool("get_board", "Get kanban board view for a project (tickets grouped by status columns)", {
4
+ project: z.string().describe("Project slug"),
5
+ }, async (params) => {
6
+ try {
7
+ const columns = await api.get(`/api/projects/${params.project}/board`);
8
+ const lines = [];
9
+ for (const col of columns) {
10
+ const emoji = col.statusEmoji ? `${col.statusEmoji} ` : "";
11
+ lines.push(`## ${emoji}${col.status} (${col.tickets.length})`);
12
+ lines.push("");
13
+ if (col.tickets.length === 0) {
14
+ lines.push("_No tickets_");
15
+ }
16
+ else {
17
+ lines.push("| Ticket | Title | Priority | Assignee | Scope |");
18
+ lines.push("|--------|-------|----------|----------|-------|");
19
+ for (const t of col.tickets) {
20
+ lines.push(`| ${t.displayNumber} | ${t.title} | ${t.priority} | ${t.assigneeName || "-"} | ${t.scope || "-"} |`);
21
+ }
22
+ }
23
+ lines.push("");
24
+ }
25
+ return {
26
+ content: [{ type: "text", text: lines.join("\n") || "Board is empty." }],
27
+ };
28
+ }
29
+ catch (err) {
30
+ return {
31
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
32
+ isError: true,
33
+ };
34
+ }
35
+ });
36
+ }
37
+ //# sourceMappingURL=get-board.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerGetMyTasks(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=get-my-tasks.d.ts.map
@@ -0,0 +1,20 @@
1
+ export function registerGetMyTasks(server, api) {
2
+ server.tool("get_my_tasks", "Get tickets assigned to the current user across all projects", {}, async () => {
3
+ try {
4
+ const tickets = await api.get("/api/my-tasks");
5
+ const text = tickets
6
+ .map((t) => `${t.displayNumber} [${t.status}] ${t.title} (${t.priority}, ${t.scope || "-"})`)
7
+ .join("\n");
8
+ return {
9
+ content: [{ type: "text", text: text || "No tasks assigned to you." }],
10
+ };
11
+ }
12
+ catch (err) {
13
+ return {
14
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
15
+ isError: true,
16
+ };
17
+ }
18
+ });
19
+ }
20
+ //# sourceMappingURL=get-my-tasks.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerGetProject(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=get-project.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ import { formatProjectMarkdown } from "../formatters.js";
3
+ export function registerGetProject(server, api) {
4
+ server.tool("get_project", "Get project detail by slug", {
5
+ slug: z.string().describe("Project slug, e.g. 'tickr'"),
6
+ }, async (params) => {
7
+ try {
8
+ const project = await api.get(`/api/projects/${params.slug}`);
9
+ const md = formatProjectMarkdown(project);
10
+ return { content: [{ type: "text", text: md }] };
11
+ }
12
+ catch (err) {
13
+ return {
14
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
15
+ isError: true,
16
+ };
17
+ }
18
+ });
19
+ }
20
+ //# sourceMappingURL=get-project.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerListAttachments(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-attachments.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ export function registerListAttachments(server, api) {
3
+ server.tool("list_attachments", "List attachments on a ticket", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' (legacy) or 'TKR-BUG-0042' (typed)"),
5
+ }, async (params) => {
6
+ try {
7
+ const attachments = await api.get(`/api/tickets/${params.number}/attachments`);
8
+ if (attachments.length === 0) {
9
+ return {
10
+ content: [{ type: "text", text: "No attachments on this ticket." }],
11
+ };
12
+ }
13
+ const lines = [
14
+ "| # | File | Type | Size | Uploaded By | Date |",
15
+ "|---|------|------|------|-------------|------|",
16
+ ...attachments.map((a, i) => `| ${i + 1} | ${a.fileName} | ${a.contentType} | ${formatSize(a.size)} | ${a.createdByName || "-"} | ${a.createdAt} |`),
17
+ ];
18
+ return {
19
+ content: [{ type: "text", text: lines.join("\n") }],
20
+ };
21
+ }
22
+ catch (err) {
23
+ return {
24
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
25
+ isError: true,
26
+ };
27
+ }
28
+ });
29
+ }
30
+ function formatSize(bytes) {
31
+ if (bytes < 1024)
32
+ return `${bytes} B`;
33
+ if (bytes < 1024 * 1024)
34
+ return `${(bytes / 1024).toFixed(1)} KB`;
35
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
36
+ }
37
+ //# sourceMappingURL=list-attachments.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerListComments(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-comments.d.ts.map
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+ export function registerListComments(server, api) {
3
+ server.tool("list_comments", "List comments on a ticket", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' (legacy) or 'TKR-BUG-0042' (typed)"),
5
+ }, async (params) => {
6
+ try {
7
+ const comments = await api.get(`/api/tickets/${params.number}/comments`);
8
+ if (comments.length === 0) {
9
+ return {
10
+ content: [{ type: "text", text: "No comments on this ticket." }],
11
+ };
12
+ }
13
+ const lines = [];
14
+ for (const c of comments) {
15
+ lines.push(`**${c.authorName}** (${c.createdAt}):`);
16
+ lines.push(c.text);
17
+ lines.push("");
18
+ }
19
+ return {
20
+ content: [{ type: "text", text: lines.join("\n") }],
21
+ };
22
+ }
23
+ catch (err) {
24
+ return {
25
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
26
+ isError: true,
27
+ };
28
+ }
29
+ });
30
+ }
31
+ //# sourceMappingURL=list-comments.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerListProjects(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-projects.d.ts.map
@@ -0,0 +1,22 @@
1
+ export function registerListProjects(server, api) {
2
+ server.tool("list_projects", "List all projects accessible to the current user", {}, async () => {
3
+ try {
4
+ const projects = await api.get("/api/projects");
5
+ const lines = [
6
+ "| Name | Slug | Prefix | Scope Tags | Ticket Types |",
7
+ "|------|------|--------|------------|--------------|",
8
+ ...projects.map((p) => `| ${p.name} | ${p.slug} | ${p.prefix} | ${p.scopeTags?.join(", ") || "-"} | ${p.ticketTypes?.join(", ") || "-"} |`),
9
+ ];
10
+ return {
11
+ content: [{ type: "text", text: lines.join("\n") || "No projects found." }],
12
+ };
13
+ }
14
+ catch (err) {
15
+ return {
16
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
17
+ isError: true,
18
+ };
19
+ }
20
+ });
21
+ }
22
+ //# sourceMappingURL=list-projects.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerListStatuses(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-statuses.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ export function registerListStatuses(server, api) {
3
+ server.tool("list_statuses", "List workflow statuses for a project", {
4
+ project: z.string().describe("Project slug"),
5
+ }, async (params) => {
6
+ try {
7
+ const statuses = await api.get(`/api/projects/${params.project}/statuses`);
8
+ const lines = [
9
+ "| # | Name | Slug | Emoji | Color | Category | Default | Terminal |",
10
+ "|---|------|------|-------|-------|----------|---------|----------|",
11
+ ...statuses.map((s, i) => `| ${i + 1} | ${s.name} | ${s.slug} | ${s.emoji || "-"} | ${s.color} | ${s.category} | ${s.isDefault ? "Yes" : "No"} | ${s.isTerminal ? "Yes" : "No"} |`),
12
+ ];
13
+ return {
14
+ content: [{ type: "text", text: lines.join("\n") || "No statuses found." }],
15
+ };
16
+ }
17
+ catch (err) {
18
+ return {
19
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
20
+ isError: true,
21
+ };
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=list-statuses.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ApiClient } from "../api-client.js";
3
+ export declare function registerListTransitions(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-transitions.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ export function registerListTransitions(server, api) {
3
+ server.tool("list_transitions", "List workflow transitions for a project", {
4
+ project: z.string().describe("Project slug"),
5
+ }, async (params) => {
6
+ try {
7
+ const transitions = await api.get(`/api/projects/${params.project}/transitions`);
8
+ const lines = [
9
+ "| # | From | To | Allowed Roles |",
10
+ "|---|------|----|---------------|",
11
+ ...transitions.map((t, i) => `| ${i + 1} | ${t.fromStatusName} | ${t.toStatusName} | ${t.allowedRoles?.join(", ") || "-"} |`),
12
+ ];
13
+ return {
14
+ content: [{ type: "text", text: lines.join("\n") || "No transitions found." }],
15
+ };
16
+ }
17
+ catch (err) {
18
+ return {
19
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
20
+ isError: true,
21
+ };
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=list-transitions.js.map
@@ -11,7 +11,7 @@ export function registerUpdateImplementationItem(server, api) {
11
11
  try {
12
12
  await api.patch(`/api/tickets/${params.number}/items/${params.item_index}`, {
13
13
  status: params.status,
14
- note: params.note,
14
+ note: params.note?.replace(/\\n/g, "\n"),
15
15
  });
16
16
  return {
17
17
  content: [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@k-system/tickr-mcp",
3
- "version": "0.1.5",
4
- "description": "MCP server for Tickr project management — 17 tools for ticket CRUD, triage, labels, cycles, epics",
3
+ "version": "0.2.0",
4
+ "description": "MCP server for Tickr project management — 40 tools for ticket CRUD, workflow, projects, attachments, triage, labels, cycles, epics",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {