backlog-mcp-server 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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +440 -0
  3. package/README.md +501 -0
  4. package/build/backlog/backlogErrorHandler.js +8 -0
  5. package/build/backlog/customFields.js +16 -0
  6. package/build/backlog/parseBacklogAPIError.js +38 -0
  7. package/build/createTranslationHelper.js +28 -0
  8. package/build/handlers/builders/composeToolHandler.js +26 -0
  9. package/build/handlers/transformers/wrapWithErrorHandling.js +4 -0
  10. package/build/handlers/transformers/wrapWithFieldPicking.js +55 -0
  11. package/build/handlers/transformers/wrapWithTokenLimit.js +21 -0
  12. package/build/handlers/transformers/wrapWithToolResult.js +39 -0
  13. package/build/index.js +102 -0
  14. package/build/registerTools.js +37 -0
  15. package/build/tools/addIssue.js +94 -0
  16. package/build/tools/addIssueComment.js +44 -0
  17. package/build/tools/addProject.js +39 -0
  18. package/build/tools/addPullRequest.js +65 -0
  19. package/build/tools/addPullRequestComment.js +52 -0
  20. package/build/tools/addWiki.js +29 -0
  21. package/build/tools/countIssues.js +111 -0
  22. package/build/tools/deleteIssue.js +29 -0
  23. package/build/tools/deleteProject.js +29 -0
  24. package/build/tools/downloadDocumentAttachment.js +1 -0
  25. package/build/tools/dynamicTools/toolsets.js +103 -0
  26. package/build/tools/getCategories.js +30 -0
  27. package/build/tools/getCustomFields.js +37 -0
  28. package/build/tools/getDocument.js +20 -0
  29. package/build/tools/getDocumentTree.js +20 -0
  30. package/build/tools/getDocuments.js +25 -0
  31. package/build/tools/getGitRepositories.js +29 -0
  32. package/build/tools/getGitRepository.js +41 -0
  33. package/build/tools/getIssue.js +29 -0
  34. package/build/tools/getIssueComments.js +45 -0
  35. package/build/tools/getIssueTypes.js +30 -0
  36. package/build/tools/getIssues.js +155 -0
  37. package/build/tools/getMyself.js +14 -0
  38. package/build/tools/getNotifications.js +35 -0
  39. package/build/tools/getNotificationsCount.js +20 -0
  40. package/build/tools/getPriorities.js +13 -0
  41. package/build/tools/getProject.js +29 -0
  42. package/build/tools/getProjectList.js +23 -0
  43. package/build/tools/getPullRequest.js +44 -0
  44. package/build/tools/getPullRequestComments.js +60 -0
  45. package/build/tools/getPullRequests.js +65 -0
  46. package/build/tools/getPullRequestsCount.js +57 -0
  47. package/build/tools/getResolutions.js +13 -0
  48. package/build/tools/getSpace.js +14 -0
  49. package/build/tools/getUsers.js +14 -0
  50. package/build/tools/getWatchingListCount.js +17 -0
  51. package/build/tools/getWatchingListItems.js +17 -0
  52. package/build/tools/getWiki.js +21 -0
  53. package/build/tools/getWikiPages.js +37 -0
  54. package/build/tools/getWikisCount.js +29 -0
  55. package/build/tools/markNotificationAsRead.js +26 -0
  56. package/build/tools/resetUnreadNotificationCount.js +13 -0
  57. package/build/tools/tools.js +143 -0
  58. package/build/tools/updateIssue.js +116 -0
  59. package/build/tools/updateProject.js +57 -0
  60. package/build/tools/updatePullRequest.js +68 -0
  61. package/build/tools/updatePullRequestComment.js +51 -0
  62. package/build/types/mcp.js +1 -0
  63. package/build/types/result.js +3 -0
  64. package/build/types/tool.js +1 -0
  65. package/build/types/toolsets.js +1 -0
  66. package/build/types/zod/backlogOutputDefinition.js +468 -0
  67. package/build/utils/generateFieldsDescription.js +47 -0
  68. package/build/utils/resolveIdOrKey.js +25 -0
  69. package/build/utils/runToolSafely.js +18 -0
  70. package/build/utils/tokenCounter.js +11 -0
  71. package/build/utils/toolRegistrar.js +12 -0
  72. package/build/utils/toolsetUtils.js +48 -0
  73. package/build/utils/wrapServerWithToolRegistry.js +16 -0
  74. package/build/version.js +1 -0
  75. package/build/version.template.js +1 -0
  76. package/package.json +52 -0
@@ -0,0 +1,468 @@
1
+ import { z } from 'zod';
2
+ export const TextFormattingRuleSchema = z.enum(['backlog', 'markdown']);
3
+ export const RoleTypeSchema = z.union([
4
+ z.nativeEnum({
5
+ Admin: 1,
6
+ User: 2,
7
+ Reporter: 3,
8
+ Viewer: 4,
9
+ GuestReporter: 5,
10
+ GuestViewer: 6,
11
+ }),
12
+ z.nativeEnum({
13
+ Admin: 1,
14
+ MemberOrGuest: 2,
15
+ MemberOrGuestForAddIssues: 3,
16
+ MemberOrGuestForViewIssues: 4,
17
+ }),
18
+ ]);
19
+ export const LanguageSchema = z.union([
20
+ z.literal('en'),
21
+ z.literal('ja'),
22
+ z.null(),
23
+ ]);
24
+ export const ActivityTypeSchema = z.nativeEnum({
25
+ Undefined: -1,
26
+ IssueCreated: 1,
27
+ IssueUpdated: 2,
28
+ IssueCommented: 3,
29
+ IssueDeleted: 4,
30
+ WikiCreated: 5,
31
+ WikiUpdated: 6,
32
+ WikiDeleted: 7,
33
+ FileAdded: 8,
34
+ FileUpdated: 9,
35
+ FileDeleted: 10,
36
+ SvnCommitted: 11,
37
+ GitPushed: 12,
38
+ GitRepositoryCreated: 13,
39
+ IssueMultiUpdated: 14,
40
+ ProjectUserAdded: 15,
41
+ ProjectUserRemoved: 16,
42
+ NotifyAdded: 17,
43
+ PullRequestAdded: 18,
44
+ PullRequestUpdated: 19,
45
+ PullRequestCommented: 20,
46
+ PullRequestMerged: 21,
47
+ MilestoneCreated: 22,
48
+ MilestoneUpdated: 23,
49
+ MilestoneDeleted: 24,
50
+ ProjectGroupAdded: 25,
51
+ ProjectGroupDeleted: 26,
52
+ });
53
+ export const IssueTypeColorSchema = z.enum([
54
+ '#e30000',
55
+ '#990000',
56
+ '#934981',
57
+ '#814fbc',
58
+ '#2779ca',
59
+ '#007e9a',
60
+ '#7ea800',
61
+ '#ff9200',
62
+ '#ff3265',
63
+ '#666665',
64
+ ]);
65
+ export const ProjectStatusColorSchema = z.enum([
66
+ '#ea2c00',
67
+ '#e87758',
68
+ '#e07b9a',
69
+ '#868cb7',
70
+ '#3b9dbd',
71
+ '#4caf93',
72
+ '#b0be3c',
73
+ '#eda62a',
74
+ '#f42858',
75
+ '#393939',
76
+ ]);
77
+ export const CustomFieldTypeSchema = z.nativeEnum({
78
+ Text: 1,
79
+ TextArea: 2,
80
+ Numeric: 3,
81
+ Date: 4,
82
+ SingleList: 5,
83
+ MultipleList: 6,
84
+ CheckBox: 7,
85
+ Radio: 8,
86
+ });
87
+ export const WebhookActivityIdSchema = z.number();
88
+ export const UserSchema = z.object({
89
+ id: z.number(),
90
+ userId: z.string(),
91
+ name: z.string(),
92
+ roleType: RoleTypeSchema,
93
+ lang: LanguageSchema,
94
+ mailAddress: z.string(),
95
+ lastLoginTime: z.string(),
96
+ });
97
+ export const ProjectStatusSchema = z.object({
98
+ id: z.number(),
99
+ projectId: z.number(),
100
+ name: z.string(),
101
+ color: ProjectStatusColorSchema,
102
+ displayOrder: z.number(),
103
+ });
104
+ export const CategorySchema = z.object({
105
+ id: z.number(),
106
+ projectId: z.number(),
107
+ name: z.string(),
108
+ displayOrder: z.number(),
109
+ });
110
+ export const IssueFileInfoSchema = z.object({
111
+ id: z.number(),
112
+ name: z.string(),
113
+ size: z.number(),
114
+ createdUser: UserSchema,
115
+ created: z.string(),
116
+ });
117
+ export const StarSchema = z.object({
118
+ id: z.number(),
119
+ comment: z.string().optional(),
120
+ url: z.string(),
121
+ title: z.string(),
122
+ presenter: UserSchema,
123
+ created: z.string(),
124
+ });
125
+ export const IssueTypeSchema = z.object({
126
+ id: z.number(),
127
+ projectId: z.number(),
128
+ name: z.string(),
129
+ color: IssueTypeColorSchema,
130
+ displayOrder: z.number(),
131
+ templateSummary: z.string().optional(),
132
+ templateDescription: z.string().optional(),
133
+ });
134
+ export const ResolutionSchema = z.object({
135
+ id: z.number(),
136
+ name: z.string(),
137
+ });
138
+ export const PrioritySchema = z.object({
139
+ id: z.number(),
140
+ name: z.string(),
141
+ });
142
+ export const VersionSchema = z.object({
143
+ id: z.number(),
144
+ projectId: z.number(),
145
+ name: z.string(),
146
+ description: z.string().optional(),
147
+ startDate: z.string().optional(),
148
+ releaseDueDate: z.string().optional(),
149
+ archived: z.boolean(),
150
+ displayOrder: z.number(),
151
+ });
152
+ export const CustomFieldSchema = z.object({
153
+ id: z.number(),
154
+ projectId: z.number(),
155
+ typeId: CustomFieldTypeSchema,
156
+ name: z.string(),
157
+ description: z.string(),
158
+ required: z.boolean(),
159
+ applicableIssueTypes: z.array(z.number()),
160
+ });
161
+ export const SharedFileSchema = z.object({
162
+ id: z.number(),
163
+ projectId: z.number(),
164
+ type: z.string(),
165
+ dir: z.string(),
166
+ name: z.string(),
167
+ size: z.number(),
168
+ createdUser: UserSchema,
169
+ created: z.string(),
170
+ updatedUser: UserSchema,
171
+ updated: z.string(),
172
+ });
173
+ export const IssueSchema = z.object({
174
+ id: z.number(),
175
+ projectId: z.number(),
176
+ issueKey: z.string(),
177
+ keyId: z.number(),
178
+ issueType: IssueTypeSchema,
179
+ summary: z.string(),
180
+ description: z.string(),
181
+ resolution: ResolutionSchema.optional(),
182
+ priority: PrioritySchema,
183
+ status: ProjectStatusSchema,
184
+ assignee: UserSchema.optional(),
185
+ category: z.array(CategorySchema),
186
+ versions: z.array(VersionSchema),
187
+ milestone: z.array(VersionSchema),
188
+ startDate: z.string().optional(),
189
+ dueDate: z.string().optional(),
190
+ estimatedHours: z.number().optional(),
191
+ actualHours: z.number().optional(),
192
+ parentIssueId: z.number().optional(),
193
+ createdUser: UserSchema,
194
+ created: z.string(),
195
+ updatedUser: UserSchema,
196
+ updated: z.string(),
197
+ customFields: z.array(CustomFieldSchema),
198
+ attachments: z.array(IssueFileInfoSchema),
199
+ sharedFiles: z.array(SharedFileSchema),
200
+ stars: z.array(StarSchema),
201
+ });
202
+ export const ProjectSchema = z.object({
203
+ id: z.number(),
204
+ projectKey: z.string(),
205
+ name: z.string(),
206
+ chartEnabled: z.boolean(),
207
+ useResolvedForChart: z.boolean(),
208
+ subtaskingEnabled: z.boolean(),
209
+ projectLeaderCanEditProjectLeader: z.boolean(),
210
+ useWiki: z.boolean(),
211
+ useFileSharing: z.boolean(),
212
+ useWikiTreeView: z.boolean(),
213
+ useOriginalImageSizeAtWiki: z.boolean(),
214
+ useSubversion: z.boolean(),
215
+ useGit: z.boolean(),
216
+ textFormattingRule: TextFormattingRuleSchema,
217
+ archived: z.boolean(),
218
+ displayOrder: z.number(),
219
+ useDevAttributes: z.boolean(),
220
+ });
221
+ export const AttachmentInfoSchema = z.object({
222
+ id: z.number(),
223
+ type: z.string(),
224
+ });
225
+ export const AttributeInfoSchema = z.object({
226
+ id: z.number(),
227
+ typeId: z.number(),
228
+ });
229
+ export const NotificationInfoSchema = z.object({
230
+ type: z.string(),
231
+ });
232
+ export const IssueChangeLogSchema = z.object({
233
+ field: z.string(),
234
+ newValue: z.string(),
235
+ originalValue: z.string(),
236
+ attachmentInfo: AttachmentInfoSchema,
237
+ attributeInfo: AttributeInfoSchema,
238
+ notificationInfo: NotificationInfoSchema,
239
+ });
240
+ export const CommentNotificationSchema = z.object({
241
+ id: z.number(),
242
+ alreadyRead: z.boolean(),
243
+ reason: z.number(),
244
+ user: UserSchema,
245
+ resourceAlreadyRead: z.boolean(),
246
+ });
247
+ export const IssueCommentSchema = z.object({
248
+ id: z.number(),
249
+ projectId: z.number(),
250
+ issueId: z.number(),
251
+ content: z.string(),
252
+ changeLog: z.array(IssueChangeLogSchema),
253
+ createdUser: UserSchema,
254
+ created: z.string(),
255
+ updated: z.string(),
256
+ stars: z.array(StarSchema),
257
+ notifications: z.array(CommentNotificationSchema),
258
+ });
259
+ export const PullRequestStatusSchema = z.object({
260
+ id: z.number(),
261
+ name: z.string(),
262
+ });
263
+ export const PullRequestFileInfoSchema = z.object({
264
+ id: z.number(),
265
+ name: z.string(),
266
+ size: z.number(),
267
+ createdUser: UserSchema,
268
+ created: z.string(),
269
+ });
270
+ export const ChangeLogSchema = z.object({
271
+ field: z.string(),
272
+ newValue: z.string(),
273
+ originalValue: z.string(),
274
+ });
275
+ export const PullRequestChangeLogSchema = ChangeLogSchema;
276
+ export const PullRequestSchema = z.object({
277
+ id: z.number(),
278
+ projectId: z.number(),
279
+ repositoryId: z.number(),
280
+ number: z.number(),
281
+ summary: z.string(),
282
+ description: z.string(),
283
+ base: z.string(),
284
+ branch: z.string(),
285
+ status: PullRequestStatusSchema,
286
+ assignee: UserSchema.optional(),
287
+ issue: IssueSchema,
288
+ baseCommit: z.string().optional(),
289
+ branchCommit: z.string().optional(),
290
+ mergeCommit: z.string().optional(),
291
+ closeAt: z.string().optional(),
292
+ mergeAt: z.string().optional(),
293
+ createdUser: UserSchema,
294
+ created: z.string(),
295
+ updatedUser: UserSchema,
296
+ updated: z.string(),
297
+ attachments: z.array(PullRequestFileInfoSchema),
298
+ stars: z.array(StarSchema),
299
+ });
300
+ export const PullRequestCommentSchema = z.object({
301
+ id: z.number(),
302
+ content: z.string(),
303
+ changeLog: z.array(PullRequestChangeLogSchema),
304
+ createdUser: UserSchema,
305
+ created: z.string(),
306
+ updated: z.string(),
307
+ stars: z.array(StarSchema),
308
+ notifications: z.array(CommentNotificationSchema),
309
+ });
310
+ export const WikiFileInfoSchema = z.object({
311
+ id: z.number(),
312
+ name: z.string(),
313
+ size: z.number(),
314
+ createdUser: UserSchema,
315
+ created: z.string(),
316
+ });
317
+ export const TagSchema = z.object({
318
+ id: z.number(),
319
+ name: z.string(),
320
+ });
321
+ export const WikiSchema = z.object({
322
+ id: z.number(),
323
+ projectId: z.number(),
324
+ name: z.string(),
325
+ content: z.string(),
326
+ tags: z.array(TagSchema),
327
+ attachments: z.array(WikiFileInfoSchema),
328
+ sharedFiles: z.array(SharedFileSchema),
329
+ stars: z.array(StarSchema),
330
+ createdUser: UserSchema,
331
+ created: z.string(),
332
+ updatedUser: UserSchema,
333
+ updated: z.string(),
334
+ });
335
+ export const IssueCountSchema = z.object({
336
+ count: z.number(),
337
+ });
338
+ export const WatchingListItemSchema = z.object({
339
+ id: z.number(),
340
+ resourceAlreadyRead: z.boolean(),
341
+ note: z.string(),
342
+ type: z.string(),
343
+ issue: IssueSchema,
344
+ lastContentUpdated: z.string(),
345
+ created: z.string(),
346
+ updated: z.string(),
347
+ });
348
+ export const GitRepositorySchema = z.object({
349
+ id: z.number(),
350
+ projectId: z.number(),
351
+ name: z.string(),
352
+ description: z.string(),
353
+ hookUrl: z.string().optional(),
354
+ httpUrl: z.string(),
355
+ sshUrl: z.string(),
356
+ displayOrder: z.number(),
357
+ pushedAt: z.string().optional(),
358
+ createdUser: UserSchema,
359
+ created: z.string(),
360
+ updatedUser: UserSchema,
361
+ updated: z.string(),
362
+ });
363
+ export const NotificationSchema = z.object({
364
+ id: z.number(),
365
+ alreadyRead: z.boolean(),
366
+ reason: z.number(),
367
+ resourceAlreadyRead: z.boolean(),
368
+ project: ProjectSchema.optional(),
369
+ issue: IssueSchema.optional(),
370
+ comment: IssueCommentSchema.optional(),
371
+ pullRequest: PullRequestSchema.optional(),
372
+ pullRequestComment: PullRequestCommentSchema.optional(),
373
+ sender: UserSchema,
374
+ created: z.string(),
375
+ });
376
+ export const NotificationCountSchema = z.object({
377
+ count: z.number(),
378
+ });
379
+ export const PullRequestCountSchema = z.object({
380
+ count: z.number(),
381
+ });
382
+ export const SpaceSchema = z.object({
383
+ spaceKey: z.string(),
384
+ name: z.string(),
385
+ ownerId: z.number(),
386
+ lang: z.string(),
387
+ timezone: z.string(),
388
+ reportSendTime: z.string(),
389
+ textFormattingRule: TextFormattingRuleSchema,
390
+ created: z.string(),
391
+ updated: z.string(),
392
+ });
393
+ export const WatchingListCountSchema = z.object({
394
+ count: z.number(),
395
+ });
396
+ export const WikiListItemSchema = z.object({
397
+ id: z.number(),
398
+ projectId: z.number(),
399
+ name: z.string(),
400
+ tags: z.array(TagSchema),
401
+ createdUser: UserSchema,
402
+ created: z.string(),
403
+ updatedUser: UserSchema,
404
+ updated: z.string(),
405
+ });
406
+ export const WikiCountSchema = z.object({
407
+ count: z.number(),
408
+ });
409
+ export const DocumentSchema = z.object({
410
+ id: z.number(),
411
+ projectId: z.number(),
412
+ name: z.string(),
413
+ content: z.string(),
414
+ createdUser: UserSchema,
415
+ created: z.string(),
416
+ updatedUser: UserSchema,
417
+ updated: z.string(),
418
+ });
419
+ export const DocumentAttachmentSchema = z.object({
420
+ filename: z.string(),
421
+ body: z.any(),
422
+ url: z.string(),
423
+ });
424
+ export const DocumentTagSchema = z.object({
425
+ id: z.number(),
426
+ name: z.string(),
427
+ });
428
+ export const DocumentFileInfoSchema = z.object({
429
+ id: z.number(),
430
+ name: z.string(),
431
+ size: z.number(),
432
+ createdUser: UserSchema,
433
+ created: z.string(),
434
+ });
435
+ export const DocumentItemSchema = z.object({
436
+ id: z.string(),
437
+ projectId: z.number(),
438
+ title: z.string(),
439
+ plain: z.string(),
440
+ json: z.string(),
441
+ statusId: z.number(),
442
+ emoji: z.string().nullable(),
443
+ attachments: z.array(DocumentFileInfoSchema),
444
+ tags: z.array(DocumentTagSchema),
445
+ createdUser: UserSchema,
446
+ created: z.string(),
447
+ updatedUser: UserSchema,
448
+ updated: z.string(),
449
+ });
450
+ export const DocumentTreeNodeSchema = z.lazy(() => z.object({
451
+ id: z.string(),
452
+ name: z.string().optional(),
453
+ children: z.array(DocumentTreeNodeSchema),
454
+ statusId: z.number().optional(),
455
+ emoji: z.string().optional(),
456
+ emojiType: z.string().optional(),
457
+ updated: z.string().optional(),
458
+ }));
459
+ export const ActiveTrashTreeSchema = z.object({
460
+ id: z.string(),
461
+ children: z.array(DocumentTreeNodeSchema),
462
+ });
463
+ export const DocumentTreeFullSchema = {
464
+ projectId: z.number(),
465
+ activeTree: ActiveTrashTreeSchema.optional(),
466
+ trashTree: ActiveTrashTreeSchema.optional(),
467
+ };
468
+ export const DocumentTreeFullSchemaZ = z.object(DocumentTreeFullSchema);
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Generate GraphQL like fields and type specs from Zod types
4
+ */
5
+ export function generateFieldsDescription(outputSchema, importantFields = [], typeName = 'Output') {
6
+ const allFields = Object.keys(outputSchema.shape);
7
+ // Generate Example Query
8
+ const exampleQueryFields = importantFields.length > 0 ? importantFields : allFields;
9
+ // Generate Output Schema
10
+ const gqlTypeDef = generateGraphQLType(typeName, outputSchema);
11
+ return `
12
+ Specify the fields to retrieve using GraphQL query syntax.
13
+ Example (query):
14
+ {
15
+ ${exampleQueryFields.join('\n ')}
16
+ }
17
+ Output schema (type definition):
18
+ ${gqlTypeDef}
19
+ `.trim();
20
+ }
21
+ function generateGraphQLType(typeName, schema) {
22
+ const lines = [`type ${typeName} {`];
23
+ for (const [key, value] of Object.entries(schema.shape)) {
24
+ lines.push(` ${key}: ${mapZodTypeToGraphQLType(value)}`);
25
+ }
26
+ lines.push('}');
27
+ return lines.join('\n');
28
+ }
29
+ /**
30
+ * Zod to graphql
31
+ */
32
+ function mapZodTypeToGraphQLType(zodType) {
33
+ if (zodType instanceof z.ZodString)
34
+ return 'String!';
35
+ if (zodType instanceof z.ZodNumber)
36
+ return 'Int!';
37
+ if (zodType instanceof z.ZodBoolean)
38
+ return 'Boolean!';
39
+ if (zodType instanceof z.ZodNullable)
40
+ return mapZodTypeToGraphQLType(zodType.unwrap()).replace(/!$/, '');
41
+ if (zodType instanceof z.ZodOptional)
42
+ return mapZodTypeToGraphQLType(zodType.unwrap()).replace(/!$/, '');
43
+ // Spec: a nested part is JSON
44
+ if (zodType instanceof z.ZodObject)
45
+ return 'JSON';
46
+ return 'String';
47
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Generic resolver for entity identification by ID or named field (e.g., key, name, slug).
3
+ * @param entity - The entity name, e.g., "project"
4
+ * @param fieldName - The name of the alternative to `id`, e.g., "key", "name", "slug"
5
+ * @param values - An object with `id?: number` and `[fieldName]?: string`
6
+ * @param t - Translator
7
+ */
8
+ function resolveIdOrField(entity, fieldName, values, t) {
9
+ const value = tryResolveIdOrField(fieldName, values);
10
+ if (value === undefined) {
11
+ return {
12
+ ok: false,
13
+ error: new Error(t(`${entity.toUpperCase()}_ID_OR_${fieldName.toUpperCase()}_REQUIRED`, `${capitalize(entity)} ID or ${fieldName} is required`)),
14
+ };
15
+ }
16
+ return { ok: true, value };
17
+ }
18
+ function tryResolveIdOrField(fieldName, values) {
19
+ return values.id !== undefined ? values.id : values[fieldName];
20
+ }
21
+ export const resolveIdOrKey = (entity, values, t) => resolveIdOrField(entity, 'key', values, t);
22
+ export const resolveIdOrName = (entity, values, t) => resolveIdOrField(entity, 'name', values, t);
23
+ function capitalize(str) {
24
+ return str.charAt(0).toUpperCase() + str.slice(1);
25
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Runs a tool handler safely, catching any errors and converting to SafeResult.
3
+ * The `onError` handler defines how to turn unknown errors into ErrorLike objects.
4
+ */
5
+ export function runToolSafely(fn, onError) {
6
+ return async (input) => {
7
+ try {
8
+ const data = await fn(input);
9
+ return { kind: 'ok', data };
10
+ }
11
+ catch (err) {
12
+ if (onError) {
13
+ return onError(err);
14
+ }
15
+ return { kind: 'error', message: 'Unknown: ' + err };
16
+ }
17
+ };
18
+ }
@@ -0,0 +1,11 @@
1
+ export function countTokens(text) {
2
+ // Normalize whitespace (convert tabs and newlines to spaces)
3
+ const normalized = text
4
+ .replace(/\s+/g, ' ') // Replace multiple whitespace with a single space
5
+ .replace(/[\n\t]/g, ' ') // Replace newlines and tabs with a space
6
+ .trim();
7
+ // Split into words and individual symbols
8
+ const tokens = normalized.match(/\w+|[^\s\w]/g);
9
+ // Return the number of tokens
10
+ return tokens ? tokens.length : 0;
11
+ }
@@ -0,0 +1,12 @@
1
+ import { registerTools } from '../registerTools.js';
2
+ import { enableToolset } from '../utils/toolsetUtils.js';
3
+ export function createToolRegistrar(server, toolsetGroup, options) {
4
+ return {
5
+ async enableToolsetAndRefresh(toolset) {
6
+ const msg = enableToolset(toolsetGroup, toolset);
7
+ registerTools(server, toolsetGroup, options);
8
+ await server.server.sendToolListChanged();
9
+ return msg;
10
+ },
11
+ };
12
+ }
@@ -0,0 +1,48 @@
1
+ import { allTools } from '../tools/tools.js';
2
+ export function getToolset(group, name) {
3
+ return group.toolsets.find((t) => t.name === name);
4
+ }
5
+ export function enableToolset(group, name) {
6
+ const ts = getToolset(group, name);
7
+ if (!ts)
8
+ return `Toolset ${name} not found`;
9
+ if (ts.enabled)
10
+ return `Toolset ${name} is already enabled`;
11
+ ts.enabled = true;
12
+ return `Toolset ${name} enabled`;
13
+ }
14
+ export function getEnabledTools(group) {
15
+ return group.toolsets.filter((ts) => ts.enabled).flatMap((ts) => ts.tools);
16
+ }
17
+ export function listAvailableToolsets(group) {
18
+ return group.toolsets.map((ts) => ({
19
+ name: ts.name,
20
+ description: ts.description,
21
+ currentlyEnabled: ts.enabled,
22
+ canEnable: true,
23
+ }));
24
+ }
25
+ export function listToolsetTools(group, name) {
26
+ const ts = getToolset(group, name);
27
+ return (ts?.tools.map((tool) => ({
28
+ name: tool.name,
29
+ description: tool.description,
30
+ toolset: name,
31
+ canEnable: true,
32
+ })) ?? []);
33
+ }
34
+ export const buildToolsetGroup = (backlog, helper, enabledToolsets) => {
35
+ const toolsetGroup = allTools(backlog, helper);
36
+ const knownNames = toolsetGroup.toolsets.map((ts) => ts.name);
37
+ const unknown = enabledToolsets.filter((name) => name !== 'all' && !knownNames.includes(name));
38
+ if (unknown.length > 0) {
39
+ console.warn(`⚠️ Unknown toolsets: ${unknown.join(', ')}`);
40
+ }
41
+ const allEnabled = enabledToolsets.includes('all');
42
+ return {
43
+ toolsets: toolsetGroup.toolsets.map((ts) => ({
44
+ ...ts,
45
+ enabled: allEnabled || enabledToolsets.includes(ts.name),
46
+ })),
47
+ };
48
+ };
@@ -0,0 +1,16 @@
1
+ // This function takes an McpServer instance and extends it with a tool registration mechanism that prevents duplicate tool registrations.
2
+ export function wrapServerWithToolRegistry(server) {
3
+ const s = server;
4
+ if (!s.__registeredToolNames) {
5
+ s.__registeredToolNames = new Set();
6
+ }
7
+ s.registerOnce = (name, description, schema, handler) => {
8
+ if (s.__registeredToolNames.has(name)) {
9
+ console.warn(`Skipping duplicate tool registration: ${name}`);
10
+ return;
11
+ }
12
+ s.__registeredToolNames.add(name);
13
+ s.tool(name, description, schema, handler);
14
+ };
15
+ return s;
16
+ }
@@ -0,0 +1 @@
1
+ export const VERSION = '0.4.0';
@@ -0,0 +1 @@
1
+ export const VERSION = '__VERSION__';