@k-system/tickr-mcp 0.2.0 → 0.3.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 (44) hide show
  1. package/dist/index.js +55 -1
  2. package/dist/tools/add-project-member.d.ts +4 -0
  3. package/dist/tools/add-project-member.js +32 -0
  4. package/dist/tools/create-label.d.ts +4 -0
  5. package/dist/tools/create-label.js +30 -0
  6. package/dist/tools/create-ticket.js +2 -0
  7. package/dist/tools/delete-comment.d.ts +4 -0
  8. package/dist/tools/delete-comment.js +22 -0
  9. package/dist/tools/delete-cycle.d.ts +4 -0
  10. package/dist/tools/delete-cycle.js +26 -0
  11. package/dist/tools/delete-epic.d.ts +4 -0
  12. package/dist/tools/delete-epic.js +26 -0
  13. package/dist/tools/delete-label.d.ts +4 -0
  14. package/dist/tools/delete-label.js +26 -0
  15. package/dist/tools/fail-dev-task.d.ts +4 -0
  16. package/dist/tools/fail-dev-task.js +29 -0
  17. package/dist/tools/get-next-statuses.d.ts +4 -0
  18. package/dist/tools/get-next-statuses.js +30 -0
  19. package/dist/tools/list-dev-assignments.d.ts +4 -0
  20. package/dist/tools/list-dev-assignments.js +27 -0
  21. package/dist/tools/list-project-members.d.ts +4 -0
  22. package/dist/tools/list-project-members.js +29 -0
  23. package/dist/tools/list-relations.d.ts +4 -0
  24. package/dist/tools/list-relations.js +30 -0
  25. package/dist/tools/list-workflow-presets.d.ts +4 -0
  26. package/dist/tools/list-workflow-presets.js +22 -0
  27. package/dist/tools/remove-project-member.d.ts +4 -0
  28. package/dist/tools/remove-project-member.js +26 -0
  29. package/dist/tools/update-comment.d.ts +4 -0
  30. package/dist/tools/update-comment.js +24 -0
  31. package/dist/tools/update-cycle.d.ts +4 -0
  32. package/dist/tools/update-cycle.js +39 -0
  33. package/dist/tools/update-epic.d.ts +4 -0
  34. package/dist/tools/update-epic.js +42 -0
  35. package/dist/tools/update-label.d.ts +4 -0
  36. package/dist/tools/update-label.js +33 -0
  37. package/dist/tools/update-project-member-role.d.ts +4 -0
  38. package/dist/tools/update-project-member-role.js +29 -0
  39. package/dist/tools/update-status.d.ts +4 -0
  40. package/dist/tools/update-status.js +39 -0
  41. package/dist/tools/update-ticket.js +12 -4
  42. package/dist/tools/update-transitions.d.ts +4 -0
  43. package/dist/tools/update-transitions.js +37 -0
  44. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -50,6 +50,33 @@ import { registerCreateEpic } from "./tools/create-epic.js";
50
50
  // Phase 2 — Skupina F: Implementation Items
51
51
  import { registerCreateImplementationItem } from "./tools/create-implementation-item.js";
52
52
  import { registerDeleteImplementationItem } from "./tools/delete-implementation-item.js";
53
+ // Phase 3 — Skupina A: Workflow & Status
54
+ import { registerUpdateTransitions } from "./tools/update-transitions.js";
55
+ import { registerUpdateStatus } from "./tools/update-status.js";
56
+ import { registerListWorkflowPresets } from "./tools/list-workflow-presets.js";
57
+ import { registerGetNextStatuses } from "./tools/get-next-statuses.js";
58
+ // Phase 3 — Skupina B: Comments & Activity
59
+ import { registerUpdateComment } from "./tools/update-comment.js";
60
+ import { registerDeleteComment } from "./tools/delete-comment.js";
61
+ // Phase 3 — Skupina C: Relations
62
+ import { registerListRelations } from "./tools/list-relations.js";
63
+ // Phase 3 — Skupina D: Dev Queue
64
+ import { registerFailDevTask } from "./tools/fail-dev-task.js";
65
+ import { registerListDevAssignments } from "./tools/list-dev-assignments.js";
66
+ // Phase 3 — Skupina E: Labels CRUD
67
+ import { registerCreateLabel } from "./tools/create-label.js";
68
+ import { registerUpdateLabel } from "./tools/update-label.js";
69
+ import { registerDeleteLabel } from "./tools/delete-label.js";
70
+ // Phase 3 — Skupina F: Cycles/Epics extras
71
+ import { registerUpdateCycle } from "./tools/update-cycle.js";
72
+ import { registerDeleteCycle } from "./tools/delete-cycle.js";
73
+ import { registerUpdateEpic } from "./tools/update-epic.js";
74
+ import { registerDeleteEpic } from "./tools/delete-epic.js";
75
+ // ADR-0026 Phase 2f: Project Members
76
+ import { registerListProjectMembers } from "./tools/list-project-members.js";
77
+ import { registerAddProjectMember } from "./tools/add-project-member.js";
78
+ import { registerUpdateProjectMemberRole } from "./tools/update-project-member-role.js";
79
+ import { registerRemoveProjectMember } from "./tools/remove-project-member.js";
53
80
  // Resources
54
81
  import { registerTicketResource } from "./resources/ticket-resource.js";
55
82
  import { registerProjectResource } from "./resources/project-resource.js";
@@ -58,7 +85,7 @@ async function main() {
58
85
  const api = new ApiClient(config);
59
86
  const server = new McpServer({
60
87
  name: "tickr",
61
- version: "0.1.4",
88
+ version: "0.1.5",
62
89
  });
63
90
  // Registrace tools
64
91
  registerCreateTicket(server, api);
@@ -107,6 +134,33 @@ async function main() {
107
134
  // Phase 2 — Skupina F: Implementation Items
108
135
  registerCreateImplementationItem(server, api);
109
136
  registerDeleteImplementationItem(server, api);
137
+ // Phase 3 — Skupina A: Workflow & Status
138
+ registerUpdateTransitions(server, api);
139
+ registerUpdateStatus(server, api);
140
+ registerListWorkflowPresets(server, api);
141
+ registerGetNextStatuses(server, api);
142
+ // Phase 3 — Skupina B: Comments & Activity
143
+ registerUpdateComment(server, api);
144
+ registerDeleteComment(server, api);
145
+ // Phase 3 — Skupina C: Relations
146
+ registerListRelations(server, api);
147
+ // Phase 3 — Skupina D: Dev Queue
148
+ registerFailDevTask(server, api);
149
+ registerListDevAssignments(server, api);
150
+ // Phase 3 — Skupina E: Labels CRUD
151
+ registerCreateLabel(server, api);
152
+ registerUpdateLabel(server, api);
153
+ registerDeleteLabel(server, api);
154
+ // Phase 3 — Skupina F: Cycles/Epics extras
155
+ registerUpdateCycle(server, api);
156
+ registerDeleteCycle(server, api);
157
+ registerUpdateEpic(server, api);
158
+ registerDeleteEpic(server, api);
159
+ // ADR-0026 Phase 2f: Project Members
160
+ registerListProjectMembers(server, api);
161
+ registerAddProjectMember(server, api);
162
+ registerUpdateProjectMemberRole(server, api);
163
+ registerRemoveProjectMember(server, api);
110
164
  // Registrace resources
111
165
  registerTicketResource(server, api);
112
166
  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 registerAddProjectMember(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=add-project-member.d.ts.map
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ export function registerAddProjectMember(server, api) {
3
+ server.tool("add_project_member", "Add a member to a project with a specific role", {
4
+ project: z.string().describe("Project slug"),
5
+ user_id: z.string().describe("UUID of the user to add"),
6
+ role: z
7
+ .enum(["Viewer", "Developer", "Analytic", "Editor", "ProjectAdmin"])
8
+ .describe("Project role for the user"),
9
+ }, async (params) => {
10
+ try {
11
+ await api.post(`/api/projects/${params.project}/members`, {
12
+ userId: params.user_id,
13
+ role: params.role,
14
+ });
15
+ return {
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: `Member added to project "${params.project}" with role ${params.role}`,
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=add-project-member.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 registerCreateLabel(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=create-label.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ export function registerCreateLabel(server, api) {
3
+ server.tool("create_label", "Create a new label in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ name: z.string().describe("Label name"),
6
+ color: z.string().describe("Hex color code, e.g. '#ef4444'"),
7
+ }, async (params) => {
8
+ try {
9
+ const result = await api.post(`/api/projects/${params.project}/labels`, {
10
+ name: params.name,
11
+ color: params.color,
12
+ });
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: `Created label "${result.name}" (${result.id}) with color ${result.color}`,
18
+ },
19
+ ],
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
+ //# sourceMappingURL=create-label.js.map
@@ -8,6 +8,7 @@ export function registerCreateTicket(server, api) {
8
8
  priority: z.enum(["P0", "P1", "P2", "P3"]).default("P2"),
9
9
  content: z.string().optional().describe("Markdown content (analysis, solution)"),
10
10
  affected_parts: z.array(z.string()).optional(),
11
+ due_date: z.string().optional().describe("Due date in YYYY-MM-DD format"),
11
12
  }, async (params) => {
12
13
  try {
13
14
  // Unescapovat double-escaped newlines z MCP tool parametrů
@@ -19,6 +20,7 @@ export function registerCreateTicket(server, api) {
19
20
  priority: params.priority,
20
21
  content,
21
22
  affectedParts: params.affected_parts,
23
+ dueDate: params.due_date,
22
24
  });
23
25
  return {
24
26
  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 registerDeleteComment(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-comment.d.ts.map
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteComment(server, api) {
3
+ server.tool("delete_comment", "Delete a comment", {
4
+ comment_id: z.string().describe("UUID of the comment to delete"),
5
+ }, async (params) => {
6
+ try {
7
+ await api.delete(`/api/comments/${params.comment_id}`);
8
+ return {
9
+ content: [
10
+ { type: "text", text: `Comment ${params.comment_id} deleted` },
11
+ ],
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=delete-comment.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 registerDeleteCycle(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-cycle.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteCycle(server, api) {
3
+ server.tool("delete_cycle", "Delete a cycle (sprint) from a project", {
4
+ project: z.string().describe("Project slug"),
5
+ cycle_id: z.string().describe("UUID of the cycle to delete"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.delete(`/api/projects/${params.project}/cycles/${params.cycle_id}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Cycle ${params.cycle_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-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 registerDeleteEpic(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-epic.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteEpic(server, api) {
3
+ server.tool("delete_epic", "Delete an epic from a project", {
4
+ project: z.string().describe("Project slug"),
5
+ epic_id: z.string().describe("UUID of the epic to delete"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.delete(`/api/projects/${params.project}/epics/${params.epic_id}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Epic ${params.epic_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-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 registerDeleteLabel(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=delete-label.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerDeleteLabel(server, api) {
3
+ server.tool("delete_label", "Delete a label from a project", {
4
+ project: z.string().describe("Project slug"),
5
+ label_id: z.string().describe("UUID of the label to delete"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.delete(`/api/projects/${params.project}/labels/${params.label_id}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Label ${params.label_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-label.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 registerFailDevTask(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=fail-dev-task.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ export function registerFailDevTask(server, api) {
3
+ server.tool("fail_dev_task", "Mark a dev agent task as failed with a reason", {
4
+ assignment_id: z.string().describe("UUID of the dev agent assignment"),
5
+ reason: z.string().describe("Reason why the task failed"),
6
+ }, async (params) => {
7
+ try {
8
+ const reason = params.reason.replace(/\\n/g, "\n");
9
+ await api.post(`/api/dev-queue/fail/${params.assignment_id}`, {
10
+ reason,
11
+ });
12
+ return {
13
+ content: [
14
+ {
15
+ type: "text",
16
+ text: `Task ${params.assignment_id} marked as failed.`,
17
+ },
18
+ ],
19
+ };
20
+ }
21
+ catch (err) {
22
+ return {
23
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
24
+ isError: true,
25
+ };
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=fail-dev-task.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 registerGetNextStatuses(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=get-next-statuses.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ export function registerGetNextStatuses(server, api) {
3
+ server.tool("get_next_statuses", "Get available next statuses for a ticket (based on current status and user role)", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' or 'TKR-BUG-0042'"),
5
+ }, async (params) => {
6
+ try {
7
+ const statuses = await api.get(`/api/tickets/${params.number}/next-statuses`);
8
+ if (statuses.length === 0) {
9
+ return {
10
+ content: [{ type: "text", text: `No available transitions for ${params.number}` }],
11
+ };
12
+ }
13
+ const lines = [
14
+ "| # | Status | Emoji | Color | Category |",
15
+ "|---|--------|-------|-------|----------|",
16
+ ...statuses.map((s, i) => `| ${i + 1} | ${s.name} | ${s.emoji || "-"} | ${s.color} | ${s.category} |`),
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
+ //# sourceMappingURL=get-next-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 registerListDevAssignments(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-dev-assignments.d.ts.map
@@ -0,0 +1,27 @@
1
+ export function registerListDevAssignments(server, api) {
2
+ server.tool("list_dev_assignments", "List all dev queue assignments (pending, in-progress, completed, failed)", {}, async () => {
3
+ try {
4
+ const assignments = await api.get("/api/dev-queue/assignments");
5
+ if (assignments.length === 0) {
6
+ return {
7
+ content: [{ type: "text", text: "No dev assignments found." }],
8
+ };
9
+ }
10
+ const lines = [
11
+ "| # | Ticket | Title | Status | Agent | Assigned | Completed |",
12
+ "|---|--------|-------|--------|-------|----------|-----------|",
13
+ ...assignments.map((a, i) => `| ${i + 1} | ${a.ticketDisplayNumber} | ${a.ticketTitle} | ${a.status} | ${a.agentName || "-"} | ${a.assignedAt} | ${a.completedAt || "-"} |`),
14
+ ];
15
+ return {
16
+ content: [{ type: "text", text: lines.join("\n") }],
17
+ };
18
+ }
19
+ catch (err) {
20
+ return {
21
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
22
+ isError: true,
23
+ };
24
+ }
25
+ });
26
+ }
27
+ //# sourceMappingURL=list-dev-assignments.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 registerListProjectMembers(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-project-members.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ export function registerListProjectMembers(server, api) {
3
+ server.tool("list_project_members", "List members of a project with their roles", {
4
+ project: z.string().describe("Project slug"),
5
+ }, async (params) => {
6
+ try {
7
+ const members = await api.get(`/api/projects/${params.project}/members`);
8
+ if (!members || members.length === 0) {
9
+ return {
10
+ content: [{ type: "text", text: "No members found." }],
11
+ };
12
+ }
13
+ const header = "| User | Email | Role | Added |";
14
+ const separator = "|------|-------|------|-------|";
15
+ const rows = members.map((m) => `| ${m.userName} | ${m.email} | ${m.role} | ${m.addedAt?.substring(0, 10) ?? "—"} |`);
16
+ const text = [header, separator, ...rows].join("\n");
17
+ return {
18
+ content: [{ type: "text", text }],
19
+ };
20
+ }
21
+ catch (err) {
22
+ return {
23
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
24
+ isError: true,
25
+ };
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=list-project-members.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 registerListRelations(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-relations.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ export function registerListRelations(server, api) {
3
+ server.tool("list_relations", "List all relations for a ticket", {
4
+ number: z.string().describe("Ticket display number, e.g. 'TKR-42' or 'TKR-BUG-0042'"),
5
+ }, async (params) => {
6
+ try {
7
+ const relations = await api.get(`/api/tickets/${params.number}/relations`);
8
+ if (relations.length === 0) {
9
+ return {
10
+ content: [{ type: "text", text: `No relations for ${params.number}` }],
11
+ };
12
+ }
13
+ const lines = [
14
+ "| # | Direction | Type | Ticket | Title | Status |",
15
+ "|---|-----------|------|--------|-------|--------|",
16
+ ...relations.map((r, i) => `| ${i + 1} | ${r.direction} | ${r.type} | ${r.displayNumber} | ${r.title} | ${r.status} |`),
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
+ //# sourceMappingURL=list-relations.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 registerListWorkflowPresets(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=list-workflow-presets.d.ts.map
@@ -0,0 +1,22 @@
1
+ export function registerListWorkflowPresets(server, api) {
2
+ server.tool("list_workflow_presets", "List all available workflow presets", {}, async () => {
3
+ try {
4
+ const presets = await api.get("/api/workflow-presets");
5
+ const lines = [
6
+ "| # | Name | Description | Statuses | Transitions |",
7
+ "|---|------|-------------|----------|-------------|",
8
+ ...presets.map((p, i) => `| ${i + 1} | ${p.name} | ${p.description || "-"} | ${p.statusCount} | ${p.transitionCount} |`),
9
+ ];
10
+ return {
11
+ content: [{ type: "text", text: lines.join("\n") || "No presets 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-workflow-presets.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 registerRemoveProjectMember(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=remove-project-member.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export function registerRemoveProjectMember(server, api) {
3
+ server.tool("remove_project_member", "Remove a member from a project", {
4
+ project: z.string().describe("Project slug"),
5
+ user_id: z.string().describe("UUID of the user to remove"),
6
+ }, async (params) => {
7
+ try {
8
+ await api.delete(`/api/projects/${params.project}/members/${params.user_id}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: "text",
13
+ text: `Member ${params.user_id} removed 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=remove-project-member.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 registerUpdateComment(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=update-comment.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ export function registerUpdateComment(server, api) {
3
+ server.tool("update_comment", "Update the text of an existing comment", {
4
+ comment_id: z.string().describe("UUID of the comment to update"),
5
+ text: z.string().describe("New comment text (markdown)"),
6
+ }, async (params) => {
7
+ try {
8
+ const text = params.text.replace(/\\n/g, "\n");
9
+ await api.put(`/api/comments/${params.comment_id}`, { text });
10
+ return {
11
+ content: [
12
+ { type: "text", text: `Comment ${params.comment_id} updated` },
13
+ ],
14
+ };
15
+ }
16
+ catch (err) {
17
+ return {
18
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
19
+ isError: true,
20
+ };
21
+ }
22
+ });
23
+ }
24
+ //# sourceMappingURL=update-comment.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 registerUpdateCycle(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=update-cycle.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ export function registerUpdateCycle(server, api) {
3
+ server.tool("update_cycle", "Update a cycle (sprint) in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ cycle_id: z.string().describe("UUID of the cycle to update"),
6
+ name: z.string().optional().describe("New cycle name"),
7
+ startDate: z.string().optional().describe("New start date (ISO 8601, e.g. '2026-03-15')"),
8
+ endDate: z.string().optional().describe("New end date (ISO 8601, e.g. '2026-03-29')"),
9
+ status: z.string().optional().describe("New status: planned, active, completed"),
10
+ }, async (params) => {
11
+ try {
12
+ const body = {};
13
+ if (params.name !== undefined)
14
+ body.name = params.name;
15
+ if (params.startDate !== undefined)
16
+ body.startDate = params.startDate;
17
+ if (params.endDate !== undefined)
18
+ body.endDate = params.endDate;
19
+ if (params.status !== undefined)
20
+ body.status = params.status;
21
+ await api.put(`/api/projects/${params.project}/cycles/${params.cycle_id}`, body);
22
+ return {
23
+ content: [
24
+ {
25
+ type: "text",
26
+ text: `Cycle ${params.cycle_id} updated in project ${params.project}`,
27
+ },
28
+ ],
29
+ };
30
+ }
31
+ catch (err) {
32
+ return {
33
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
34
+ isError: true,
35
+ };
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=update-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 registerUpdateEpic(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=update-epic.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ export function registerUpdateEpic(server, api) {
3
+ server.tool("update_epic", "Update an epic in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ epic_id: z.string().describe("UUID of the epic to update"),
6
+ name: z.string().optional().describe("New epic name"),
7
+ description: z.string().optional().describe("New epic description"),
8
+ color: z.string().optional().describe("New hex color code, e.g. '#6366f1'"),
9
+ startDate: z.string().optional().describe("New start date (YYYY-MM-DD)"),
10
+ targetDate: z.string().optional().describe("New target date (YYYY-MM-DD)"),
11
+ }, async (params) => {
12
+ try {
13
+ const body = {};
14
+ if (params.name !== undefined)
15
+ body.name = params.name;
16
+ if (params.description !== undefined)
17
+ body.description = params.description.replace(/\\n/g, "\n");
18
+ if (params.color !== undefined)
19
+ body.color = params.color;
20
+ if (params.startDate !== undefined)
21
+ body.startDate = params.startDate;
22
+ if (params.targetDate !== undefined)
23
+ body.targetDate = params.targetDate;
24
+ await api.put(`/api/projects/${params.project}/epics/${params.epic_id}`, body);
25
+ return {
26
+ content: [
27
+ {
28
+ type: "text",
29
+ text: `Epic ${params.epic_id} updated in project ${params.project}`,
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=update-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 registerUpdateLabel(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=update-label.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ export function registerUpdateLabel(server, api) {
3
+ server.tool("update_label", "Update a label in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ label_id: z.string().describe("UUID of the label to update"),
6
+ name: z.string().optional().describe("New label name"),
7
+ color: z.string().optional().describe("New hex color code, e.g. '#ef4444'"),
8
+ }, async (params) => {
9
+ try {
10
+ const body = {};
11
+ if (params.name !== undefined)
12
+ body.name = params.name;
13
+ if (params.color !== undefined)
14
+ body.color = params.color;
15
+ await api.put(`/api/projects/${params.project}/labels/${params.label_id}`, body);
16
+ return {
17
+ content: [
18
+ {
19
+ type: "text",
20
+ text: `Label ${params.label_id} updated in project ${params.project}`,
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=update-label.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 registerUpdateProjectMemberRole(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=update-project-member-role.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ export function registerUpdateProjectMemberRole(server, api) {
3
+ server.tool("update_project_member_role", "Update the role of a project member", {
4
+ project: z.string().describe("Project slug"),
5
+ user_id: z.string().describe("UUID of the user"),
6
+ role: z
7
+ .enum(["Viewer", "Developer", "Analytic", "Editor", "ProjectAdmin"])
8
+ .describe("New project role"),
9
+ }, async (params) => {
10
+ try {
11
+ await api.put(`/api/projects/${params.project}/members/${params.user_id}/role`, { role: params.role });
12
+ return {
13
+ content: [
14
+ {
15
+ type: "text",
16
+ text: `Role updated to ${params.role} for user ${params.user_id} in project "${params.project}"`,
17
+ },
18
+ ],
19
+ };
20
+ }
21
+ catch (err) {
22
+ return {
23
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
24
+ isError: true,
25
+ };
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=update-project-member-role.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 registerUpdateStatus(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=update-status.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ export function registerUpdateStatus(server, api) {
3
+ server.tool("update_status", "Update a workflow status in a project", {
4
+ project: z.string().describe("Project slug"),
5
+ status_id: z.string().describe("Status ID to update"),
6
+ name: z.string().optional().describe("New display name"),
7
+ emoji: z.string().optional().describe("New emoji icon"),
8
+ color: z.string().optional().describe("New hex color code, e.g. '#3b82f6'"),
9
+ category: z.string().optional().describe("New category: backlog, active, done, cancelled"),
10
+ }, async (params) => {
11
+ try {
12
+ const body = {};
13
+ if (params.name !== undefined)
14
+ body.name = params.name;
15
+ if (params.emoji !== undefined)
16
+ body.emoji = params.emoji;
17
+ if (params.color !== undefined)
18
+ body.color = params.color;
19
+ if (params.category !== undefined)
20
+ body.category = params.category;
21
+ await api.put(`/api/projects/${params.project}/statuses/${params.status_id}`, body);
22
+ return {
23
+ content: [
24
+ {
25
+ type: "text",
26
+ text: `Status ${params.status_id} updated in project ${params.project}`,
27
+ },
28
+ ],
29
+ };
30
+ }
31
+ catch (err) {
32
+ return {
33
+ content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
34
+ isError: true,
35
+ };
36
+ }
37
+ });
38
+ }
39
+ //# sourceMappingURL=update-status.js.map
@@ -8,13 +8,21 @@ export function registerUpdateTicket(server, api) {
8
8
  priority: z.string().optional(),
9
9
  assignee: z.string().optional().describe("Username or 'unassigned'"),
10
10
  scope: z.string().optional(),
11
+ due_date: z.string().optional().describe("Due date in YYYY-MM-DD format, or 'clear' to remove"),
11
12
  }, async (params) => {
12
13
  try {
13
- const { number, ...updates } = params;
14
+ const { number, due_date, ...rest } = params;
14
15
  // Unescapovat double-escaped newlines z MCP tool parametrů
15
- if (updates.content)
16
- updates.content = updates.content.replace(/\\n/g, "\n");
17
- const ticket = await api.put(`/api/tickets/${number}`, updates);
16
+ if (rest.content)
17
+ rest.content = rest.content.replace(/\\n/g, "\n");
18
+ const body = { ...rest };
19
+ if (due_date === "clear") {
20
+ body.clearDueDate = true;
21
+ }
22
+ else if (due_date) {
23
+ body.dueDate = due_date;
24
+ }
25
+ const ticket = await api.put(`/api/tickets/${number}`, body);
18
26
  return {
19
27
  content: [
20
28
  {
@@ -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 registerUpdateTransitions(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=update-transitions.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ export function registerUpdateTransitions(server, api) {
3
+ server.tool("update_transitions", "Replace all workflow transitions for a project", {
4
+ project: z.string().describe("Project slug"),
5
+ transitions: z
6
+ .array(z.object({
7
+ fromStatusId: z.string().describe("Source status ID"),
8
+ toStatusId: z.string().describe("Target status ID"),
9
+ allowedRoles: z
10
+ .array(z.string())
11
+ .optional()
12
+ .describe("Roles allowed to perform this transition"),
13
+ }))
14
+ .describe("Array of transition definitions"),
15
+ }, async (params) => {
16
+ try {
17
+ await api.put(`/api/projects/${params.project}/transitions`, {
18
+ transitions: params.transitions,
19
+ });
20
+ return {
21
+ content: [
22
+ {
23
+ type: "text",
24
+ text: `Updated ${params.transitions.length} transitions for project ${params.project}`,
25
+ },
26
+ ],
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=update-transitions.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-system/tickr-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
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",