@pschroee/redmine-mcp 0.3.3 → 0.4.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/README.md CHANGED
@@ -44,7 +44,18 @@ npx @pschroee/redmine-mcp@latest --url=https://your-redmine.com --api-key=your-a
44
44
  | `roles` | 2 | Roles listing and details |
45
45
  | `admin` | 11 | Users & Groups management (admin only) |
46
46
 
47
- **Total: 70 Tools**
47
+ **Total: 70 Core Tools**
48
+
49
+ ### Plugin Groups (enabled by default, require RedmineUP plugins)
50
+
51
+ | Group | Tools | Description |
52
+ |-------|-------|-------------|
53
+ | `plugin_checklists` | 5 | Checklist items (requires [redmine_checklists](https://www.redmineup.com/pages/plugins/checklists) plugin) |
54
+ | `plugin_agile` | 7 | Agile sprints & story points (requires [redmine_agile](https://www.redmineup.com/pages/plugins/agile) plugin) |
55
+
56
+ **Total: 12 Plugin Tools**
57
+
58
+ > **Note:** Plugin tools are enabled by default but require the corresponding RedmineUP plugins to be installed on your Redmine server. If a plugin is not installed, the tools will return errors when used. Use `--exclude=plugin_checklists,plugin_agile` to disable them.
48
59
 
49
60
  ## Usage Examples
50
61
 
@@ -66,6 +77,12 @@ npx @pschroee/redmine-mcp@latest --tools=core,metadata
66
77
  npx @pschroee/redmine-mcp@latest --exclude=wiki,files
67
78
  ```
68
79
 
80
+ ### Exclude plugin tools (if plugins not installed)
81
+
82
+ ```bash
83
+ npx @pschroee/redmine-mcp@latest --exclude=plugin_checklists,plugin_agile
84
+ ```
85
+
69
86
  ## Claude Configuration
70
87
 
71
88
  ### Quick Setup with Claude CLI
@@ -102,6 +119,24 @@ claude mcp add redmine -s user -- cmd /c npx -y @pschroee/redmine-mcp \
102
119
  --tools=core,metadata,search
103
120
  ```
104
121
 
122
+ ### Without Plugin Tools
123
+
124
+ **macOS / Linux:**
125
+
126
+ ```bash
127
+ claude mcp add redmine -s user -- npx -y @pschroee/redmine-mcp@latest \
128
+ --url=https://your-redmine.com --api-key=your-api-key \
129
+ --exclude=plugin_checklists,plugin_agile
130
+ ```
131
+
132
+ **Windows:**
133
+
134
+ ```bash
135
+ claude mcp add redmine -s user -- cmd /c npx -y @pschroee/redmine-mcp@latest \
136
+ --url=https://your-redmine.com --api-key=your-api-key \
137
+ --exclude=plugin_checklists,plugin_agile
138
+ ```
139
+
105
140
  ### Manual Configuration (Claude Desktop)
106
141
 
107
142
  #### macOS / Linux
@@ -292,6 +327,28 @@ Add to your Claude Desktop config (`%APPDATA%\Claude\claude_desktop_config.json`
292
327
  - `add_user_to_group` - Add user to group
293
328
  - `remove_user_from_group` - Remove user from group
294
329
 
330
+ ### Plugin: Checklists (plugin_checklists)
331
+
332
+ > Requires [redmine_checklists](https://www.redmineup.com/pages/plugins/checklists) plugin
333
+
334
+ - `list_checklists` - List checklist items for an issue
335
+ - `get_checklist` - Get checklist item details
336
+ - `create_checklist` - Create checklist item
337
+ - `update_checklist` - Update checklist item (text, done status)
338
+ - `delete_checklist` - Delete checklist item
339
+
340
+ ### Plugin: Agile (plugin_agile)
341
+
342
+ > Requires [redmine_agile](https://www.redmineup.com/pages/plugins/agile) plugin
343
+
344
+ - `list_agile_sprints` - List sprints for a project
345
+ - `get_agile_sprint` - Get sprint details
346
+ - `create_agile_sprint` - Create sprint
347
+ - `update_agile_sprint` - Update sprint
348
+ - `delete_agile_sprint` - Delete sprint
349
+ - `get_issue_agile_data` - Get agile data for issue (position, story points, sprint)
350
+ - `update_issue_agile_data` - Update agile data for issue
351
+
295
352
  ## Development
296
353
 
297
354
  ```bash
@@ -329,12 +386,12 @@ npm test
329
386
 
330
387
  ### Test Coverage
331
388
 
332
- The test suite includes 195 tests across 12 test files:
389
+ The test suite includes 198 tests across 12 test files:
333
390
 
334
391
  | Test File | Tests | Description |
335
392
  |-----------|-------|-------------|
336
393
  | `account.test.ts` | 1 | Current user account |
337
- | `core.test.ts` | 48 | Projects and Issues CRUD |
394
+ | `core.test.ts` | 51 | Projects and Issues CRUD |
338
395
  | `metadata.test.ts` | 14 | Trackers, Statuses, Categories |
339
396
  | `relations.test.ts` | 24 | Versions and Issue Relations |
340
397
  | `wiki.test.ts` | 14 | Wiki Pages CRUD |
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  import { RedmineClient } from "./redmine/client.js";
4
4
  import { createServer } from "./server.js";
5
- import { resolveGroups, ALL_GROUPS } from "./tools/index.js";
5
+ import { resolveGroups, ALL_GROUPS, PLUGIN_GROUPS } from "./tools/index.js";
6
6
  function printHelp() {
7
7
  console.log(`
8
8
  Redmine MCP Server
@@ -16,13 +16,15 @@ Options:
16
16
  --exclude=<groups> Comma-separated list of tool groups to exclude
17
17
  --help Show this help message
18
18
 
19
- Tool Groups:
19
+ Tool Groups (all enabled by default):
20
20
  ${ALL_GROUPS.join(", ")}
21
21
 
22
+ Note: Plugin groups (${PLUGIN_GROUPS.join(", ")}) require RedmineUP plugins installed.
23
+
22
24
  Examples:
23
25
  redmine-mcp --url=https://redmine.example.com --api-key=abc123
24
26
  redmine-mcp --tools=core,metadata
25
- redmine-mcp --exclude=wiki,files
27
+ redmine-mcp --exclude=wiki,files,plugin_checklists,plugin_agile
26
28
  `);
27
29
  }
28
30
  function parseArgs() {
@@ -1,4 +1,4 @@
1
- import type { RedmineIssue, RedmineIssuesResponse, RedmineProject, RedmineProjectsResponse, RedmineResult, RedmineWikiPage, RedmineWikiPagesResponse, RedmineAttachment, RedmineUploadResponse, RedmineFilesResponse, RedmineRelation, RedmineRelationsResponse, RedmineVersion, RedmineVersionsResponse, RedmineTrackersResponse, RedmineIssueStatusesResponse, RedmineCategory, RedmineCategoriesResponse, RedmineCustomFieldsResponse, RedmineQueriesResponse, RedmineSearchResponse, RedmineMyAccountResponse, RedmineTimeEntry, RedmineTimeEntriesResponse, RedmineIssuePrioritiesResponse, RedmineTimeEntryActivitiesResponse, RedmineDocumentCategoriesResponse, RedmineUser, RedmineUsersResponse, RedmineGroup, RedmineGroupsResponse, RedmineMembership, RedmineMembershipsResponse, RedmineRole, RedmineRolesResponse } from "./types.js";
1
+ import type { RedmineIssue, RedmineIssuesResponse, RedmineProject, RedmineProjectsResponse, RedmineResult, RedmineWikiPage, RedmineWikiPagesResponse, RedmineAttachment, RedmineUploadResponse, RedmineFilesResponse, RedmineRelation, RedmineRelationsResponse, RedmineVersion, RedmineVersionsResponse, RedmineTrackersResponse, RedmineIssueStatusesResponse, RedmineCategory, RedmineCategoriesResponse, RedmineCustomFieldsResponse, RedmineQueriesResponse, RedmineSearchResponse, RedmineMyAccountResponse, RedmineTimeEntry, RedmineTimeEntriesResponse, RedmineIssuePrioritiesResponse, RedmineTimeEntryActivitiesResponse, RedmineDocumentCategoriesResponse, RedmineUser, RedmineUsersResponse, RedmineGroup, RedmineGroupsResponse, RedmineMembership, RedmineMembershipsResponse, RedmineRole, RedmineRolesResponse, RedmineChecklist, RedmineChecklistsResponse, RedmineAgileSprint, RedmineAgileSprintsResponse, RedmineAgileData } from "./types.js";
2
2
  export declare class RedmineClient {
3
3
  private baseUrl;
4
4
  private apiKey;
@@ -347,4 +347,53 @@ export declare class RedmineClient {
347
347
  getRole(id: number): Promise<RedmineResult<{
348
348
  role: RedmineRole;
349
349
  }>>;
350
+ listChecklists(issueId: number): Promise<RedmineResult<RedmineChecklistsResponse>>;
351
+ getChecklist(id: number): Promise<RedmineResult<{
352
+ checklist: RedmineChecklist;
353
+ }>>;
354
+ createChecklist(data: {
355
+ issue_id: number;
356
+ subject: string;
357
+ is_done?: boolean;
358
+ position?: number;
359
+ }): Promise<RedmineResult<{
360
+ checklist: RedmineChecklist;
361
+ }>>;
362
+ updateChecklist(id: number, data: {
363
+ subject?: string;
364
+ is_done?: boolean;
365
+ position?: number;
366
+ }): Promise<RedmineResult<void>>;
367
+ deleteChecklist(id: number): Promise<RedmineResult<void>>;
368
+ listAgileSprints(projectId: string | number): Promise<RedmineResult<RedmineAgileSprintsResponse>>;
369
+ getAgileSprint(projectId: string | number, sprintId: number): Promise<RedmineResult<{
370
+ agile_sprint: RedmineAgileSprint;
371
+ }>>;
372
+ createAgileSprint(projectId: string | number, data: {
373
+ name: string;
374
+ status?: string;
375
+ start_date?: string;
376
+ end_date?: string;
377
+ description?: string;
378
+ sharing?: string;
379
+ }): Promise<RedmineResult<{
380
+ agile_sprint: RedmineAgileSprint;
381
+ }>>;
382
+ updateAgileSprint(projectId: string | number, sprintId: number, data: {
383
+ name?: string;
384
+ status?: string;
385
+ start_date?: string;
386
+ end_date?: string;
387
+ description?: string;
388
+ sharing?: string;
389
+ }): Promise<RedmineResult<void>>;
390
+ deleteAgileSprint(projectId: string | number, sprintId: number): Promise<RedmineResult<void>>;
391
+ getIssueAgileData(issueId: number): Promise<RedmineResult<{
392
+ agile_data: RedmineAgileData;
393
+ }>>;
394
+ updateIssueAgileData(issueId: number, data: {
395
+ position?: number;
396
+ story_points?: number;
397
+ agile_sprint_id?: number | null;
398
+ }): Promise<RedmineResult<void>>;
350
399
  }
@@ -477,4 +477,50 @@ export class RedmineClient {
477
477
  async getRole(id) {
478
478
  return this.request("GET", `/roles/${id}.json`);
479
479
  }
480
+ // ==================== CHECKLISTS (Plugin) ====================
481
+ async listChecklists(issueId) {
482
+ return this.request("GET", `/issues/${issueId}/checklists.json`);
483
+ }
484
+ async getChecklist(id) {
485
+ return this.request("GET", `/checklists/${id}.json`);
486
+ }
487
+ async createChecklist(data) {
488
+ return this.request("POST", "/checklists.json", {
489
+ checklist: data,
490
+ });
491
+ }
492
+ async updateChecklist(id, data) {
493
+ return this.request("PUT", `/checklists/${id}.json`, {
494
+ checklist: data,
495
+ });
496
+ }
497
+ async deleteChecklist(id) {
498
+ return this.request("DELETE", `/checklists/${id}.json`);
499
+ }
500
+ // ==================== AGILE (Plugin) ====================
501
+ async listAgileSprints(projectId) {
502
+ return this.request("GET", `/projects/${projectId}/agile_sprints.json`);
503
+ }
504
+ async getAgileSprint(projectId, sprintId) {
505
+ return this.request("GET", `/projects/${projectId}/agile_sprints/${sprintId}.json`);
506
+ }
507
+ async createAgileSprint(projectId, data) {
508
+ return this.request("POST", `/projects/${projectId}/agile_sprints.json`, { agile_sprint: data });
509
+ }
510
+ async updateAgileSprint(projectId, sprintId, data) {
511
+ return this.request("PUT", `/projects/${projectId}/agile_sprints/${sprintId}.json`, { agile_sprint: data });
512
+ }
513
+ async deleteAgileSprint(projectId, sprintId) {
514
+ return this.request("DELETE", `/projects/${projectId}/agile_sprints/${sprintId}.json`);
515
+ }
516
+ async getIssueAgileData(issueId) {
517
+ return this.request("GET", `/issues/${issueId}/agile_data.json`);
518
+ }
519
+ async updateIssueAgileData(issueId, data) {
520
+ return this.request("PUT", `/issues/${issueId}.json`, {
521
+ issue: {
522
+ agile_data_attributes: data,
523
+ },
524
+ });
525
+ }
480
526
  }
@@ -487,3 +487,40 @@ export interface RedmineRole {
487
487
  export interface RedmineRolesResponse {
488
488
  roles: RedmineRole[];
489
489
  }
490
+ export interface RedmineChecklist {
491
+ id: number;
492
+ issue_id: number;
493
+ subject: string;
494
+ is_done: boolean;
495
+ position: number;
496
+ created_at: string;
497
+ updated_at: string;
498
+ }
499
+ export interface RedmineChecklistsResponse {
500
+ checklists: RedmineChecklist[];
501
+ }
502
+ export interface RedmineAgileSprint {
503
+ id: number;
504
+ name: string;
505
+ status: string;
506
+ start_date?: string;
507
+ end_date?: string;
508
+ description?: string;
509
+ sharing?: string;
510
+ is_active?: boolean;
511
+ created_at?: string;
512
+ updated_at?: string;
513
+ }
514
+ export interface RedmineAgileSprintsResponse {
515
+ agile_sprints: RedmineAgileSprint[];
516
+ }
517
+ export interface RedmineAgileData {
518
+ id: number;
519
+ issue_id: number;
520
+ position: number;
521
+ story_points?: number;
522
+ agile_sprint_id?: number;
523
+ }
524
+ export interface RedmineAgileDataResponse {
525
+ agile_data: RedmineAgileData;
526
+ }
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@ import { registerTools } from "./tools/index.js";
3
3
  export function createServer(redmineClient, toolGroups) {
4
4
  const server = new McpServer({
5
5
  name: "redmine-mcp",
6
- version: "0.3.3",
6
+ version: "0.4.0",
7
7
  });
8
8
  registerTools(server, redmineClient, toolGroups);
9
9
  return server;
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { RedmineClient } from "../redmine/client.js";
3
+ export declare function registerAgileTools(server: McpServer, client: RedmineClient): void;
@@ -0,0 +1,103 @@
1
+ import { z } from "zod";
2
+ export function registerAgileTools(server, client) {
3
+ // === SPRINTS ===
4
+ server.registerTool("list_agile_sprints", {
5
+ description: "List all agile sprints for a project (requires redmine_agile plugin)",
6
+ inputSchema: {
7
+ project_id: z.union([z.string(), z.number()]).describe("Project ID or identifier"),
8
+ },
9
+ }, async (params) => {
10
+ const result = await client.listAgileSprints(params.project_id);
11
+ return {
12
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
13
+ };
14
+ });
15
+ server.registerTool("get_agile_sprint", {
16
+ description: "Get details of a specific agile sprint (requires redmine_agile plugin)",
17
+ inputSchema: {
18
+ project_id: z.union([z.string(), z.number()]).describe("Project ID or identifier"),
19
+ sprint_id: z.number().describe("The sprint ID"),
20
+ },
21
+ }, async (params) => {
22
+ const result = await client.getAgileSprint(params.project_id, params.sprint_id);
23
+ return {
24
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
25
+ };
26
+ });
27
+ server.registerTool("create_agile_sprint", {
28
+ description: "Create a new agile sprint for a project (requires redmine_agile plugin)",
29
+ inputSchema: {
30
+ project_id: z.union([z.string(), z.number()]).describe("Project ID or identifier"),
31
+ name: z.string().describe("Sprint name"),
32
+ status: z.string().optional().describe("Sprint status: open, active, closed"),
33
+ start_date: z.string().optional().describe("Start date (YYYY-MM-DD)"),
34
+ end_date: z.string().optional().describe("End date (YYYY-MM-DD)"),
35
+ description: z.string().optional().describe("Sprint description"),
36
+ sharing: z.string().optional().describe("Sharing level"),
37
+ },
38
+ }, async (params) => {
39
+ const { project_id, ...data } = params;
40
+ const result = await client.createAgileSprint(project_id, data);
41
+ return {
42
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
43
+ };
44
+ });
45
+ server.registerTool("update_agile_sprint", {
46
+ description: "Update an existing agile sprint (requires redmine_agile plugin)",
47
+ inputSchema: {
48
+ project_id: z.union([z.string(), z.number()]).describe("Project ID or identifier"),
49
+ sprint_id: z.number().describe("The sprint ID to update"),
50
+ name: z.string().optional().describe("New sprint name"),
51
+ status: z.string().optional().describe("Sprint status: open, active, closed"),
52
+ start_date: z.string().optional().describe("Start date (YYYY-MM-DD)"),
53
+ end_date: z.string().optional().describe("End date (YYYY-MM-DD)"),
54
+ description: z.string().optional().describe("Sprint description"),
55
+ sharing: z.string().optional().describe("Sharing level"),
56
+ },
57
+ }, async (params) => {
58
+ const { project_id, sprint_id, ...data } = params;
59
+ const result = await client.updateAgileSprint(project_id, sprint_id, data);
60
+ return {
61
+ content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
62
+ };
63
+ });
64
+ server.registerTool("delete_agile_sprint", {
65
+ description: "Delete an agile sprint (requires redmine_agile plugin)",
66
+ inputSchema: {
67
+ project_id: z.union([z.string(), z.number()]).describe("Project ID or identifier"),
68
+ sprint_id: z.number().describe("The sprint ID to delete"),
69
+ },
70
+ }, async (params) => {
71
+ const result = await client.deleteAgileSprint(params.project_id, params.sprint_id);
72
+ return {
73
+ content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
74
+ };
75
+ });
76
+ // === AGILE DATA (Issue attributes) ===
77
+ server.registerTool("get_issue_agile_data", {
78
+ description: "Get agile data for an issue (position, story points, sprint) (requires redmine_agile plugin)",
79
+ inputSchema: {
80
+ issue_id: z.number().describe("The issue ID"),
81
+ },
82
+ }, async (params) => {
83
+ const result = await client.getIssueAgileData(params.issue_id);
84
+ return {
85
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
86
+ };
87
+ });
88
+ server.registerTool("update_issue_agile_data", {
89
+ description: "Update agile data for an issue (position, story points, sprint assignment) (requires redmine_agile plugin)",
90
+ inputSchema: {
91
+ issue_id: z.number().describe("The issue ID"),
92
+ position: z.number().optional().describe("Position on the agile board"),
93
+ story_points: z.number().optional().describe("Story points for the issue"),
94
+ agile_sprint_id: z.number().nullable().optional().describe("Sprint ID to assign (null to unassign)"),
95
+ },
96
+ }, async (params) => {
97
+ const { issue_id, ...data } = params;
98
+ const result = await client.updateIssueAgileData(issue_id, data);
99
+ return {
100
+ content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
101
+ };
102
+ });
103
+ }
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { RedmineClient } from "../redmine/client.js";
3
+ export declare function registerChecklistsTools(server: McpServer, client: RedmineClient): void;
@@ -0,0 +1,65 @@
1
+ import { z } from "zod";
2
+ export function registerChecklistsTools(server, client) {
3
+ server.registerTool("list_checklists", {
4
+ description: "List all checklist items for an issue (requires redmine_checklists plugin)",
5
+ inputSchema: {
6
+ issue_id: z.number().describe("The issue ID to get checklists for"),
7
+ },
8
+ }, async (params) => {
9
+ const result = await client.listChecklists(params.issue_id);
10
+ return {
11
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
12
+ };
13
+ });
14
+ server.registerTool("get_checklist", {
15
+ description: "Get a specific checklist item by ID (requires redmine_checklists plugin)",
16
+ inputSchema: {
17
+ checklist_id: z.number().describe("The checklist item ID"),
18
+ },
19
+ }, async (params) => {
20
+ const result = await client.getChecklist(params.checklist_id);
21
+ return {
22
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
23
+ };
24
+ });
25
+ server.registerTool("create_checklist", {
26
+ description: "Create a new checklist item for an issue (requires redmine_checklists plugin)",
27
+ inputSchema: {
28
+ issue_id: z.number().describe("The issue ID to add the checklist item to"),
29
+ subject: z.string().describe("The checklist item text"),
30
+ is_done: z.boolean().optional().describe("Whether the item is completed (default: false)"),
31
+ position: z.number().optional().describe("Position in the checklist (1-based)"),
32
+ },
33
+ }, async (params) => {
34
+ const result = await client.createChecklist(params);
35
+ return {
36
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
37
+ };
38
+ });
39
+ server.registerTool("update_checklist", {
40
+ description: "Update an existing checklist item (requires redmine_checklists plugin)",
41
+ inputSchema: {
42
+ checklist_id: z.number().describe("The checklist item ID to update"),
43
+ subject: z.string().optional().describe("New text for the checklist item"),
44
+ is_done: z.boolean().optional().describe("Mark as done/undone"),
45
+ position: z.number().optional().describe("New position in the checklist"),
46
+ },
47
+ }, async (params) => {
48
+ const { checklist_id, ...data } = params;
49
+ const result = await client.updateChecklist(checklist_id, data);
50
+ return {
51
+ content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
52
+ };
53
+ });
54
+ server.registerTool("delete_checklist", {
55
+ description: "Delete a checklist item (requires redmine_checklists plugin)",
56
+ inputSchema: {
57
+ checklist_id: z.number().describe("The checklist item ID to delete"),
58
+ },
59
+ }, async (params) => {
60
+ const result = await client.deleteChecklist(params.checklist_id);
61
+ return {
62
+ content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
63
+ };
64
+ });
65
+ }
@@ -1,9 +1,12 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { RedmineClient } from "../redmine/client.js";
3
3
  export type ToolRegistrationFn = (server: McpServer, client: RedmineClient) => void;
4
+ export declare const coreToolGroups: Record<string, ToolRegistrationFn>;
5
+ export declare const pluginToolGroups: Record<string, ToolRegistrationFn>;
4
6
  export declare const toolGroups: Record<string, ToolRegistrationFn>;
5
7
  export type ToolGroup = keyof typeof toolGroups;
6
8
  export declare const ALL_GROUPS: ToolGroup[];
9
+ export declare const PLUGIN_GROUPS: ToolGroup[];
7
10
  export declare function isValidToolGroup(group: string): group is ToolGroup;
8
11
  export declare function validateToolGroups(groups: string[]): ToolGroup[];
9
12
  export declare function resolveGroups(include?: string[], exclude?: string[]): ToolGroup[];
@@ -1,5 +1,7 @@
1
1
  import { registerAccountTools } from "./account.js";
2
2
  import { registerAdminTools } from "./admin.js";
3
+ import { registerAgileTools } from "./agile.js";
4
+ import { registerChecklistsTools } from "./checklists.js";
3
5
  import { registerCoreTools } from "./core.js";
4
6
  import { registerEnumerationsTools } from "./enumerations.js";
5
7
  import { registerFilesTools } from "./files.js";
@@ -10,7 +12,8 @@ import { registerRolesTools } from "./roles.js";
10
12
  import { registerSearchTools } from "./search.js";
11
13
  import { registerTimeTools } from "./time.js";
12
14
  import { registerWikiTools } from "./wiki.js";
13
- export const toolGroups = {
15
+ // Core tool groups
16
+ export const coreToolGroups = {
14
17
  core: registerCoreTools,
15
18
  metadata: registerMetadataTools,
16
19
  wiki: registerWikiTools,
@@ -24,7 +27,20 @@ export const toolGroups = {
24
27
  roles: registerRolesTools,
25
28
  admin: registerAdminTools,
26
29
  };
30
+ // Plugin tool groups (require RedmineUP plugins to be installed)
31
+ export const pluginToolGroups = {
32
+ plugin_checklists: registerChecklistsTools,
33
+ plugin_agile: registerAgileTools,
34
+ };
35
+ // All tool groups combined
36
+ export const toolGroups = {
37
+ ...coreToolGroups,
38
+ ...pluginToolGroups,
39
+ };
40
+ // All groups including plugins are enabled by default
27
41
  export const ALL_GROUPS = Object.keys(toolGroups);
42
+ // Plugin groups (for documentation purposes)
43
+ export const PLUGIN_GROUPS = Object.keys(pluginToolGroups);
28
44
  export function isValidToolGroup(group) {
29
45
  return group in toolGroups;
30
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pschroee/redmine-mcp",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server for Redmine - full API access with configurable tool groups",
5
5
  "type": "module",
6
6
  "bin": {