@pschroee/redmine-mcp 0.5.7 → 0.5.10
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/formatters/index.d.ts +1 -1
- package/dist/formatters/metadata.d.ts +5 -1
- package/dist/formatters/metadata.js +6 -2
- package/dist/redmine/client.d.ts +1 -3
- package/dist/redmine/client.js +1 -4
- package/dist/tools/agile.js +5 -5
- package/dist/tools/core.js +8 -8
- package/dist/tools/files.js +2 -2
- package/dist/tools/memberships.js +2 -2
- package/dist/tools/metadata.js +28 -5
- package/dist/tools/time.js +2 -2
- package/dist/tools/wiki.js +5 -5
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ export { formatWikiPage, formatWikiPageList } from "./wiki.js";
|
|
|
7
7
|
export { formatVersion, formatVersionList } from "./version.js";
|
|
8
8
|
export { formatTimeEntry, formatTimeEntryList } from "./time.js";
|
|
9
9
|
export { formatGroup, formatGroupList } from "./group.js";
|
|
10
|
-
export { formatTrackerList, formatStatusList, formatCategoryList, formatPriorityList, formatActivityList, formatRoleList, formatRole, formatCategory, formatCustomFieldList, formatQueryList, formatDocumentCategoryList, } from "./metadata.js";
|
|
10
|
+
export { formatTrackerList, formatStatusList, formatCategoryList, formatPriorityList, formatActivityList, formatRoleList, formatRole, formatCategory, formatCustomFieldList, formatQueryList, formatDocumentCategoryList, type ProjectLookup, } from "./metadata.js";
|
|
11
11
|
export { formatRelation, formatRelationList } from "./relation.js";
|
|
12
12
|
export { formatAttachment, formatFileList } from "./file.js";
|
|
13
13
|
export { formatMembership, formatMembershipList } from "./membership.js";
|
|
@@ -124,10 +124,14 @@ export declare function formatCategory(response: {
|
|
|
124
124
|
* Format a list of custom fields as a Markdown table
|
|
125
125
|
*/
|
|
126
126
|
export declare function formatCustomFieldList(response: RedmineCustomFieldsResponse): string;
|
|
127
|
+
/**
|
|
128
|
+
* Project lookup map: ID -> name
|
|
129
|
+
*/
|
|
130
|
+
export type ProjectLookup = Record<number, string>;
|
|
127
131
|
/**
|
|
128
132
|
* Format a list of saved queries as a Markdown table
|
|
129
133
|
*/
|
|
130
|
-
export declare function formatQueryList(response: RedmineQueriesResponse): string;
|
|
134
|
+
export declare function formatQueryList(response: RedmineQueriesResponse, projectLookup?: ProjectLookup): string;
|
|
131
135
|
/**
|
|
132
136
|
* Format a list of document categories as a Markdown table
|
|
133
137
|
*/
|
|
@@ -176,7 +176,7 @@ export function formatCustomFieldList(response) {
|
|
|
176
176
|
/**
|
|
177
177
|
* Format a list of saved queries as a Markdown table
|
|
178
178
|
*/
|
|
179
|
-
export function formatQueryList(response) {
|
|
179
|
+
export function formatQueryList(response, projectLookup = {}) {
|
|
180
180
|
const queries = response.queries;
|
|
181
181
|
if (queries.length === 0) {
|
|
182
182
|
return "No queries found.";
|
|
@@ -188,7 +188,11 @@ export function formatQueryList(response) {
|
|
|
188
188
|
lines.push("|----|------|---------|------------|");
|
|
189
189
|
for (const query of queries) {
|
|
190
190
|
const visibility = query.is_public ? "Public" : "Private";
|
|
191
|
-
|
|
191
|
+
let project = "Global";
|
|
192
|
+
if (query.project_id) {
|
|
193
|
+
const projectName = projectLookup[query.project_id];
|
|
194
|
+
project = projectName ? `${projectName} (${query.project_id})` : `#${query.project_id}`;
|
|
195
|
+
}
|
|
192
196
|
lines.push(`| ${query.id} | ${query.name} | ${project} | ${visibility} |`);
|
|
193
197
|
}
|
|
194
198
|
return lines.join("\n");
|
package/dist/redmine/client.d.ts
CHANGED
|
@@ -230,9 +230,7 @@ export declare class RedmineClient {
|
|
|
230
230
|
}>>;
|
|
231
231
|
deleteIssueCategory(id: number, reassignToId?: number): Promise<RedmineResult<void>>;
|
|
232
232
|
listCustomFields(): Promise<RedmineResult<RedmineCustomFieldsResponse>>;
|
|
233
|
-
listQueries(
|
|
234
|
-
project_id?: string | number;
|
|
235
|
-
}): Promise<RedmineResult<RedmineQueriesResponse>>;
|
|
233
|
+
listQueries(): Promise<RedmineResult<RedmineQueriesResponse>>;
|
|
236
234
|
search(params: {
|
|
237
235
|
q: string;
|
|
238
236
|
scope?: string;
|
package/dist/redmine/client.js
CHANGED
|
@@ -305,10 +305,7 @@ export class RedmineClient {
|
|
|
305
305
|
return this.request("GET", "/custom_fields.json");
|
|
306
306
|
}
|
|
307
307
|
// ==================== QUERIES ====================
|
|
308
|
-
async listQueries(
|
|
309
|
-
if (params?.project_id) {
|
|
310
|
-
return this.request("GET", `/projects/${params.project_id}/queries.json`);
|
|
311
|
-
}
|
|
308
|
+
async listQueries() {
|
|
312
309
|
return this.request("GET", "/queries.json");
|
|
313
310
|
}
|
|
314
311
|
// ==================== SEARCH ====================
|
package/dist/tools/agile.js
CHANGED
|
@@ -5,7 +5,7 @@ export function registerAgileTools(server, client) {
|
|
|
5
5
|
server.registerTool("list_agile_sprints", {
|
|
6
6
|
description: "List all agile sprints for a project (requires redmine_agile plugin)",
|
|
7
7
|
inputSchema: {
|
|
8
|
-
project_id: z.
|
|
8
|
+
project_id: z.string().describe("Project identifier"),
|
|
9
9
|
},
|
|
10
10
|
}, async (params) => {
|
|
11
11
|
const result = await client.listAgileSprints(params.project_id);
|
|
@@ -21,7 +21,7 @@ export function registerAgileTools(server, client) {
|
|
|
21
21
|
server.registerTool("get_agile_sprint", {
|
|
22
22
|
description: "Get details of a specific agile sprint (requires redmine_agile plugin)",
|
|
23
23
|
inputSchema: {
|
|
24
|
-
project_id: z.
|
|
24
|
+
project_id: z.string().describe("Project identifier"),
|
|
25
25
|
sprint_id: z.number().describe("The sprint ID"),
|
|
26
26
|
},
|
|
27
27
|
}, async (params) => {
|
|
@@ -38,7 +38,7 @@ export function registerAgileTools(server, client) {
|
|
|
38
38
|
server.registerTool("create_agile_sprint", {
|
|
39
39
|
description: "Create a new agile sprint for a project (requires redmine_agile plugin)",
|
|
40
40
|
inputSchema: {
|
|
41
|
-
project_id: z.
|
|
41
|
+
project_id: z.string().describe("Project identifier"),
|
|
42
42
|
name: z.string().describe("Sprint name"),
|
|
43
43
|
status: z.string().optional().describe("Sprint status: open, active, closed"),
|
|
44
44
|
start_date: z.string().optional().describe("Start date (YYYY-MM-DD)"),
|
|
@@ -56,7 +56,7 @@ export function registerAgileTools(server, client) {
|
|
|
56
56
|
server.registerTool("update_agile_sprint", {
|
|
57
57
|
description: "Update an existing agile sprint (requires redmine_agile plugin)",
|
|
58
58
|
inputSchema: {
|
|
59
|
-
project_id: z.
|
|
59
|
+
project_id: z.string().describe("Project identifier"),
|
|
60
60
|
sprint_id: z.number().describe("The sprint ID to update"),
|
|
61
61
|
name: z.string().optional().describe("New sprint name"),
|
|
62
62
|
status: z.string().optional().describe("Sprint status: open, active, closed"),
|
|
@@ -75,7 +75,7 @@ export function registerAgileTools(server, client) {
|
|
|
75
75
|
server.registerTool("delete_agile_sprint", {
|
|
76
76
|
description: "Delete an agile sprint (requires redmine_agile plugin)",
|
|
77
77
|
inputSchema: {
|
|
78
|
-
project_id: z.
|
|
78
|
+
project_id: z.string().describe("Project identifier"),
|
|
79
79
|
sprint_id: z.number().describe("The sprint ID to delete"),
|
|
80
80
|
},
|
|
81
81
|
}, async (params) => {
|
package/dist/tools/core.js
CHANGED
|
@@ -5,7 +5,7 @@ export function registerCoreTools(server, client) {
|
|
|
5
5
|
server.registerTool("list_issues", {
|
|
6
6
|
description: "List issues from Redmine with optional filters and sorting",
|
|
7
7
|
inputSchema: {
|
|
8
|
-
project_id: z.
|
|
8
|
+
project_id: z.string().optional().describe("Filter by project identifier"),
|
|
9
9
|
tracker_id: z.number().optional().describe("Filter by tracker ID"),
|
|
10
10
|
status_id: z.union([z.string(), z.number()]).optional().describe("Filter by status: 'open', 'closed', '*', or status ID"),
|
|
11
11
|
assigned_to_id: z.union([z.number(), z.string()]).optional().describe("Filter by assigned user ID or 'me'"),
|
|
@@ -85,7 +85,7 @@ export function registerCoreTools(server, client) {
|
|
|
85
85
|
server.registerTool("create_issue", {
|
|
86
86
|
description: "Create a new issue in Redmine",
|
|
87
87
|
inputSchema: {
|
|
88
|
-
project_id: z.
|
|
88
|
+
project_id: z.string().describe("Project identifier"),
|
|
89
89
|
subject: z.string().describe("Issue subject/title"),
|
|
90
90
|
description: z.string().optional().describe("Issue description (supports Textile/Markdown)"),
|
|
91
91
|
tracker_id: z.number().optional().describe("Tracker ID (e.g., Bug, Feature)"),
|
|
@@ -117,7 +117,7 @@ export function registerCoreTools(server, client) {
|
|
|
117
117
|
issue_id: z.number().describe("The issue ID to update"),
|
|
118
118
|
subject: z.string().optional().describe("New subject/title"),
|
|
119
119
|
description: z.string().optional().describe("New description"),
|
|
120
|
-
project_id: z.
|
|
120
|
+
project_id: z.string().optional().describe("Move to different project"),
|
|
121
121
|
tracker_id: z.number().optional().describe("Change tracker"),
|
|
122
122
|
status_id: z.number().optional().describe("Change status"),
|
|
123
123
|
priority_id: z.number().optional().describe("Change priority"),
|
|
@@ -201,7 +201,7 @@ export function registerCoreTools(server, client) {
|
|
|
201
201
|
server.registerTool("get_project", {
|
|
202
202
|
description: "Get details of a specific project",
|
|
203
203
|
inputSchema: {
|
|
204
|
-
project_id: z.
|
|
204
|
+
project_id: z.string().describe("Project identifier"),
|
|
205
205
|
include: z.string().optional().describe("Include: trackers, issue_categories, enabled_modules, time_entry_activities, issue_custom_fields"),
|
|
206
206
|
},
|
|
207
207
|
}, async (params) => {
|
|
@@ -240,7 +240,7 @@ export function registerCoreTools(server, client) {
|
|
|
240
240
|
server.registerTool("update_project", {
|
|
241
241
|
description: "Update an existing project",
|
|
242
242
|
inputSchema: {
|
|
243
|
-
project_id: z.
|
|
243
|
+
project_id: z.string().describe("Project identifier"),
|
|
244
244
|
name: z.string().optional().describe("New project name"),
|
|
245
245
|
description: z.string().optional().describe("New description"),
|
|
246
246
|
homepage: z.string().optional().describe("New homepage URL"),
|
|
@@ -263,7 +263,7 @@ export function registerCoreTools(server, client) {
|
|
|
263
263
|
server.registerTool("delete_project", {
|
|
264
264
|
description: "Delete a project permanently (requires admin privileges)",
|
|
265
265
|
inputSchema: {
|
|
266
|
-
project_id: z.
|
|
266
|
+
project_id: z.string().describe("Project identifier to delete"),
|
|
267
267
|
},
|
|
268
268
|
}, async (params) => {
|
|
269
269
|
const result = await client.deleteProject(params.project_id);
|
|
@@ -274,7 +274,7 @@ export function registerCoreTools(server, client) {
|
|
|
274
274
|
server.registerTool("archive_project", {
|
|
275
275
|
description: "Archive a project (Redmine 5.0+)",
|
|
276
276
|
inputSchema: {
|
|
277
|
-
project_id: z.
|
|
277
|
+
project_id: z.string().describe("Project identifier to archive"),
|
|
278
278
|
},
|
|
279
279
|
}, async (params) => {
|
|
280
280
|
const result = await client.archiveProject(params.project_id);
|
|
@@ -285,7 +285,7 @@ export function registerCoreTools(server, client) {
|
|
|
285
285
|
server.registerTool("unarchive_project", {
|
|
286
286
|
description: "Unarchive a project (Redmine 5.0+)",
|
|
287
287
|
inputSchema: {
|
|
288
|
-
project_id: z.
|
|
288
|
+
project_id: z.string().describe("Project identifier to unarchive"),
|
|
289
289
|
},
|
|
290
290
|
}, async (params) => {
|
|
291
291
|
const result = await client.unarchiveProject(params.project_id);
|
package/dist/tools/files.js
CHANGED
|
@@ -49,7 +49,7 @@ export function registerFilesTools(server, client) {
|
|
|
49
49
|
server.registerTool("list_project_files", {
|
|
50
50
|
description: "List all files attached to a project",
|
|
51
51
|
inputSchema: {
|
|
52
|
-
project_id: z.
|
|
52
|
+
project_id: z.string().describe("Project identifier"),
|
|
53
53
|
},
|
|
54
54
|
}, async (params) => {
|
|
55
55
|
const result = await client.listProjectFiles(params.project_id);
|
|
@@ -65,7 +65,7 @@ export function registerFilesTools(server, client) {
|
|
|
65
65
|
server.registerTool("upload_project_file", {
|
|
66
66
|
description: "Attach an uploaded file to a project",
|
|
67
67
|
inputSchema: {
|
|
68
|
-
project_id: z.
|
|
68
|
+
project_id: z.string().describe("Project identifier"),
|
|
69
69
|
token: z.string().describe("Upload token from upload_file"),
|
|
70
70
|
version_id: z.number().optional().describe("Associated version ID"),
|
|
71
71
|
filename: z.string().optional().describe("Override filename"),
|
|
@@ -4,7 +4,7 @@ export function registerMembershipsTools(server, client) {
|
|
|
4
4
|
server.registerTool("list_project_memberships", {
|
|
5
5
|
description: "List all memberships (users and groups) for a project",
|
|
6
6
|
inputSchema: {
|
|
7
|
-
project_id: z.
|
|
7
|
+
project_id: z.string().describe("Project identifier"),
|
|
8
8
|
limit: z.number().optional().describe("Maximum results"),
|
|
9
9
|
offset: z.number().optional().describe("Skip first N results"),
|
|
10
10
|
},
|
|
@@ -39,7 +39,7 @@ export function registerMembershipsTools(server, client) {
|
|
|
39
39
|
server.registerTool("create_project_membership", {
|
|
40
40
|
description: "Add a user or group to a project with specified roles",
|
|
41
41
|
inputSchema: {
|
|
42
|
-
project_id: z.
|
|
42
|
+
project_id: z.string().describe("Project identifier"),
|
|
43
43
|
user_id: z.number().describe("User ID or Group ID to add"),
|
|
44
44
|
role_ids: z.array(z.number()).describe("Role IDs to assign (use list_roles to get IDs)"),
|
|
45
45
|
},
|
package/dist/tools/metadata.js
CHANGED
|
@@ -33,7 +33,7 @@ export function registerMetadataTools(server, client) {
|
|
|
33
33
|
server.registerTool("list_issue_categories", {
|
|
34
34
|
description: "List all issue categories for a project",
|
|
35
35
|
inputSchema: {
|
|
36
|
-
project_id: z.
|
|
36
|
+
project_id: z.string().describe("Project identifier"),
|
|
37
37
|
},
|
|
38
38
|
}, async (params) => {
|
|
39
39
|
const result = await client.listIssueCategories(params.project_id);
|
|
@@ -65,7 +65,7 @@ export function registerMetadataTools(server, client) {
|
|
|
65
65
|
server.registerTool("create_issue_category", {
|
|
66
66
|
description: "Create a new issue category in a project",
|
|
67
67
|
inputSchema: {
|
|
68
|
-
project_id: z.
|
|
68
|
+
project_id: z.string().describe("Project identifier"),
|
|
69
69
|
name: z.string().describe("Category name"),
|
|
70
70
|
assigned_to_id: z.number().optional().describe("Default assignee user ID for this category"),
|
|
71
71
|
},
|
|
@@ -120,17 +120,40 @@ export function registerMetadataTools(server, client) {
|
|
|
120
120
|
server.registerTool("list_queries", {
|
|
121
121
|
description: "List all saved issue queries (public and private)",
|
|
122
122
|
inputSchema: {
|
|
123
|
-
project_id: z.
|
|
123
|
+
project_id: z.string().optional().describe("Filter queries by project identifier"),
|
|
124
124
|
},
|
|
125
125
|
}, async (params) => {
|
|
126
|
-
const result = await client.listQueries(
|
|
126
|
+
const result = await client.listQueries();
|
|
127
127
|
if ("error" in result) {
|
|
128
128
|
return {
|
|
129
129
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
+
// Build project lookup for resolving project names
|
|
133
|
+
const projectLookup = {};
|
|
134
|
+
const projectsResult = await client.listProjects({ limit: 100 });
|
|
135
|
+
let filterProjectId;
|
|
136
|
+
if (!("error" in projectsResult)) {
|
|
137
|
+
for (const project of projectsResult.projects) {
|
|
138
|
+
projectLookup[project.id] = project.name;
|
|
139
|
+
// Find the numeric ID for the filter project identifier
|
|
140
|
+
if (params.project_id && project.identifier === params.project_id) {
|
|
141
|
+
filterProjectId = project.id;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Filter queries by project if requested
|
|
146
|
+
let queries = result.queries;
|
|
147
|
+
if (params.project_id) {
|
|
148
|
+
if (filterProjectId === undefined) {
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: "text", text: `Project "${params.project_id}" not found.` }],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
queries = queries.filter(q => q.project_id === filterProjectId);
|
|
154
|
+
}
|
|
132
155
|
return {
|
|
133
|
-
content: [{ type: "text", text: formatQueryList(
|
|
156
|
+
content: [{ type: "text", text: formatQueryList({ queries }, projectLookup) }],
|
|
134
157
|
};
|
|
135
158
|
});
|
|
136
159
|
}
|
package/dist/tools/time.js
CHANGED
|
@@ -4,7 +4,7 @@ export function registerTimeTools(server, client) {
|
|
|
4
4
|
server.registerTool("list_time_entries", {
|
|
5
5
|
description: "List time entries with optional filters",
|
|
6
6
|
inputSchema: {
|
|
7
|
-
project_id: z.
|
|
7
|
+
project_id: z.string().optional().describe("Filter by project identifier"),
|
|
8
8
|
user_id: z.union([z.number(), z.string()]).optional().describe("Filter by user ID or 'me'"),
|
|
9
9
|
spent_on: z.string().optional().describe("Filter by exact date (YYYY-MM-DD)"),
|
|
10
10
|
from: z.string().optional().describe("Filter from date (YYYY-MM-DD)"),
|
|
@@ -43,7 +43,7 @@ export function registerTimeTools(server, client) {
|
|
|
43
43
|
description: "Log time on an issue or project",
|
|
44
44
|
inputSchema: {
|
|
45
45
|
issue_id: z.number().optional().describe("Issue ID to log time on (either issue_id or project_id required)"),
|
|
46
|
-
project_id: z.
|
|
46
|
+
project_id: z.string().optional().describe("Project identifier to log time on (either issue_id or project_id required)"),
|
|
47
47
|
hours: z.number().describe("Number of hours spent"),
|
|
48
48
|
activity_id: z.number().optional().describe("Activity ID (use list_time_entry_activities to get IDs)"),
|
|
49
49
|
spent_on: z.string().optional().describe("Date spent (YYYY-MM-DD, defaults to today)"),
|
package/dist/tools/wiki.js
CHANGED
|
@@ -4,7 +4,7 @@ export function registerWikiTools(server, client) {
|
|
|
4
4
|
server.registerTool("list_wiki_pages", {
|
|
5
5
|
description: "List all wiki pages in a project",
|
|
6
6
|
inputSchema: {
|
|
7
|
-
project_id: z.
|
|
7
|
+
project_id: z.string().describe("Project identifier"),
|
|
8
8
|
},
|
|
9
9
|
}, async (params) => {
|
|
10
10
|
const result = await client.listWikiPages(params.project_id);
|
|
@@ -20,7 +20,7 @@ export function registerWikiTools(server, client) {
|
|
|
20
20
|
server.registerTool("get_wiki_page", {
|
|
21
21
|
description: "Get content of a specific wiki page",
|
|
22
22
|
inputSchema: {
|
|
23
|
-
project_id: z.
|
|
23
|
+
project_id: z.string().describe("Project identifier"),
|
|
24
24
|
page_name: z.string().describe("Wiki page name/title"),
|
|
25
25
|
version: z.number().optional().describe("Specific version number to retrieve"),
|
|
26
26
|
include: z.string().optional().describe("Include: attachments"),
|
|
@@ -42,7 +42,7 @@ export function registerWikiTools(server, client) {
|
|
|
42
42
|
server.registerTool("create_wiki_page", {
|
|
43
43
|
description: "Create a new wiki page in a project",
|
|
44
44
|
inputSchema: {
|
|
45
|
-
project_id: z.
|
|
45
|
+
project_id: z.string().describe("Project identifier"),
|
|
46
46
|
page_name: z.string().describe("Wiki page name/title (used in URL)"),
|
|
47
47
|
text: z.string().describe("Page content (supports Textile/Markdown)"),
|
|
48
48
|
comments: z.string().optional().describe("Edit comment for version history"),
|
|
@@ -58,7 +58,7 @@ export function registerWikiTools(server, client) {
|
|
|
58
58
|
server.registerTool("update_wiki_page", {
|
|
59
59
|
description: "Update an existing wiki page",
|
|
60
60
|
inputSchema: {
|
|
61
|
-
project_id: z.
|
|
61
|
+
project_id: z.string().describe("Project identifier"),
|
|
62
62
|
page_name: z.string().describe("Wiki page name/title"),
|
|
63
63
|
text: z.string().describe("New page content"),
|
|
64
64
|
comments: z.string().optional().describe("Edit comment for version history"),
|
|
@@ -74,7 +74,7 @@ export function registerWikiTools(server, client) {
|
|
|
74
74
|
server.registerTool("delete_wiki_page", {
|
|
75
75
|
description: "Delete a wiki page and all its history",
|
|
76
76
|
inputSchema: {
|
|
77
|
-
project_id: z.
|
|
77
|
+
project_id: z.string().describe("Project identifier"),
|
|
78
78
|
page_name: z.string().describe("Wiki page name/title to delete"),
|
|
79
79
|
},
|
|
80
80
|
}, async (params) => {
|