@ecubelabs/atlassian-mcp 1.9.0 → 1.10.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 (30) hide show
  1. package/dist/confluence-tools/add-labels-to-page.js +4 -8
  2. package/dist/confluence-tools/create-folder.js +4 -8
  3. package/dist/confluence-tools/create-page.js +4 -8
  4. package/dist/confluence-tools/delete-folder.js +4 -8
  5. package/dist/confluence-tools/find-label-by-name.js +4 -8
  6. package/dist/confluence-tools/find-pages-by-label-name.js +4 -8
  7. package/dist/confluence-tools/find-space-by-name.js +4 -8
  8. package/dist/confluence-tools/get-folder-by-id.js +4 -8
  9. package/dist/confluence-tools/get-folder-children.js +7 -11
  10. package/dist/confluence-tools/get-labels.js +4 -8
  11. package/dist/confluence-tools/get-page-by-id.js +5 -8
  12. package/dist/confluence-tools/get-page-children-tree.js +5 -8
  13. package/dist/confluence-tools/get-page-children.js +7 -11
  14. package/dist/confluence-tools/get-page-descendants.js +4 -8
  15. package/dist/confluence-tools/get-pages-for-label.js +4 -8
  16. package/dist/confluence-tools/get-pages.js +5 -8
  17. package/dist/confluence-tools/get-recently-created-pages.js +4 -8
  18. package/dist/confluence-tools/get-recently-updated-pages.js +4 -8
  19. package/dist/confluence-tools/get-space-by-id.js +4 -8
  20. package/dist/confluence-tools/get-space-root-content.js +4 -8
  21. package/dist/confluence-tools/get-spaces.js +4 -8
  22. package/dist/confluence-tools/get-template-by-id.js +4 -8
  23. package/dist/confluence-tools/get-templates.js +4 -8
  24. package/dist/confluence-tools/move-page.js +4 -8
  25. package/dist/confluence-tools/update-page.js +4 -8
  26. package/dist/index.js +2 -0
  27. package/dist/jira-tools-register.js +110 -272
  28. package/dist/libs/confluence-client.js +1 -1
  29. package/dist/libs/response-formatter.js +49 -0
  30. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { JiraService } from './libs/jira-client.js';
3
+ import { formatToolResponse } from './libs/response-formatter.js';
3
4
  export const registerJiraTools = (server) => {
4
5
  // Initialize Jira service
5
6
  const jiraService = new JiraService();
@@ -22,14 +23,10 @@ export const registerJiraTools = (server) => {
22
23
  }, async ({ issueKey, expand }) => {
23
24
  try {
24
25
  const issue = await jiraService.getIssue(issueKey, expand);
25
- return {
26
- content: [
27
- {
28
- type: 'text',
29
- text: JSON.stringify(issue),
30
- },
31
- ],
32
- };
26
+ return formatToolResponse(issue, {
27
+ toolName: 'get-issue',
28
+ summary: `Issue ${issue.key}: ${issue.fields?.summary ?? ''} (Status: ${issue.fields?.status?.name ?? 'unknown'})`,
29
+ });
33
30
  }
34
31
  catch (error) {
35
32
  return {
@@ -102,14 +99,12 @@ export const registerJiraTools = (server) => {
102
99
  failFast,
103
100
  reconcileIssues,
104
101
  });
105
- return {
106
- content: [
107
- {
108
- type: 'text',
109
- text: JSON.stringify(result),
110
- },
111
- ],
112
- };
102
+ const issues = result.issues ?? [];
103
+ const keys = issues.map((i) => i.key).join(', ');
104
+ return formatToolResponse(result, {
105
+ toolName: 'search-issues',
106
+ summary: `Found ${issues.length} issues (total: ${result.total ?? 'unknown'}): ${keys}`,
107
+ });
113
108
  }
114
109
  catch (error) {
115
110
  return {
@@ -151,14 +146,10 @@ export const registerJiraTools = (server) => {
151
146
  orderBy,
152
147
  expand,
153
148
  });
154
- return {
155
- content: [
156
- {
157
- type: 'text',
158
- text: JSON.stringify(result),
159
- },
160
- ],
161
- };
149
+ return formatToolResponse(result, {
150
+ toolName: 'get-comments',
151
+ summary: `${result.comments?.length ?? 0} comments for ${issueKey} (total: ${result.total ?? 'unknown'})`,
152
+ });
162
153
  }
163
154
  catch (error) {
164
155
  return {
@@ -247,14 +238,9 @@ export const registerJiraTools = (server) => {
247
238
  expand,
248
239
  status,
249
240
  });
250
- return {
251
- content: [
252
- {
253
- type: 'text',
254
- text: JSON.stringify(result),
255
- },
256
- ],
257
- };
241
+ return formatToolResponse(result, {
242
+ toolName: 'get-projects',
243
+ });
258
244
  }
259
245
  catch (error) {
260
246
  return {
@@ -272,14 +258,9 @@ export const registerJiraTools = (server) => {
272
258
  }, async ({ projectIdOrKey }) => {
273
259
  try {
274
260
  const result = await jiraService.getCreateMetadataIssueTypes(projectIdOrKey);
275
- return {
276
- content: [
277
- {
278
- type: 'text',
279
- text: JSON.stringify(result),
280
- },
281
- ],
282
- };
261
+ return formatToolResponse(result, {
262
+ toolName: 'get-create-metadata-issue-types',
263
+ });
283
264
  }
284
265
  catch (error) {
285
266
  return {
@@ -298,14 +279,9 @@ export const registerJiraTools = (server) => {
298
279
  }, async ({ projectIdOrKey, issueTypeId }) => {
299
280
  try {
300
281
  const result = await jiraService.getCreateFieldMetadata(projectIdOrKey, issueTypeId);
301
- return {
302
- content: [
303
- {
304
- type: 'text',
305
- text: JSON.stringify(result),
306
- },
307
- ],
308
- };
282
+ return formatToolResponse(result, {
283
+ toolName: 'get-create-field-metadata',
284
+ });
309
285
  }
310
286
  catch (error) {
311
287
  return {
@@ -333,14 +309,9 @@ export const registerJiraTools = (server) => {
333
309
  startAt,
334
310
  maxResults,
335
311
  });
336
- return {
337
- content: [
338
- {
339
- type: 'text',
340
- text: JSON.stringify(result),
341
- },
342
- ],
343
- };
312
+ return formatToolResponse(result, {
313
+ toolName: 'get-fields',
314
+ });
344
315
  }
345
316
  catch (error) {
346
317
  return {
@@ -362,14 +333,9 @@ export const registerJiraTools = (server) => {
362
333
  }, async ({ query, validation }) => {
363
334
  try {
364
335
  const result = await jiraService.parseJql(query, validation);
365
- return {
366
- content: [
367
- {
368
- type: 'text',
369
- text: JSON.stringify(result),
370
- },
371
- ],
372
- };
336
+ return formatToolResponse(result, {
337
+ toolName: 'parse-jql',
338
+ });
373
339
  }
374
340
  catch (error) {
375
341
  return {
@@ -413,14 +379,9 @@ export const registerJiraTools = (server) => {
413
379
  labels,
414
380
  additionalFields,
415
381
  });
416
- return {
417
- content: [
418
- {
419
- type: 'text',
420
- text: JSON.stringify(issue),
421
- },
422
- ],
423
- };
382
+ return formatToolResponse(issue, {
383
+ toolName: 'create-issue',
384
+ });
424
385
  }
425
386
  catch (error) {
426
387
  return {
@@ -523,14 +484,9 @@ export const registerJiraTools = (server) => {
523
484
  maxResults,
524
485
  property,
525
486
  });
526
- return {
527
- content: [
528
- {
529
- type: 'text',
530
- text: JSON.stringify(users),
531
- },
532
- ],
533
- };
487
+ return formatToolResponse(users, {
488
+ toolName: 'search-users',
489
+ });
534
490
  }
535
491
  catch (error) {
536
492
  return {
@@ -562,14 +518,9 @@ export const registerJiraTools = (server) => {
562
518
  avatarSize,
563
519
  excludeConnectUsers,
564
520
  });
565
- return {
566
- content: [
567
- {
568
- type: 'text',
569
- text: JSON.stringify(result),
570
- },
571
- ],
572
- };
521
+ return formatToolResponse(result, {
522
+ toolName: 'get-user-picker',
523
+ });
573
524
  }
574
525
  catch (error) {
575
526
  return {
@@ -599,14 +550,9 @@ export const registerJiraTools = (server) => {
599
550
  startAt,
600
551
  maxResults,
601
552
  });
602
- return {
603
- content: [
604
- {
605
- type: 'text',
606
- text: JSON.stringify(users),
607
- },
608
- ],
609
- };
553
+ return formatToolResponse(users, {
554
+ toolName: 'search-assignable-users',
555
+ });
610
556
  }
611
557
  catch (error) {
612
558
  return {
@@ -640,14 +586,9 @@ export const registerJiraTools = (server) => {
640
586
  startAt,
641
587
  maxResults,
642
588
  });
643
- return {
644
- content: [
645
- {
646
- type: 'text',
647
- text: JSON.stringify(users),
648
- },
649
- ],
650
- };
589
+ return formatToolResponse(users, {
590
+ toolName: 'search-users-by-permission',
591
+ });
651
592
  }
652
593
  catch (error) {
653
594
  return {
@@ -668,14 +609,9 @@ export const registerJiraTools = (server) => {
668
609
  }, async ({ expand }) => {
669
610
  try {
670
611
  const user = await jiraService.getMyself(expand);
671
- return {
672
- content: [
673
- {
674
- type: 'text',
675
- text: JSON.stringify(user),
676
- },
677
- ],
678
- };
612
+ return formatToolResponse(user, {
613
+ toolName: 'get-myself',
614
+ });
679
615
  }
680
616
  catch (error) {
681
617
  return {
@@ -709,14 +645,9 @@ export const registerJiraTools = (server) => {
709
645
  projectConfigurationUuid,
710
646
  commentId,
711
647
  });
712
- return {
713
- content: [
714
- {
715
- type: 'text',
716
- text: JSON.stringify(result),
717
- },
718
- ],
719
- };
648
+ return formatToolResponse(result, {
649
+ toolName: 'get-my-permissions',
650
+ });
720
651
  }
721
652
  catch (error) {
722
653
  return {
@@ -742,14 +673,9 @@ export const registerJiraTools = (server) => {
742
673
  timeZone,
743
674
  locale,
744
675
  });
745
- return {
746
- content: [
747
- {
748
- type: 'text',
749
- text: JSON.stringify(user),
750
- },
751
- ],
752
- };
676
+ return formatToolResponse(user, {
677
+ toolName: 'update-myself',
678
+ });
753
679
  }
754
680
  catch (error) {
755
681
  return {
@@ -767,14 +693,9 @@ export const registerJiraTools = (server) => {
767
693
  }, async ({ key }) => {
768
694
  try {
769
695
  const preferences = await jiraService.getMyPreferences(key);
770
- return {
771
- content: [
772
- {
773
- type: 'text',
774
- text: JSON.stringify(preferences),
775
- },
776
- ],
777
- };
696
+ return formatToolResponse(preferences, {
697
+ toolName: 'get-my-preferences',
698
+ });
778
699
  }
779
700
  catch (error) {
780
701
  return {
@@ -793,14 +714,9 @@ export const registerJiraTools = (server) => {
793
714
  }, async ({ key, value }) => {
794
715
  try {
795
716
  const result = await jiraService.updateMyPreferences(key, value);
796
- return {
797
- content: [
798
- {
799
- type: 'text',
800
- text: JSON.stringify(result),
801
- },
802
- ],
803
- };
717
+ return formatToolResponse(result, {
718
+ toolName: 'update-my-preferences',
719
+ });
804
720
  }
805
721
  catch (error) {
806
722
  return {
@@ -816,14 +732,9 @@ export const registerJiraTools = (server) => {
816
732
  server.tool('get-my-locale', "Get current user's locale setting", {}, async () => {
817
733
  try {
818
734
  const locale = await jiraService.getMyLocale();
819
- return {
820
- content: [
821
- {
822
- type: 'text',
823
- text: JSON.stringify(locale),
824
- },
825
- ],
826
- };
735
+ return formatToolResponse(locale, {
736
+ toolName: 'get-my-locale',
737
+ });
827
738
  }
828
739
  catch (error) {
829
740
  return {
@@ -841,14 +752,9 @@ export const registerJiraTools = (server) => {
841
752
  }, async ({ locale }) => {
842
753
  try {
843
754
  const result = await jiraService.updateMyLocale(locale);
844
- return {
845
- content: [
846
- {
847
- type: 'text',
848
- text: JSON.stringify(result),
849
- },
850
- ],
851
- };
755
+ return formatToolResponse(result, {
756
+ toolName: 'update-my-locale',
757
+ });
852
758
  }
853
759
  catch (error) {
854
760
  return {
@@ -864,14 +770,9 @@ export const registerJiraTools = (server) => {
864
770
  server.tool('get-priorities', 'Get all priorities', {}, async () => {
865
771
  try {
866
772
  const priorities = await jiraService.getPriorities();
867
- return {
868
- content: [
869
- {
870
- type: 'text',
871
- text: JSON.stringify(priorities),
872
- },
873
- ],
874
- };
773
+ return formatToolResponse(priorities, {
774
+ toolName: 'get-priorities',
775
+ });
875
776
  }
876
777
  catch (error) {
877
778
  return {
@@ -893,14 +794,9 @@ export const registerJiraTools = (server) => {
893
794
  }, async ({ issueKey, expand }) => {
894
795
  try {
895
796
  const result = await jiraService.getIssueTransitions(issueKey, expand);
896
- return {
897
- content: [
898
- {
899
- type: 'text',
900
- text: JSON.stringify(result),
901
- },
902
- ],
903
- };
797
+ return formatToolResponse(result, {
798
+ toolName: 'get-issue-transitions',
799
+ });
904
800
  }
905
801
  catch (error) {
906
802
  return {
@@ -972,14 +868,9 @@ export const registerJiraTools = (server) => {
972
868
  server.tool('get-statuses', 'Get all workflow statuses', {}, async () => {
973
869
  try {
974
870
  const statuses = await jiraService.getStatuses();
975
- return {
976
- content: [
977
- {
978
- type: 'text',
979
- text: JSON.stringify(statuses),
980
- },
981
- ],
982
- };
871
+ return formatToolResponse(statuses, {
872
+ toolName: 'get-statuses',
873
+ });
983
874
  }
984
875
  catch (error) {
985
876
  return {
@@ -997,14 +888,9 @@ export const registerJiraTools = (server) => {
997
888
  }, async ({ idOrName }) => {
998
889
  try {
999
890
  const status = await jiraService.getStatus(idOrName);
1000
- return {
1001
- content: [
1002
- {
1003
- type: 'text',
1004
- text: JSON.stringify(status),
1005
- },
1006
- ],
1007
- };
891
+ return formatToolResponse(status, {
892
+ toolName: 'get-status',
893
+ });
1008
894
  }
1009
895
  catch (error) {
1010
896
  return {
@@ -1032,14 +918,9 @@ export const registerJiraTools = (server) => {
1032
918
  projectId,
1033
919
  expand,
1034
920
  });
1035
- return {
1036
- content: [
1037
- {
1038
- type: 'text',
1039
- text: JSON.stringify(result),
1040
- },
1041
- ],
1042
- };
921
+ return formatToolResponse(result, {
922
+ toolName: 'search-statuses',
923
+ });
1043
924
  }
1044
925
  catch (error) {
1045
926
  return {
@@ -1057,14 +938,9 @@ export const registerJiraTools = (server) => {
1057
938
  }, async ({ id }) => {
1058
939
  try {
1059
940
  const priority = await jiraService.getPriority(id);
1060
- return {
1061
- content: [
1062
- {
1063
- type: 'text',
1064
- text: JSON.stringify(priority),
1065
- },
1066
- ],
1067
- };
941
+ return formatToolResponse(priority, {
942
+ toolName: 'get-priority',
943
+ });
1068
944
  }
1069
945
  catch (error) {
1070
946
  return {
@@ -1094,14 +970,9 @@ export const registerJiraTools = (server) => {
1094
970
  priorityName,
1095
971
  onlyDefault,
1096
972
  });
1097
- return {
1098
- content: [
1099
- {
1100
- type: 'text',
1101
- text: JSON.stringify(result),
1102
- },
1103
- ],
1104
- };
973
+ return formatToolResponse(result, {
974
+ toolName: 'search-priorities',
975
+ });
1105
976
  }
1106
977
  catch (error) {
1107
978
  return {
@@ -1138,14 +1009,9 @@ export const registerJiraTools = (server) => {
1138
1009
  visibility,
1139
1010
  properties: properties,
1140
1011
  });
1141
- return {
1142
- content: [
1143
- {
1144
- type: 'text',
1145
- text: JSON.stringify(comment),
1146
- },
1147
- ],
1148
- };
1012
+ return formatToolResponse(comment, {
1013
+ toolName: 'create-comment',
1014
+ });
1149
1015
  }
1150
1016
  catch (error) {
1151
1017
  return {
@@ -1183,14 +1049,9 @@ export const registerJiraTools = (server) => {
1183
1049
  visibility,
1184
1050
  properties: properties,
1185
1051
  });
1186
- return {
1187
- content: [
1188
- {
1189
- type: 'text',
1190
- text: JSON.stringify(comment),
1191
- },
1192
- ],
1193
- };
1052
+ return formatToolResponse(comment, {
1053
+ toolName: 'update-comment',
1054
+ });
1194
1055
  }
1195
1056
  catch (error) {
1196
1057
  return {
@@ -1258,14 +1119,9 @@ export const registerJiraTools = (server) => {
1258
1119
  server.tool('get-issue-link-types', 'Get available issue link types', {}, async () => {
1259
1120
  try {
1260
1121
  const result = await jiraService.getIssueLinkTypes();
1261
- return {
1262
- content: [
1263
- {
1264
- type: 'text',
1265
- text: JSON.stringify(result),
1266
- },
1267
- ],
1268
- };
1122
+ return formatToolResponse(result, {
1123
+ toolName: 'get-issue-link-types',
1124
+ });
1269
1125
  }
1270
1126
  catch (error) {
1271
1127
  return {
@@ -1283,14 +1139,9 @@ export const registerJiraTools = (server) => {
1283
1139
  }, async ({ issueLinkTypeId }) => {
1284
1140
  try {
1285
1141
  const result = await jiraService.getIssueLinkType(issueLinkTypeId);
1286
- return {
1287
- content: [
1288
- {
1289
- type: 'text',
1290
- text: JSON.stringify(result),
1291
- },
1292
- ],
1293
- };
1142
+ return formatToolResponse(result, {
1143
+ toolName: 'get-issue-link-type',
1144
+ });
1294
1145
  }
1295
1146
  catch (error) {
1296
1147
  return {
@@ -1393,14 +1244,9 @@ export const registerJiraTools = (server) => {
1393
1244
  }, async ({ linkId }) => {
1394
1245
  try {
1395
1246
  const result = await jiraService.getIssueLink(linkId);
1396
- return {
1397
- content: [
1398
- {
1399
- type: 'text',
1400
- text: JSON.stringify(result),
1401
- },
1402
- ],
1403
- };
1247
+ return formatToolResponse(result, {
1248
+ toolName: 'get-issue-link',
1249
+ });
1404
1250
  }
1405
1251
  catch (error) {
1406
1252
  return {
@@ -1443,14 +1289,11 @@ export const registerJiraTools = (server) => {
1443
1289
  }, async ({ issueKey }) => {
1444
1290
  try {
1445
1291
  const result = await jiraService.getIssueWithLinks(issueKey);
1446
- return {
1447
- content: [
1448
- {
1449
- type: 'text',
1450
- text: JSON.stringify(result),
1451
- },
1452
- ],
1453
- };
1292
+ const links = result.fields?.issuelinks ?? [];
1293
+ return formatToolResponse(result, {
1294
+ toolName: 'get-issue-with-links',
1295
+ summary: `Issue ${result.key}: ${result.fields?.summary ?? ''} with ${links.length} links`,
1296
+ });
1454
1297
  }
1455
1298
  catch (error) {
1456
1299
  return {
@@ -1468,14 +1311,9 @@ export const registerJiraTools = (server) => {
1468
1311
  }, async ({ issueKey }) => {
1469
1312
  try {
1470
1313
  const result = await jiraService.getIssueWatchers(issueKey);
1471
- return {
1472
- content: [
1473
- {
1474
- type: 'text',
1475
- text: JSON.stringify(result),
1476
- },
1477
- ],
1478
- };
1314
+ return formatToolResponse(result, {
1315
+ toolName: 'get-issue-watchers',
1316
+ });
1479
1317
  }
1480
1318
  catch (error) {
1481
1319
  return {
@@ -395,7 +395,7 @@ export class ConfluenceService extends BaseApiService {
395
395
  const { targetId, position } = options;
396
396
  return this.makeRequest(() => this.v1Client.put(`/content/${pageId}/move/${position}/${targetId}`, null, {
397
397
  headers: {
398
- 'Accept': 'application/json',
398
+ Accept: 'application/json',
399
399
  },
400
400
  }));
401
401
  }
@@ -0,0 +1,49 @@
1
+ import { writeFileSync, readdirSync, statSync, unlinkSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ const DEFAULT_THRESHOLD = 20_000;
6
+ const MAX_AGE_MS = 60 * 60 * 1000; // 1 hour
7
+ export function formatToolResponse(data, options) {
8
+ const text = typeof data === 'string' ? data : JSON.stringify(data);
9
+ const threshold = options.threshold ?? DEFAULT_THRESHOLD;
10
+ if (text.length <= threshold) {
11
+ return { content: [{ type: 'text', text }] };
12
+ }
13
+ const fileName = `atlassian-mcp-${options.toolName}-${Date.now()}-${randomUUID().slice(0, 8)}.json`;
14
+ const filePath = join(tmpdir(), fileName);
15
+ writeFileSync(filePath, text, 'utf-8');
16
+ const message = [
17
+ `Response too large (${text.length.toLocaleString()} chars). Full data saved to temporary file.`,
18
+ ``,
19
+ `File: ${filePath}`,
20
+ ``,
21
+ `Use the Read tool to read this file for full content.`,
22
+ options.summary ? `\nSummary: ${options.summary}` : '',
23
+ ]
24
+ .filter(Boolean)
25
+ .join('\n');
26
+ return { content: [{ type: 'text', text: message }] };
27
+ }
28
+ export function cleanupOldTempFiles() {
29
+ try {
30
+ const dir = tmpdir();
31
+ const files = readdirSync(dir).filter((f) => f.startsWith('atlassian-mcp-') && f.endsWith('.json'));
32
+ const now = Date.now();
33
+ for (const file of files) {
34
+ try {
35
+ const filePath = join(dir, file);
36
+ const stat = statSync(filePath);
37
+ if (now - stat.mtimeMs > MAX_AGE_MS) {
38
+ unlinkSync(filePath);
39
+ }
40
+ }
41
+ catch {
42
+ /* skip individual file errors */
43
+ }
44
+ }
45
+ }
46
+ catch {
47
+ /* non-critical, skip silently */
48
+ }
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecubelabs/atlassian-mcp",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "bin": "./dist/index.js",
5
5
  "repository": {
6
6
  "url": "https://github.com/Ecube-Labs/skynet.git"