@k-system/tickr-mcp 0.4.0 → 0.5.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.
- package/dist/server.js +18 -0
- package/dist/tools/add-release-ticket.d.ts +4 -0
- package/dist/tools/add-release-ticket.js +27 -0
- package/dist/tools/create-release.d.ts +4 -0
- package/dist/tools/create-release.js +34 -0
- package/dist/tools/generate-release-notes.d.ts +4 -0
- package/dist/tools/generate-release-notes.js +66 -0
- package/dist/tools/get-release.d.ts +4 -0
- package/dist/tools/get-release.js +42 -0
- package/dist/tools/list-releases.d.ts +4 -0
- package/dist/tools/list-releases.js +38 -0
- package/dist/tools/publish-release.d.ts +4 -0
- package/dist/tools/publish-release.js +26 -0
- package/dist/tools/remove-release-ticket.d.ts +4 -0
- package/dist/tools/remove-release-ticket.js +27 -0
- package/dist/tools/update-release.d.ts +4 -0
- package/dist/tools/update-release.js +36 -0
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -76,6 +76,15 @@ import { registerListProjectMembers } from "./tools/list-project-members.js";
|
|
|
76
76
|
import { registerAddProjectMember } from "./tools/add-project-member.js";
|
|
77
77
|
import { registerUpdateProjectMemberRole } from "./tools/update-project-member-role.js";
|
|
78
78
|
import { registerRemoveProjectMember } from "./tools/remove-project-member.js";
|
|
79
|
+
// ADR-0030: Releases
|
|
80
|
+
import { registerCreateRelease } from "./tools/create-release.js";
|
|
81
|
+
import { registerGetRelease } from "./tools/get-release.js";
|
|
82
|
+
import { registerListReleases } from "./tools/list-releases.js";
|
|
83
|
+
import { registerUpdateRelease } from "./tools/update-release.js";
|
|
84
|
+
import { registerPublishRelease } from "./tools/publish-release.js";
|
|
85
|
+
import { registerAddReleaseTicket } from "./tools/add-release-ticket.js";
|
|
86
|
+
import { registerRemoveReleaseTicket } from "./tools/remove-release-ticket.js";
|
|
87
|
+
import { registerGenerateReleaseNotes } from "./tools/generate-release-notes.js";
|
|
79
88
|
// Resources
|
|
80
89
|
import { registerTicketResource } from "./resources/ticket-resource.js";
|
|
81
90
|
import { registerProjectResource } from "./resources/project-resource.js";
|
|
@@ -160,6 +169,15 @@ export async function startServer() {
|
|
|
160
169
|
registerAddProjectMember(server, api);
|
|
161
170
|
registerUpdateProjectMemberRole(server, api);
|
|
162
171
|
registerRemoveProjectMember(server, api);
|
|
172
|
+
// ADR-0030: Releases
|
|
173
|
+
registerCreateRelease(server, api);
|
|
174
|
+
registerGetRelease(server, api);
|
|
175
|
+
registerListReleases(server, api);
|
|
176
|
+
registerUpdateRelease(server, api);
|
|
177
|
+
registerPublishRelease(server, api);
|
|
178
|
+
registerAddReleaseTicket(server, api);
|
|
179
|
+
registerRemoveReleaseTicket(server, api);
|
|
180
|
+
registerGenerateReleaseNotes(server, api);
|
|
163
181
|
// Registrace resources
|
|
164
182
|
registerTicketResource(server, api);
|
|
165
183
|
registerProjectResource(server, api);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerAddReleaseTicket(server, api) {
|
|
3
|
+
server.tool("add_release_ticket", "Link a ticket to a release", {
|
|
4
|
+
project: z.string().describe("Project slug"),
|
|
5
|
+
release_id: z.string().describe("UUID of the release"),
|
|
6
|
+
ticket_number: z.string().describe("Ticket display number, e.g. 'TKR-42' or 'TKR-BUG-0042'"),
|
|
7
|
+
}, async (params) => {
|
|
8
|
+
try {
|
|
9
|
+
await api.post(`/api/projects/${params.project}/releases/${params.release_id}/tickets`, { ticketNumber: params.ticket_number });
|
|
10
|
+
return {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: `Ticket ${params.ticket_number} added to release ${params.release_id}`,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
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=add-release-ticket.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerCreateRelease(server, api) {
|
|
3
|
+
server.tool("create_release", "Create a new release in a project", {
|
|
4
|
+
project: z.string().describe("Project slug, e.g. 'tickr'"),
|
|
5
|
+
version: z.string().describe("Semantic version, e.g. '1.6.0'"),
|
|
6
|
+
name: z.string().optional().describe("Human-readable release name"),
|
|
7
|
+
git_tag: z.string().optional().describe("Git tag name, e.g. 'v1.6.0'"),
|
|
8
|
+
cycle_id: z.string().optional().describe("UUID of linked cycle (sprint)"),
|
|
9
|
+
}, async (params) => {
|
|
10
|
+
try {
|
|
11
|
+
const result = await api.post(`/api/projects/${params.project}/releases`, {
|
|
12
|
+
version: params.version,
|
|
13
|
+
name: params.name,
|
|
14
|
+
gitTag: params.git_tag,
|
|
15
|
+
cycleId: params.cycle_id,
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
content: [
|
|
19
|
+
{
|
|
20
|
+
type: "text",
|
|
21
|
+
text: `Created release ${result.version} (id: ${result.id})`,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
29
|
+
isError: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=create-release.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 registerGenerateReleaseNotes(server: McpServer, api: ApiClient): void;
|
|
4
|
+
//# sourceMappingURL=generate-release-notes.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerGenerateReleaseNotes(server, api) {
|
|
3
|
+
server.tool("generate_release_notes", "Generate markdown release notes from linked tickets (client-side generation)", {
|
|
4
|
+
project: z.string().describe("Project slug"),
|
|
5
|
+
release_id: z.string().describe("UUID of the release"),
|
|
6
|
+
}, async (params) => {
|
|
7
|
+
try {
|
|
8
|
+
const r = await api.get(`/api/projects/${params.project}/releases/${params.release_id}`);
|
|
9
|
+
const lines = [
|
|
10
|
+
`# Release ${r.version}${r.name ? ` — ${r.name}` : ""}`,
|
|
11
|
+
"",
|
|
12
|
+
];
|
|
13
|
+
if (!r.tickets?.length) {
|
|
14
|
+
lines.push("No tickets linked to this release.");
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
// Seskupit tickety podle typu
|
|
20
|
+
const grouped = {};
|
|
21
|
+
for (const t of r.tickets) {
|
|
22
|
+
const key = t.type.toLowerCase();
|
|
23
|
+
if (!grouped[key])
|
|
24
|
+
grouped[key] = [];
|
|
25
|
+
grouped[key].push(t);
|
|
26
|
+
}
|
|
27
|
+
// Pořadí sekcí a labely
|
|
28
|
+
const sectionOrder = [
|
|
29
|
+
["feature", "Features"],
|
|
30
|
+
["adr", "Architecture Decisions"],
|
|
31
|
+
["bug", "Bug Fixes"],
|
|
32
|
+
["task", "Tasks"],
|
|
33
|
+
];
|
|
34
|
+
for (const [typeKey, sectionTitle] of sectionOrder) {
|
|
35
|
+
const tickets = grouped[typeKey];
|
|
36
|
+
if (!tickets?.length)
|
|
37
|
+
continue;
|
|
38
|
+
lines.push(`## ${sectionTitle}`, "");
|
|
39
|
+
for (const t of tickets) {
|
|
40
|
+
lines.push(`- **${t.displayNumber}** ${t.title}`);
|
|
41
|
+
}
|
|
42
|
+
lines.push("");
|
|
43
|
+
}
|
|
44
|
+
// Ostatní typy, které nejsou ve standardním pořadí
|
|
45
|
+
for (const [typeKey, tickets] of Object.entries(grouped)) {
|
|
46
|
+
if (sectionOrder.some(([k]) => k === typeKey))
|
|
47
|
+
continue;
|
|
48
|
+
lines.push(`## ${typeKey.charAt(0).toUpperCase() + typeKey.slice(1)}`, "");
|
|
49
|
+
for (const t of tickets) {
|
|
50
|
+
lines.push(`- **${t.displayNumber}** ${t.title}`);
|
|
51
|
+
}
|
|
52
|
+
lines.push("");
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
61
|
+
isError: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=generate-release-notes.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerGetRelease(server, api) {
|
|
3
|
+
server.tool("get_release", "Get full release detail including linked tickets", {
|
|
4
|
+
project: z.string().describe("Project slug"),
|
|
5
|
+
release_id: z.string().describe("UUID of the release"),
|
|
6
|
+
}, async (params) => {
|
|
7
|
+
try {
|
|
8
|
+
const r = await api.get(`/api/projects/${params.project}/releases/${params.release_id}`);
|
|
9
|
+
const lines = [
|
|
10
|
+
`# Release ${r.version}${r.name ? ` — ${r.name}` : ""}`,
|
|
11
|
+
"",
|
|
12
|
+
`| Field | Value |`,
|
|
13
|
+
`|-------|-------|`,
|
|
14
|
+
`| Id | ${r.id} |`,
|
|
15
|
+
`| Status | ${r.status} |`,
|
|
16
|
+
`| Git Tag | ${r.gitTag || "-"} |`,
|
|
17
|
+
`| Published | ${r.publishedAt || "-"} |`,
|
|
18
|
+
`| Created | ${r.createdAt} |`,
|
|
19
|
+
`| Updated | ${r.updatedAt} |`,
|
|
20
|
+
];
|
|
21
|
+
if (r.notes) {
|
|
22
|
+
lines.push("", "## Notes", "", r.notes);
|
|
23
|
+
}
|
|
24
|
+
if (r.tickets?.length > 0) {
|
|
25
|
+
lines.push("", "## Tickets", "", "| Number | Type | Title | Status |", "|--------|------|-------|--------|");
|
|
26
|
+
for (const t of r.tickets) {
|
|
27
|
+
lines.push(`| ${t.displayNumber} | ${t.type} | ${t.title} | ${t.status} |`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
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=get-release.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerListReleases(server, api) {
|
|
3
|
+
server.tool("list_releases", "List releases in a project with optional status filter", {
|
|
4
|
+
project: z.string().describe("Project slug"),
|
|
5
|
+
status: z.string().optional().describe("Filter by status: draft, published, archived"),
|
|
6
|
+
}, async (params) => {
|
|
7
|
+
try {
|
|
8
|
+
const qs = new URLSearchParams();
|
|
9
|
+
if (params.status)
|
|
10
|
+
qs.set("status", params.status);
|
|
11
|
+
const qsStr = qs.toString();
|
|
12
|
+
const path = `/api/projects/${params.project}/releases${qsStr ? `?${qsStr}` : ""}`;
|
|
13
|
+
const releases = await api.get(path);
|
|
14
|
+
if (!releases.length) {
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: "text", text: "No releases found." }],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const lines = [
|
|
20
|
+
"| Version | Name | Status | Tag | Tickets | Published | Created |",
|
|
21
|
+
"|---------|------|--------|-----|---------|-----------|---------|",
|
|
22
|
+
];
|
|
23
|
+
for (const r of releases) {
|
|
24
|
+
lines.push(`| ${r.version} | ${r.name || "-"} | ${r.status} | ${r.gitTag || "-"} | ${r.ticketCount} | ${r.publishedAt || "-"} | ${r.createdAt} |`);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
33
|
+
isError: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=list-releases.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerPublishRelease(server, api) {
|
|
3
|
+
server.tool("publish_release", "Publish a draft release — sets status to published and records publishedAt timestamp", {
|
|
4
|
+
project: z.string().describe("Project slug"),
|
|
5
|
+
release_id: z.string().describe("UUID of the release to publish"),
|
|
6
|
+
}, async (params) => {
|
|
7
|
+
try {
|
|
8
|
+
await api.post(`/api/projects/${params.project}/releases/${params.release_id}/publish`);
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: `Release ${params.release_id} published in 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=publish-release.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 registerRemoveReleaseTicket(server: McpServer, api: ApiClient): void;
|
|
4
|
+
//# sourceMappingURL=remove-release-ticket.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerRemoveReleaseTicket(server, api) {
|
|
3
|
+
server.tool("remove_release_ticket", "Remove a ticket from a release", {
|
|
4
|
+
project: z.string().describe("Project slug"),
|
|
5
|
+
release_id: z.string().describe("UUID of the release"),
|
|
6
|
+
ticket_id: z.string().describe("UUID of the ticket to remove from the release"),
|
|
7
|
+
}, async (params) => {
|
|
8
|
+
try {
|
|
9
|
+
await api.delete(`/api/projects/${params.project}/releases/${params.release_id}/tickets/${params.ticket_id}`);
|
|
10
|
+
return {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: `Ticket ${params.ticket_id} removed from release ${params.release_id}`,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
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=remove-release-ticket.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerUpdateRelease(server, api) {
|
|
3
|
+
server.tool("update_release", "Update a release (name, notes, status)", {
|
|
4
|
+
project: z.string().describe("Project slug"),
|
|
5
|
+
release_id: z.string().describe("UUID of the release to update"),
|
|
6
|
+
name: z.string().optional().describe("New release name"),
|
|
7
|
+
notes: z.string().optional().describe("Release notes (markdown)"),
|
|
8
|
+
status: z.string().optional().describe("New status: draft, published, archived"),
|
|
9
|
+
}, async (params) => {
|
|
10
|
+
try {
|
|
11
|
+
const body = {};
|
|
12
|
+
if (params.name !== undefined)
|
|
13
|
+
body.name = params.name;
|
|
14
|
+
if (params.notes !== undefined)
|
|
15
|
+
body.notes = params.notes?.replace(/\\n/g, "\n");
|
|
16
|
+
if (params.status !== undefined)
|
|
17
|
+
body.status = params.status;
|
|
18
|
+
await api.put(`/api/projects/${params.project}/releases/${params.release_id}`, body);
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: "text",
|
|
23
|
+
text: `Release ${params.release_id} updated in project ${params.project}`,
|
|
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=update-release.js.map
|