@pschroee/redmine-mcp 0.3.1
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 +360 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +99 -0
- package/dist/redmine/client.d.ts +349 -0
- package/dist/redmine/client.js +458 -0
- package/dist/redmine/types.d.ts +489 -0
- package/dist/redmine/types.js +2 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +10 -0
- package/dist/tools/account.d.ts +3 -0
- package/dist/tools/account.js +10 -0
- package/dist/tools/admin.d.ts +3 -0
- package/dist/tools/admin.js +150 -0
- package/dist/tools/core.d.ts +3 -0
- package/dist/tools/core.js +242 -0
- package/dist/tools/enumerations.d.ts +3 -0
- package/dist/tools/enumerations.js +26 -0
- package/dist/tools/files.d.ts +3 -0
- package/dist/tools/files.js +70 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +59 -0
- package/dist/tools/issues.d.ts +3 -0
- package/dist/tools/issues.js +61 -0
- package/dist/tools/memberships.d.ts +3 -0
- package/dist/tools/memberships.js +66 -0
- package/dist/tools/metadata.d.ts +3 -0
- package/dist/tools/metadata.js +102 -0
- package/dist/tools/projects.d.ts +3 -0
- package/dist/tools/projects.js +49 -0
- package/dist/tools/relations.d.ts +3 -0
- package/dist/tools/relations.js +157 -0
- package/dist/tools/roles.d.ts +3 -0
- package/dist/tools/roles.js +22 -0
- package/dist/tools/search.d.ts +3 -0
- package/dist/tools/search.js +28 -0
- package/dist/tools/time.d.ts +3 -0
- package/dist/tools/time.js +75 -0
- package/dist/tools/wiki.d.ts +3 -0
- package/dist/tools/wiki.js +75 -0
- package/package.json +55 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
export interface RedmineError {
|
|
2
|
+
error: true;
|
|
3
|
+
status: number;
|
|
4
|
+
message: string;
|
|
5
|
+
}
|
|
6
|
+
export type RedmineResult<T> = T | RedmineError;
|
|
7
|
+
export interface RedmineCustomFieldValue {
|
|
8
|
+
id: number;
|
|
9
|
+
name: string;
|
|
10
|
+
value: string | string[];
|
|
11
|
+
multiple?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface RedmineCustomField {
|
|
14
|
+
id: number;
|
|
15
|
+
name: string;
|
|
16
|
+
customized_type: string;
|
|
17
|
+
field_format: string;
|
|
18
|
+
regexp?: string;
|
|
19
|
+
min_length?: number;
|
|
20
|
+
max_length?: number;
|
|
21
|
+
is_required: boolean;
|
|
22
|
+
is_filter: boolean;
|
|
23
|
+
searchable: boolean;
|
|
24
|
+
multiple: boolean;
|
|
25
|
+
default_value?: string;
|
|
26
|
+
visible: boolean;
|
|
27
|
+
possible_values?: {
|
|
28
|
+
value: string;
|
|
29
|
+
label?: string;
|
|
30
|
+
}[];
|
|
31
|
+
trackers?: {
|
|
32
|
+
id: number;
|
|
33
|
+
name: string;
|
|
34
|
+
}[];
|
|
35
|
+
roles?: {
|
|
36
|
+
id: number;
|
|
37
|
+
name: string;
|
|
38
|
+
}[];
|
|
39
|
+
}
|
|
40
|
+
export interface RedmineCustomFieldsResponse {
|
|
41
|
+
custom_fields: RedmineCustomField[];
|
|
42
|
+
}
|
|
43
|
+
export interface RedmineTracker {
|
|
44
|
+
id: number;
|
|
45
|
+
name: string;
|
|
46
|
+
default_status?: {
|
|
47
|
+
id: number;
|
|
48
|
+
name: string;
|
|
49
|
+
};
|
|
50
|
+
description?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface RedmineTrackersResponse {
|
|
53
|
+
trackers: RedmineTracker[];
|
|
54
|
+
}
|
|
55
|
+
export interface RedmineIssueStatus {
|
|
56
|
+
id: number;
|
|
57
|
+
name: string;
|
|
58
|
+
is_closed: boolean;
|
|
59
|
+
}
|
|
60
|
+
export interface RedmineIssueStatusesResponse {
|
|
61
|
+
issue_statuses: RedmineIssueStatus[];
|
|
62
|
+
}
|
|
63
|
+
export interface RedmineCategory {
|
|
64
|
+
id: number;
|
|
65
|
+
project?: {
|
|
66
|
+
id: number;
|
|
67
|
+
name: string;
|
|
68
|
+
};
|
|
69
|
+
name: string;
|
|
70
|
+
assigned_to?: {
|
|
71
|
+
id: number;
|
|
72
|
+
name: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export interface RedmineCategoriesResponse {
|
|
76
|
+
issue_categories: RedmineCategory[];
|
|
77
|
+
}
|
|
78
|
+
export interface RedmineActivity {
|
|
79
|
+
id: number;
|
|
80
|
+
name: string;
|
|
81
|
+
is_default: boolean;
|
|
82
|
+
active: boolean;
|
|
83
|
+
}
|
|
84
|
+
export interface RedmineQuery {
|
|
85
|
+
id: number;
|
|
86
|
+
name: string;
|
|
87
|
+
is_public: boolean;
|
|
88
|
+
project_id?: number;
|
|
89
|
+
}
|
|
90
|
+
export interface RedmineQueriesResponse {
|
|
91
|
+
queries: RedmineQuery[];
|
|
92
|
+
}
|
|
93
|
+
export interface RedmineAttachment {
|
|
94
|
+
id: number;
|
|
95
|
+
filename: string;
|
|
96
|
+
filesize: number;
|
|
97
|
+
content_type: string;
|
|
98
|
+
description?: string;
|
|
99
|
+
content_url: string;
|
|
100
|
+
thumbnail_url?: string;
|
|
101
|
+
author: {
|
|
102
|
+
id: number;
|
|
103
|
+
name: string;
|
|
104
|
+
};
|
|
105
|
+
created_on: string;
|
|
106
|
+
}
|
|
107
|
+
export interface RedmineUploadResponse {
|
|
108
|
+
upload: {
|
|
109
|
+
token: string;
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export interface RedmineFile {
|
|
113
|
+
id: number;
|
|
114
|
+
filename: string;
|
|
115
|
+
filesize: number;
|
|
116
|
+
content_type: string;
|
|
117
|
+
description?: string;
|
|
118
|
+
content_url: string;
|
|
119
|
+
author: {
|
|
120
|
+
id: number;
|
|
121
|
+
name: string;
|
|
122
|
+
};
|
|
123
|
+
created_on: string;
|
|
124
|
+
version?: {
|
|
125
|
+
id: number;
|
|
126
|
+
name: string;
|
|
127
|
+
};
|
|
128
|
+
digest: string;
|
|
129
|
+
downloads: number;
|
|
130
|
+
}
|
|
131
|
+
export interface RedmineFilesResponse {
|
|
132
|
+
files: RedmineFile[];
|
|
133
|
+
}
|
|
134
|
+
export interface RedmineJournalDetail {
|
|
135
|
+
property: string;
|
|
136
|
+
name: string;
|
|
137
|
+
old_value?: string;
|
|
138
|
+
new_value?: string;
|
|
139
|
+
}
|
|
140
|
+
export interface RedmineJournal {
|
|
141
|
+
id: number;
|
|
142
|
+
user: {
|
|
143
|
+
id: number;
|
|
144
|
+
name: string;
|
|
145
|
+
};
|
|
146
|
+
notes?: string;
|
|
147
|
+
private_notes: boolean;
|
|
148
|
+
created_on: string;
|
|
149
|
+
details: RedmineJournalDetail[];
|
|
150
|
+
}
|
|
151
|
+
export interface RedmineChangeset {
|
|
152
|
+
revision: string;
|
|
153
|
+
user?: {
|
|
154
|
+
id: number;
|
|
155
|
+
name: string;
|
|
156
|
+
};
|
|
157
|
+
comments?: string;
|
|
158
|
+
committed_on: string;
|
|
159
|
+
}
|
|
160
|
+
export interface RedmineRelation {
|
|
161
|
+
id: number;
|
|
162
|
+
issue_id: number;
|
|
163
|
+
issue_to_id: number;
|
|
164
|
+
relation_type: string;
|
|
165
|
+
delay?: number;
|
|
166
|
+
}
|
|
167
|
+
export interface RedmineRelationsResponse {
|
|
168
|
+
relations: RedmineRelation[];
|
|
169
|
+
}
|
|
170
|
+
export interface RedmineVersion {
|
|
171
|
+
id: number;
|
|
172
|
+
project: {
|
|
173
|
+
id: number;
|
|
174
|
+
name: string;
|
|
175
|
+
};
|
|
176
|
+
name: string;
|
|
177
|
+
description?: string;
|
|
178
|
+
status: string;
|
|
179
|
+
sharing: string;
|
|
180
|
+
due_date?: string;
|
|
181
|
+
wiki_page_title?: string;
|
|
182
|
+
estimated_hours?: number;
|
|
183
|
+
spent_hours?: number;
|
|
184
|
+
created_on: string;
|
|
185
|
+
updated_on: string;
|
|
186
|
+
}
|
|
187
|
+
export interface RedmineVersionsResponse {
|
|
188
|
+
versions: RedmineVersion[];
|
|
189
|
+
total_count: number;
|
|
190
|
+
}
|
|
191
|
+
export interface RedmineIssue {
|
|
192
|
+
id: number;
|
|
193
|
+
project: {
|
|
194
|
+
id: number;
|
|
195
|
+
name: string;
|
|
196
|
+
};
|
|
197
|
+
tracker?: {
|
|
198
|
+
id: number;
|
|
199
|
+
name: string;
|
|
200
|
+
};
|
|
201
|
+
status: {
|
|
202
|
+
id: number;
|
|
203
|
+
name: string;
|
|
204
|
+
is_closed?: boolean;
|
|
205
|
+
};
|
|
206
|
+
priority: {
|
|
207
|
+
id: number;
|
|
208
|
+
name: string;
|
|
209
|
+
};
|
|
210
|
+
author: {
|
|
211
|
+
id: number;
|
|
212
|
+
name: string;
|
|
213
|
+
};
|
|
214
|
+
assigned_to?: {
|
|
215
|
+
id: number;
|
|
216
|
+
name: string;
|
|
217
|
+
};
|
|
218
|
+
category?: {
|
|
219
|
+
id: number;
|
|
220
|
+
name: string;
|
|
221
|
+
};
|
|
222
|
+
fixed_version?: {
|
|
223
|
+
id: number;
|
|
224
|
+
name: string;
|
|
225
|
+
};
|
|
226
|
+
parent?: {
|
|
227
|
+
id: number;
|
|
228
|
+
};
|
|
229
|
+
subject: string;
|
|
230
|
+
description?: string;
|
|
231
|
+
start_date?: string;
|
|
232
|
+
due_date?: string;
|
|
233
|
+
done_ratio?: number;
|
|
234
|
+
is_private?: boolean;
|
|
235
|
+
estimated_hours?: number;
|
|
236
|
+
spent_hours?: number;
|
|
237
|
+
total_estimated_hours?: number;
|
|
238
|
+
total_spent_hours?: number;
|
|
239
|
+
custom_fields?: RedmineCustomFieldValue[];
|
|
240
|
+
created_on: string;
|
|
241
|
+
updated_on: string;
|
|
242
|
+
closed_on?: string;
|
|
243
|
+
attachments?: RedmineAttachment[];
|
|
244
|
+
relations?: RedmineRelation[];
|
|
245
|
+
journals?: RedmineJournal[];
|
|
246
|
+
watchers?: {
|
|
247
|
+
id: number;
|
|
248
|
+
name: string;
|
|
249
|
+
}[];
|
|
250
|
+
children?: {
|
|
251
|
+
id: number;
|
|
252
|
+
tracker: {
|
|
253
|
+
id: number;
|
|
254
|
+
name: string;
|
|
255
|
+
};
|
|
256
|
+
subject: string;
|
|
257
|
+
}[];
|
|
258
|
+
changesets?: RedmineChangeset[];
|
|
259
|
+
allowed_statuses?: {
|
|
260
|
+
id: number;
|
|
261
|
+
name: string;
|
|
262
|
+
}[];
|
|
263
|
+
}
|
|
264
|
+
export interface RedmineIssuesResponse {
|
|
265
|
+
issues: RedmineIssue[];
|
|
266
|
+
total_count: number;
|
|
267
|
+
offset: number;
|
|
268
|
+
limit: number;
|
|
269
|
+
}
|
|
270
|
+
export interface RedmineProject {
|
|
271
|
+
id: number;
|
|
272
|
+
name: string;
|
|
273
|
+
identifier: string;
|
|
274
|
+
description?: string;
|
|
275
|
+
homepage?: string;
|
|
276
|
+
status: number;
|
|
277
|
+
is_public: boolean;
|
|
278
|
+
inherit_members?: boolean;
|
|
279
|
+
parent?: {
|
|
280
|
+
id: number;
|
|
281
|
+
name: string;
|
|
282
|
+
};
|
|
283
|
+
default_assigned_to?: {
|
|
284
|
+
id: number;
|
|
285
|
+
name: string;
|
|
286
|
+
};
|
|
287
|
+
default_version?: {
|
|
288
|
+
id: number;
|
|
289
|
+
name: string;
|
|
290
|
+
};
|
|
291
|
+
trackers?: RedmineTracker[];
|
|
292
|
+
issue_categories?: RedmineCategory[];
|
|
293
|
+
enabled_modules?: {
|
|
294
|
+
id: number;
|
|
295
|
+
name: string;
|
|
296
|
+
}[];
|
|
297
|
+
time_entry_activities?: RedmineActivity[];
|
|
298
|
+
issue_custom_fields?: RedmineCustomField[];
|
|
299
|
+
created_on: string;
|
|
300
|
+
updated_on: string;
|
|
301
|
+
}
|
|
302
|
+
export interface RedmineProjectsResponse {
|
|
303
|
+
projects: RedmineProject[];
|
|
304
|
+
total_count: number;
|
|
305
|
+
offset: number;
|
|
306
|
+
limit: number;
|
|
307
|
+
}
|
|
308
|
+
export interface RedmineWikiPage {
|
|
309
|
+
title: string;
|
|
310
|
+
parent?: {
|
|
311
|
+
title: string;
|
|
312
|
+
};
|
|
313
|
+
text: string;
|
|
314
|
+
version: number;
|
|
315
|
+
author: {
|
|
316
|
+
id: number;
|
|
317
|
+
name: string;
|
|
318
|
+
};
|
|
319
|
+
comments?: string;
|
|
320
|
+
created_on: string;
|
|
321
|
+
updated_on: string;
|
|
322
|
+
attachments?: RedmineAttachment[];
|
|
323
|
+
}
|
|
324
|
+
export interface RedmineWikiPageIndex {
|
|
325
|
+
title: string;
|
|
326
|
+
parent?: {
|
|
327
|
+
title: string;
|
|
328
|
+
};
|
|
329
|
+
version: number;
|
|
330
|
+
}
|
|
331
|
+
export interface RedmineWikiPagesResponse {
|
|
332
|
+
wiki_pages: RedmineWikiPageIndex[];
|
|
333
|
+
}
|
|
334
|
+
export interface RedmineSearchResult {
|
|
335
|
+
id: number;
|
|
336
|
+
title: string;
|
|
337
|
+
type: string;
|
|
338
|
+
url: string;
|
|
339
|
+
description: string;
|
|
340
|
+
datetime: string;
|
|
341
|
+
}
|
|
342
|
+
export interface RedmineSearchResponse {
|
|
343
|
+
results: RedmineSearchResult[];
|
|
344
|
+
total_count: number;
|
|
345
|
+
offset: number;
|
|
346
|
+
limit: number;
|
|
347
|
+
}
|
|
348
|
+
export interface RedmineMyAccount {
|
|
349
|
+
id: number;
|
|
350
|
+
login: string;
|
|
351
|
+
admin: boolean;
|
|
352
|
+
firstname: string;
|
|
353
|
+
lastname: string;
|
|
354
|
+
mail: string;
|
|
355
|
+
created_on: string;
|
|
356
|
+
updated_on?: string;
|
|
357
|
+
last_login_on?: string;
|
|
358
|
+
passwd_changed_on?: string;
|
|
359
|
+
twofa_scheme?: string;
|
|
360
|
+
api_key?: string;
|
|
361
|
+
status?: number;
|
|
362
|
+
custom_fields?: RedmineCustomFieldValue[];
|
|
363
|
+
}
|
|
364
|
+
export interface RedmineMyAccountResponse {
|
|
365
|
+
user: RedmineMyAccount;
|
|
366
|
+
}
|
|
367
|
+
export interface RedmineTimeEntry {
|
|
368
|
+
id: number;
|
|
369
|
+
project: {
|
|
370
|
+
id: number;
|
|
371
|
+
name: string;
|
|
372
|
+
};
|
|
373
|
+
issue?: {
|
|
374
|
+
id: number;
|
|
375
|
+
};
|
|
376
|
+
user: {
|
|
377
|
+
id: number;
|
|
378
|
+
name: string;
|
|
379
|
+
};
|
|
380
|
+
activity: {
|
|
381
|
+
id: number;
|
|
382
|
+
name: string;
|
|
383
|
+
};
|
|
384
|
+
hours: number;
|
|
385
|
+
comments?: string;
|
|
386
|
+
spent_on: string;
|
|
387
|
+
created_on: string;
|
|
388
|
+
updated_on: string;
|
|
389
|
+
custom_fields?: RedmineCustomFieldValue[];
|
|
390
|
+
}
|
|
391
|
+
export interface RedmineTimeEntriesResponse {
|
|
392
|
+
time_entries: RedmineTimeEntry[];
|
|
393
|
+
total_count: number;
|
|
394
|
+
offset: number;
|
|
395
|
+
limit: number;
|
|
396
|
+
}
|
|
397
|
+
export interface RedmineEnumeration {
|
|
398
|
+
id: number;
|
|
399
|
+
name: string;
|
|
400
|
+
is_default: boolean;
|
|
401
|
+
}
|
|
402
|
+
export interface RedmineIssuePrioritiesResponse {
|
|
403
|
+
issue_priorities: RedmineEnumeration[];
|
|
404
|
+
}
|
|
405
|
+
export interface RedmineTimeEntryActivitiesResponse {
|
|
406
|
+
time_entry_activities: RedmineEnumeration[];
|
|
407
|
+
}
|
|
408
|
+
export interface RedmineDocumentCategoriesResponse {
|
|
409
|
+
document_categories: RedmineEnumeration[];
|
|
410
|
+
}
|
|
411
|
+
export interface RedmineUser {
|
|
412
|
+
id: number;
|
|
413
|
+
login: string;
|
|
414
|
+
admin?: boolean;
|
|
415
|
+
firstname: string;
|
|
416
|
+
lastname: string;
|
|
417
|
+
mail?: string;
|
|
418
|
+
created_on: string;
|
|
419
|
+
updated_on?: string;
|
|
420
|
+
last_login_on?: string;
|
|
421
|
+
passwd_changed_on?: string;
|
|
422
|
+
api_key?: string;
|
|
423
|
+
status?: number;
|
|
424
|
+
custom_fields?: RedmineCustomFieldValue[];
|
|
425
|
+
memberships?: RedmineMembership[];
|
|
426
|
+
groups?: {
|
|
427
|
+
id: number;
|
|
428
|
+
name: string;
|
|
429
|
+
}[];
|
|
430
|
+
}
|
|
431
|
+
export interface RedmineUsersResponse {
|
|
432
|
+
users: RedmineUser[];
|
|
433
|
+
total_count: number;
|
|
434
|
+
offset: number;
|
|
435
|
+
limit: number;
|
|
436
|
+
}
|
|
437
|
+
export interface RedmineGroup {
|
|
438
|
+
id: number;
|
|
439
|
+
name: string;
|
|
440
|
+
users?: {
|
|
441
|
+
id: number;
|
|
442
|
+
name: string;
|
|
443
|
+
}[];
|
|
444
|
+
memberships?: RedmineMembership[];
|
|
445
|
+
}
|
|
446
|
+
export interface RedmineGroupsResponse {
|
|
447
|
+
groups: RedmineGroup[];
|
|
448
|
+
total_count: number;
|
|
449
|
+
offset: number;
|
|
450
|
+
limit: number;
|
|
451
|
+
}
|
|
452
|
+
export interface RedmineMembership {
|
|
453
|
+
id: number;
|
|
454
|
+
project: {
|
|
455
|
+
id: number;
|
|
456
|
+
name: string;
|
|
457
|
+
};
|
|
458
|
+
user?: {
|
|
459
|
+
id: number;
|
|
460
|
+
name: string;
|
|
461
|
+
};
|
|
462
|
+
group?: {
|
|
463
|
+
id: number;
|
|
464
|
+
name: string;
|
|
465
|
+
};
|
|
466
|
+
roles: {
|
|
467
|
+
id: number;
|
|
468
|
+
name: string;
|
|
469
|
+
inherited?: boolean;
|
|
470
|
+
}[];
|
|
471
|
+
}
|
|
472
|
+
export interface RedmineMembershipsResponse {
|
|
473
|
+
memberships: RedmineMembership[];
|
|
474
|
+
total_count: number;
|
|
475
|
+
offset: number;
|
|
476
|
+
limit: number;
|
|
477
|
+
}
|
|
478
|
+
export interface RedmineRole {
|
|
479
|
+
id: number;
|
|
480
|
+
name: string;
|
|
481
|
+
assignable?: boolean;
|
|
482
|
+
issues_visibility?: string;
|
|
483
|
+
time_entries_visibility?: string;
|
|
484
|
+
users_visibility?: string;
|
|
485
|
+
permissions?: string[];
|
|
486
|
+
}
|
|
487
|
+
export interface RedmineRolesResponse {
|
|
488
|
+
roles: RedmineRole[];
|
|
489
|
+
}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { RedmineClient } from "./redmine/client.js";
|
|
3
|
+
import { type ToolGroup } from "./tools/index.js";
|
|
4
|
+
export declare function createServer(redmineClient: RedmineClient, toolGroups: ToolGroup[]): McpServer;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerTools } from "./tools/index.js";
|
|
3
|
+
export function createServer(redmineClient, toolGroups) {
|
|
4
|
+
const server = new McpServer({
|
|
5
|
+
name: "redmine-mcp",
|
|
6
|
+
version: "0.3.1",
|
|
7
|
+
});
|
|
8
|
+
registerTools(server, redmineClient, toolGroups);
|
|
9
|
+
return server;
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function registerAccountTools(server, client) {
|
|
2
|
+
server.registerTool("get_my_account", {
|
|
3
|
+
description: "Get current user account information",
|
|
4
|
+
}, async () => {
|
|
5
|
+
const result = await client.getMyAccount();
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
8
|
+
};
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerAdminTools(server, client) {
|
|
3
|
+
// === USERS ===
|
|
4
|
+
server.registerTool("list_users", {
|
|
5
|
+
description: "List all users (admin only)",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
status: z.number().optional().describe("Filter by status: 0=all, 1=active (default), 2=registered, 3=locked"),
|
|
8
|
+
name: z.string().optional().describe("Search in login, firstname, lastname, mail"),
|
|
9
|
+
group_id: z.number().optional().describe("Filter by group membership"),
|
|
10
|
+
limit: z.number().optional().describe("Maximum results"),
|
|
11
|
+
offset: z.number().optional().describe("Skip first N results"),
|
|
12
|
+
},
|
|
13
|
+
}, async (params) => {
|
|
14
|
+
const result = await client.listUsers(params);
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
server.registerTool("get_user", {
|
|
20
|
+
description: "Get user details by ID or 'current' for authenticated user",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
user_id: z.union([z.number(), z.literal("current")]).describe("User ID or 'current'"),
|
|
23
|
+
include: z.string().optional().describe("Include: memberships, groups"),
|
|
24
|
+
},
|
|
25
|
+
}, async (params) => {
|
|
26
|
+
const result = await client.getUser(params.user_id, params.include);
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
server.registerTool("create_user", {
|
|
32
|
+
description: "Create a new user (admin only)",
|
|
33
|
+
inputSchema: {
|
|
34
|
+
login: z.string().describe("Login name (required)"),
|
|
35
|
+
firstname: z.string().describe("First name (required)"),
|
|
36
|
+
lastname: z.string().describe("Last name (required)"),
|
|
37
|
+
mail: z.string().describe("Email address (required)"),
|
|
38
|
+
password: z.string().optional().describe("Password (optional if generate_password=true)"),
|
|
39
|
+
generate_password: z.boolean().optional().describe("Generate random password"),
|
|
40
|
+
must_change_passwd: z.boolean().optional().describe("Force password change on first login"),
|
|
41
|
+
auth_source_id: z.number().optional().describe("External authentication source ID"),
|
|
42
|
+
mail_notification: z.string().optional().describe("Email notification preference"),
|
|
43
|
+
admin: z.boolean().optional().describe("Grant admin privileges"),
|
|
44
|
+
send_information: z.boolean().optional().describe("Send account info email to user"),
|
|
45
|
+
},
|
|
46
|
+
}, async (params) => {
|
|
47
|
+
const result = await client.createUser(params);
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
server.registerTool("update_user", {
|
|
53
|
+
description: "Update an existing user (admin only)",
|
|
54
|
+
inputSchema: {
|
|
55
|
+
user_id: z.number().describe("User ID to update"),
|
|
56
|
+
login: z.string().optional().describe("New login name"),
|
|
57
|
+
firstname: z.string().optional().describe("New first name"),
|
|
58
|
+
lastname: z.string().optional().describe("New last name"),
|
|
59
|
+
mail: z.string().optional().describe("New email address"),
|
|
60
|
+
password: z.string().optional().describe("New password"),
|
|
61
|
+
admin: z.boolean().optional().describe("Change admin status"),
|
|
62
|
+
status: z.number().optional().describe("Change status: 1=active, 2=registered, 3=locked"),
|
|
63
|
+
},
|
|
64
|
+
}, async (params) => {
|
|
65
|
+
const { user_id, ...data } = params;
|
|
66
|
+
const result = await client.updateUser(user_id, data);
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
server.registerTool("delete_user", {
|
|
72
|
+
description: "Delete a user permanently (admin only)",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
user_id: z.number().describe("User ID to delete"),
|
|
75
|
+
},
|
|
76
|
+
}, async (params) => {
|
|
77
|
+
const result = await client.deleteUser(params.user_id);
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
// === GROUPS ===
|
|
83
|
+
server.registerTool("list_groups", {
|
|
84
|
+
description: "List all groups (admin only)",
|
|
85
|
+
}, async () => {
|
|
86
|
+
const result = await client.listGroups();
|
|
87
|
+
return {
|
|
88
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
server.registerTool("get_group", {
|
|
92
|
+
description: "Get group details (admin only)",
|
|
93
|
+
inputSchema: {
|
|
94
|
+
group_id: z.number().describe("Group ID"),
|
|
95
|
+
include: z.string().optional().describe("Include: users, memberships"),
|
|
96
|
+
},
|
|
97
|
+
}, async (params) => {
|
|
98
|
+
const result = await client.getGroup(params.group_id, params.include);
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
server.registerTool("create_group", {
|
|
104
|
+
description: "Create a new group (admin only)",
|
|
105
|
+
inputSchema: {
|
|
106
|
+
name: z.string().describe("Group name (required)"),
|
|
107
|
+
user_ids: z.array(z.number()).optional().describe("Initial member user IDs"),
|
|
108
|
+
},
|
|
109
|
+
}, async (params) => {
|
|
110
|
+
const result = await client.createGroup(params);
|
|
111
|
+
return {
|
|
112
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
server.registerTool("delete_group", {
|
|
116
|
+
description: "Delete a group (admin only)",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
group_id: z.number().describe("Group ID to delete"),
|
|
119
|
+
},
|
|
120
|
+
}, async (params) => {
|
|
121
|
+
const result = await client.deleteGroup(params.group_id);
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
server.registerTool("add_user_to_group", {
|
|
127
|
+
description: "Add a user to a group (admin only)",
|
|
128
|
+
inputSchema: {
|
|
129
|
+
group_id: z.number().describe("Group ID"),
|
|
130
|
+
user_id: z.number().describe("User ID to add"),
|
|
131
|
+
},
|
|
132
|
+
}, async (params) => {
|
|
133
|
+
const result = await client.addUserToGroup(params.group_id, params.user_id);
|
|
134
|
+
return {
|
|
135
|
+
content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
server.registerTool("remove_user_from_group", {
|
|
139
|
+
description: "Remove a user from a group (admin only)",
|
|
140
|
+
inputSchema: {
|
|
141
|
+
group_id: z.number().describe("Group ID"),
|
|
142
|
+
user_id: z.number().describe("User ID to remove"),
|
|
143
|
+
},
|
|
144
|
+
}, async (params) => {
|
|
145
|
+
const result = await client.removeUserFromGroup(params.group_id, params.user_id);
|
|
146
|
+
return {
|
|
147
|
+
content: [{ type: "text", text: JSON.stringify(result ?? { success: true }, null, 2) }],
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
}
|