@shortcut/mcp 0.10.1 → 0.10.3

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 (2) hide show
  1. package/dist/index.js +219 -93
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -53,11 +53,21 @@ var ShortcutClientWrapper = class {
53
53
  userCache;
54
54
  teamCache;
55
55
  workflowCache;
56
+ customFieldCache;
56
57
  constructor(client$1) {
57
58
  this.client = client$1;
58
59
  this.userCache = new Cache();
59
60
  this.teamCache = new Cache();
60
61
  this.workflowCache = new Cache();
62
+ this.customFieldCache = new Cache();
63
+ }
64
+ getNextPageToken(next) {
65
+ let next_page_token = null;
66
+ if (next) try {
67
+ const [, t] = /next=(.+)(?:&|$)/.exec(next) || [];
68
+ if (t) next_page_token = t;
69
+ } catch {}
70
+ return next_page_token;
61
71
  }
62
72
  async loadMembers() {
63
73
  if (this.userCache.isStale) {
@@ -80,6 +90,13 @@ var ShortcutClientWrapper = class {
80
90
  if (workflows) this.workflowCache.setMany(workflows.map((workflow) => [workflow.id, workflow]));
81
91
  }
82
92
  }
93
+ async loadCustomFields() {
94
+ if (this.customFieldCache.isStale) {
95
+ const response = await this.client.listCustomFields();
96
+ const customFields = response?.data ?? null;
97
+ if (customFields) this.customFieldCache.setMany(customFields.map((customField) => [customField.id, customField]));
98
+ }
99
+ }
83
100
  async getCurrentUser() {
84
101
  if (this.currentUser) return this.currentUser;
85
102
  const response = await this.client.getCurrentMemberInfo();
@@ -172,38 +189,46 @@ var ShortcutClientWrapper = class {
172
189
  if (!milestone) return null;
173
190
  return milestone;
174
191
  }
175
- async searchStories(query) {
192
+ async searchStories(query, nextToken) {
176
193
  const response = await this.client.searchStories({
177
194
  query,
178
195
  page_size: 25,
179
- detail: "full"
196
+ detail: "full",
197
+ next: nextToken
180
198
  });
181
199
  const stories = response?.data?.data;
182
200
  const total = response?.data?.total;
201
+ const next = response?.data?.next;
183
202
  if (!stories) return {
184
203
  stories: null,
185
- total: null
204
+ total: null,
205
+ next_page_token: null
186
206
  };
187
207
  return {
188
208
  stories,
189
- total
209
+ total,
210
+ next_page_token: this.getNextPageToken(next)
190
211
  };
191
212
  }
192
- async searchIterations(query) {
213
+ async searchIterations(query, nextToken) {
193
214
  const response = await this.client.searchIterations({
194
215
  query,
195
216
  page_size: 25,
196
- detail: "full"
217
+ detail: "full",
218
+ next: nextToken
197
219
  });
198
220
  const iterations = response?.data?.data;
199
221
  const total = response?.data?.total;
222
+ const next = response?.data?.next;
200
223
  if (!iterations) return {
201
224
  iterations: null,
202
- total: null
225
+ total: null,
226
+ next_page_token: null
203
227
  };
204
228
  return {
205
229
  iterations,
206
- total
230
+ total,
231
+ next_page_token: this.getNextPageToken(next)
207
232
  };
208
233
  }
209
234
  async getActiveIteration(teamIds) {
@@ -250,38 +275,46 @@ var ShortcutClientWrapper = class {
250
275
  }, /* @__PURE__ */ new Map());
251
276
  return upcomingIterationByTeam;
252
277
  }
253
- async searchEpics(query) {
278
+ async searchEpics(query, nextToken) {
254
279
  const response = await this.client.searchEpics({
255
280
  query,
256
281
  page_size: 25,
257
- detail: "full"
282
+ detail: "full",
283
+ next: nextToken
258
284
  });
259
285
  const epics = response?.data?.data;
260
286
  const total = response?.data?.total;
287
+ const next = response?.data?.next;
261
288
  if (!epics) return {
262
289
  epics: null,
263
- total: null
290
+ total: null,
291
+ next_page_token: null
264
292
  };
265
293
  return {
266
294
  epics,
267
- total
295
+ total,
296
+ next_page_token: this.getNextPageToken(next)
268
297
  };
269
298
  }
270
- async searchMilestones(query) {
299
+ async searchMilestones(query, nextToken) {
271
300
  const response = await this.client.searchMilestones({
272
301
  query,
273
302
  page_size: 25,
274
- detail: "full"
303
+ detail: "full",
304
+ next: nextToken
275
305
  });
276
306
  const milestones = response?.data?.data;
277
307
  const total = response?.data?.total;
308
+ const next = response?.data?.next;
278
309
  if (!milestones) return {
279
310
  milestones: null,
280
- total: null
311
+ total: null,
312
+ next_page_token: null
281
313
  };
282
314
  return {
283
315
  milestones,
284
- total
316
+ total,
317
+ next_page_token: this.getNextPageToken(next)
285
318
  };
286
319
  }
287
320
  async listIterationStories(iterationPublicId, includeDescription = false) {
@@ -389,12 +422,20 @@ var ShortcutClientWrapper = class {
389
422
  if (!doc) throw new Error(`Failed to create the document: ${response.status}`);
390
423
  return doc;
391
424
  }
425
+ async getCustomFieldMap(customFieldIds) {
426
+ await this.loadCustomFields();
427
+ return new Map(customFieldIds.map((id) => [id, this.customFieldCache.get(id)]).filter((customField) => customField[1] !== null));
428
+ }
429
+ async getCustomFields() {
430
+ await this.loadCustomFields();
431
+ return Array.from(this.customFieldCache.values());
432
+ }
392
433
  };
393
434
 
394
435
  //#endregion
395
436
  //#region package.json
396
437
  var name = "@shortcut/mcp";
397
- var version = "0.10.1";
438
+ var version = "0.10.3";
398
439
 
399
440
  //#endregion
400
441
  //#region src/tools/base.ts
@@ -448,9 +489,33 @@ var BaseTools = class {
448
489
  is_owner
449
490
  };
450
491
  }
451
- getSimplifiedStory(entity) {
492
+ getSimplifiedStory(entity, kind) {
452
493
  if (!entity) return null;
453
- const { id, name: name$1, app_url, archived, group_id, epic_id, iteration_id, workflow_id, workflow_state_id, owner_ids, requested_by_id } = entity;
494
+ const { id, name: name$1, app_url, archived, group_id, epic_id, iteration_id, workflow_id, workflow_state_id, owner_ids, requested_by_id, estimate, labels, comments, description, external_links, story_links, pull_requests, formatted_vcs_branch_name, branches, parent_story_id, sub_task_story_ids, tasks, custom_fields, blocked, blocker } = entity;
495
+ const additionalFields = {};
496
+ if (kind === "simple") {
497
+ additionalFields.description = description;
498
+ additionalFields.estimate = estimate ?? null;
499
+ additionalFields.comments = (comments || []).filter((c) => !c.deleted).map(({ id: id$1, author_id, text }) => ({
500
+ id: id$1,
501
+ author_id: author_id ?? null,
502
+ text: text ?? ""
503
+ }));
504
+ additionalFields.labels = (labels || []).map((l) => l.name);
505
+ additionalFields.external_links = external_links || [];
506
+ additionalFields.suggested_branch_name = formatted_vcs_branch_name ?? null;
507
+ additionalFields.pull_requests = (pull_requests || []).map((pr) => pr.url);
508
+ additionalFields.branches = (branches || []).map((b) => b.name);
509
+ additionalFields.related_stories = (story_links || []).map((sl) => sl.type === "object" ? sl.subject_id : sl.object_id);
510
+ additionalFields.tasks = (tasks || []).map((t) => ({
511
+ id: t.id,
512
+ description: t.description,
513
+ complete: t.complete
514
+ }));
515
+ additionalFields.custom_fields = (custom_fields || []).map((field) => field.value_id);
516
+ additionalFields.blocked = blocked;
517
+ additionalFields.blocker = blocker;
518
+ }
454
519
  return {
455
520
  id,
456
521
  name: name$1,
@@ -462,7 +527,10 @@ var BaseTools = class {
462
527
  workflow_id,
463
528
  workflow_state_id,
464
529
  owner_ids,
465
- requested_by_id
530
+ requested_by_id,
531
+ parent_story_id: parent_story_id ?? null,
532
+ sub_task_ids: sub_task_story_ids ?? [],
533
+ ...additionalFields
466
534
  };
467
535
  }
468
536
  getSimplifiedWorkflow(entity) {
@@ -502,9 +570,19 @@ var BaseTools = class {
502
570
  categories: categories.map((cat) => cat.name)
503
571
  };
504
572
  }
505
- getSimplifiedEpic(entity) {
573
+ getSimplifiedEpic(entity, kind) {
506
574
  if (!entity) return null;
507
- const { id, name: name$1, app_url, archived, group_id, state, milestone_id } = entity;
575
+ const { id, name: name$1, app_url, archived, group_id, state, milestone_id, comments, description, deadline, owner_ids } = entity;
576
+ const additionalFields = {};
577
+ if (kind === "simple") {
578
+ additionalFields.comments = (comments || []).filter((comment) => !comment.deleted).map(({ id: id$1, author_id, text }) => ({
579
+ id: id$1,
580
+ author_id,
581
+ text
582
+ }));
583
+ additionalFields.description = description;
584
+ additionalFields.deadline = deadline ?? null;
585
+ }
508
586
  return {
509
587
  id,
510
588
  name: name$1,
@@ -512,7 +590,9 @@ var BaseTools = class {
512
590
  archived,
513
591
  state,
514
592
  team_id: group_id || null,
515
- objective_id: milestone_id || null
593
+ objective_id: milestone_id || null,
594
+ owner_ids,
595
+ ...additionalFields
516
596
  };
517
597
  }
518
598
  getSimplifiedIteration(entity) {
@@ -534,8 +614,7 @@ var BaseTools = class {
534
614
  workflows: {}
535
615
  };
536
616
  const { member_ids, workflow_ids } = entity;
537
- const users = await this.client.getUserMap(member_ids);
538
- const workflows = await this.client.getWorkflowMap(workflow_ids);
617
+ const [users, workflows] = await Promise.all([this.client.getUserMap(member_ids), this.client.getWorkflowMap(workflow_ids)]);
539
618
  return {
540
619
  users: Object.fromEntries(member_ids.map((id) => this.getSimplifiedMember(users.get(id))).filter((member) => member !== null).map((member) => [member.id, member])),
541
620
  workflows: Object.fromEntries(workflow_ids.map((id) => this.getSimplifiedWorkflow(workflows.get(id))).filter((workflow) => workflow !== null).map((workflow) => [workflow.id, workflow]))
@@ -564,17 +643,21 @@ var BaseTools = class {
564
643
  teams: {},
565
644
  objectives: {}
566
645
  };
567
- const { group_id, owner_ids, milestone_id, requested_by_id, follower_ids } = entity;
568
- const usersForEpicMap = await this.client.getUserMap([...new Set([
569
- ...owner_ids || [],
570
- requested_by_id,
571
- ...follower_ids || []
572
- ].filter(Boolean))]);
646
+ const { group_id, owner_ids, milestone_id, requested_by_id, follower_ids, comments } = entity;
647
+ const [usersForEpicMap, teams, fullMilestone] = await Promise.all([
648
+ this.client.getUserMap([...new Set([
649
+ ...owner_ids || [],
650
+ requested_by_id,
651
+ ...follower_ids || [],
652
+ ...(comments || []).map((comment) => comment.author_id)
653
+ ].filter(Boolean))]),
654
+ this.client.getTeamMap(group_id ? [group_id] : []),
655
+ milestone_id ? this.client.getMilestone(milestone_id) : null
656
+ ]);
573
657
  const usersForEpic = Object.fromEntries([...usersForEpicMap.entries()].filter(([_, user$1]) => !!user$1).map(([id, user$1]) => [id, this.getSimplifiedMember(user$1)]));
574
- const teams = await this.client.getTeamMap(group_id ? [group_id] : []);
575
658
  const team = this.getSimplifiedTeam(teams.get(group_id || ""));
576
659
  const { users, workflows } = await this.getRelatedEntitiesForTeam(teams.get(group_id || ""));
577
- const milestone = this.getSimplifiedObjective(milestone_id ? await this.client.getMilestone(milestone_id) : null);
660
+ const milestone = this.getSimplifiedObjective(fullMilestone);
578
661
  return {
579
662
  users: this.mergeRelatedEntities([usersForEpic, users]),
580
663
  teams: team ? { [team.id]: team } : {},
@@ -582,20 +665,23 @@ var BaseTools = class {
582
665
  workflows
583
666
  };
584
667
  }
585
- async getRelatedEntitiesForStory(entity) {
586
- const { group_id, iteration_id, epic_id, owner_ids, requested_by_id, follower_ids, workflow_id } = entity;
587
- const fullUsersForStory = await this.client.getUserMap([...new Set([
588
- ...owner_ids || [],
589
- requested_by_id,
590
- ...follower_ids || []
591
- ].filter(Boolean))]);
668
+ async getRelatedEntitiesForStory(entity, kind) {
669
+ const { group_id, iteration_id, epic_id, owner_ids, requested_by_id, follower_ids, workflow_id, comments, custom_fields } = entity;
670
+ const [fullUsersForStory, teamsForStory, workflowsForStory, iteration, epic] = await Promise.all([
671
+ this.client.getUserMap([...new Set([
672
+ ...owner_ids || [],
673
+ requested_by_id,
674
+ ...follower_ids || [],
675
+ ...(comments || []).map((comment) => comment.author_id || "")
676
+ ].filter(Boolean))]),
677
+ this.client.getTeamMap(group_id ? [group_id] : []),
678
+ this.client.getWorkflowMap(workflow_id ? [workflow_id] : []),
679
+ iteration_id ? this.client.getIteration(iteration_id) : null,
680
+ epic_id ? this.client.getEpic(epic_id) : null
681
+ ]);
592
682
  const usersForStory = Object.fromEntries([...fullUsersForStory.entries()].filter(([_, user$1]) => !!user$1).map(([id, user$1]) => [id, this.getSimplifiedMember(user$1)]));
593
- const teamsForStory = await this.client.getTeamMap(group_id ? [group_id] : []);
594
- const workflowsForStory = await this.client.getWorkflowMap(workflow_id ? [workflow_id] : []);
595
- const iteration = iteration_id ? await this.client.getIteration(iteration_id) : null;
596
683
  const simplifiedIteration = this.getSimplifiedIteration(iteration);
597
- const epic = epic_id ? await this.client.getEpic(epic_id) : null;
598
- const simplifiedEpic = this.getSimplifiedEpic(epic);
684
+ const simplifiedEpic = this.getSimplifiedEpic(epic, kind);
599
685
  const teamForStory = teamsForStory.get(group_id || "");
600
686
  const workflowForStory = this.getSimplifiedWorkflow(workflowsForStory.get(workflow_id));
601
687
  const { users: usersForTeam, workflows: workflowsForTeam } = await this.getRelatedEntitiesForTeam(teamForStory);
@@ -620,49 +706,67 @@ var BaseTools = class {
620
706
  ]);
621
707
  const epics = simplifiedEpic ? { [simplifiedEpic.id]: simplifiedEpic } : {};
622
708
  const iterations = simplifiedIteration ? { [simplifiedIteration.id]: simplifiedIteration } : {};
709
+ const relatedCustomFields = {};
710
+ if (custom_fields?.length) {
711
+ const customFieldMap = await this.client.getCustomFieldMap(custom_fields.map((cf) => cf.field_id));
712
+ custom_fields.forEach((cf) => {
713
+ const field = customFieldMap.get(cf.field_id);
714
+ if (!field) return;
715
+ const value = field.values?.find((v) => v.id === cf.value_id);
716
+ if (!value) return;
717
+ relatedCustomFields[cf.value_id] = {
718
+ field_id: cf.field_id,
719
+ value_id: cf.value_id,
720
+ field_name: field.name,
721
+ value_name: value.value
722
+ };
723
+ });
724
+ }
623
725
  return {
624
726
  users,
625
727
  epics,
626
728
  iterations,
627
729
  workflows,
628
730
  teams,
629
- objectives
731
+ objectives,
732
+ custom_fields: relatedCustomFields
630
733
  };
631
734
  }
632
- async getRelatedEntities(entity) {
735
+ async getRelatedEntities(entity, kind) {
633
736
  if (entity.entity_type === "group") return this.getRelatedEntitiesForTeam(entity);
634
737
  if (entity.entity_type === "iteration") return this.getRelatedEntitiesForIteration(entity);
635
738
  if (entity.entity_type === "epic") return this.getRelatedEntitiesForEpic(entity);
636
- if (entity.entity_type === "story") return this.getRelatedEntitiesForStory(entity);
739
+ if (entity.entity_type === "story") return this.getRelatedEntitiesForStory(entity, kind);
637
740
  return {};
638
741
  }
639
- getSimplifiedEntity(entity) {
742
+ getSimplifiedEntity(entity, kind) {
640
743
  if (entity.entity_type === "group") return this.getSimplifiedTeam(entity);
641
744
  if (entity.entity_type === "iteration") return this.getSimplifiedIteration(entity);
642
- if (entity.entity_type === "epic") return this.getSimplifiedEpic(entity);
643
- if (entity.entity_type === "story") return this.getSimplifiedStory(entity);
745
+ if (entity.entity_type === "epic") return this.getSimplifiedEpic(entity, kind);
746
+ if (entity.entity_type === "story") return this.getSimplifiedStory(entity, kind);
644
747
  if (entity.entity_type === "milestone") return this.getSimplifiedObjective(entity);
645
748
  if (entity.entity_type === "workflow") return this.getSimplifiedWorkflow(entity);
646
749
  return entity;
647
750
  }
648
- async entityWithRelatedEntities(entity, entityType = "entity") {
649
- const relatedEntities = await this.getRelatedEntities(entity);
751
+ async entityWithRelatedEntities(entity, entityType = "entity", full = false) {
752
+ const finalEntity = full ? entity : this.getSimplifiedEntity(entity, "simple");
753
+ const relatedEntities = await this.getRelatedEntities(entity, full ? "full" : "simple");
650
754
  return {
651
- [entityType]: this.renameEntityProps(entity),
755
+ [entityType]: this.renameEntityProps(finalEntity),
652
756
  relatedEntities
653
757
  };
654
758
  }
655
759
  async entitiesWithRelatedEntities(entities, entityType = "entities") {
656
- const relatedEntities = await Promise.all(entities.map((entity) => this.getRelatedEntities(entity)));
760
+ const relatedEntities = await Promise.all(entities.map((entity) => this.getRelatedEntities(entity, "list")));
657
761
  return {
658
- [entityType]: entities.map((entity) => this.getSimplifiedEntity(entity)),
762
+ [entityType]: entities.map((entity) => this.getSimplifiedEntity(entity, "list")),
659
763
  relatedEntities: this.mergeRelatedEntities(relatedEntities)
660
764
  };
661
765
  }
662
- toResult(message, data) {
766
+ toResult(message, data, paginationToken) {
663
767
  return { content: [{
664
768
  type: "text",
665
- text: `${message}${data !== void 0 ? `\n\n${JSON.stringify(data, null, 2)}` : ""}`
769
+ text: `${message}${data !== void 0 ? `\n\n<json>\n${JSON.stringify(data, null, 2)}\n</json>${paginationToken ? `\n\n<next-page-token>${paginationToken}</next-page-token>` : ""}` : ""}`
666
770
  }] };
667
771
  }
668
772
  };
@@ -755,8 +859,12 @@ const user = (field) => z.string().optional().describe(`Find entities where the
755
859
  var EpicTools = class EpicTools extends BaseTools {
756
860
  static create(client$1, server$1) {
757
861
  const tools = new EpicTools(client$1);
758
- server$1.tool("get-epic", "Get a Shortcut epic by public ID", { epicPublicId: z.number().positive().describe("The public ID of the epic to get") }, async ({ epicPublicId }) => await tools.getEpic(epicPublicId));
862
+ server$1.tool("get-epic", "Get a Shortcut epic by public ID", {
863
+ epicPublicId: z.number().positive().describe("The public ID of the epic to get"),
864
+ full: z.boolean().optional().default(false).describe("True to return all epic fields from the API. False to return a slim version that excludes uncommon fields")
865
+ }, async ({ epicPublicId, full }) => await tools.getEpic(epicPublicId, full));
759
866
  server$1.tool("search-epics", "Find Shortcut epics.", {
867
+ nextPageToken: z.string().optional().describe("If a next_page_token was returned from the search result, pass it in to get the next page of results. Should be combined with the original search parameters."),
760
868
  id: z.number().optional().describe("Find only epics with the specified public ID"),
761
869
  name: z.string().optional().describe("Find only epics matching the specified name"),
762
870
  description: z.string().optional().describe("Find only epics matching the specified description"),
@@ -783,7 +891,7 @@ var EpicTools = class EpicTools extends BaseTools {
783
891
  updated: date(),
784
892
  completed: date(),
785
893
  due: date()
786
- }, async (params) => await tools.searchEpics(params));
894
+ }, async ({ nextPageToken,...params }) => await tools.searchEpics(params, nextPageToken));
787
895
  server$1.tool("create-epic", "Create a new Shortcut epic.", {
788
896
  name: z.string().describe("The name of the epic"),
789
897
  owner: z.string().optional().describe("The user ID of the owner of the epic"),
@@ -792,18 +900,18 @@ var EpicTools = class EpicTools extends BaseTools {
792
900
  }, async (params) => await tools.createEpic(params));
793
901
  return tools;
794
902
  }
795
- async searchEpics(params) {
903
+ async searchEpics(params, nextToken) {
796
904
  const currentUser = await this.client.getCurrentUser();
797
905
  const query = await buildSearchQuery(params, currentUser);
798
- const { epics, total } = await this.client.searchEpics(query);
906
+ const { epics, total, next_page_token } = await this.client.searchEpics(query, nextToken);
799
907
  if (!epics) throw new Error(`Failed to search for epics matching your query: "${query}"`);
800
908
  if (!epics.length) return this.toResult(`Result: No epics found.`);
801
- return this.toResult(`Result (first ${epics.length} shown of ${total} total epics found):`, await this.entitiesWithRelatedEntities(epics, "epics"));
909
+ return this.toResult(`Result (${epics.length} shown of ${total} total epics found):`, await this.entitiesWithRelatedEntities(epics, "epics"), next_page_token);
802
910
  }
803
- async getEpic(epicPublicId) {
911
+ async getEpic(epicPublicId, full = false) {
804
912
  const epic = await this.client.getEpic(epicPublicId);
805
913
  if (!epic) throw new Error(`Failed to retrieve Shortcut epic with public ID: ${epicPublicId}`);
806
- return this.toResult(`Epic: ${epicPublicId}`, await this.entityWithRelatedEntities(epic, "epic"));
914
+ return this.toResult(`Epic: ${epicPublicId}`, await this.entityWithRelatedEntities(epic, "epic", full));
807
915
  }
808
916
  async createEpic({ name: name$1, owner, teamId: group_id, description }) {
809
917
  const epic = await this.client.createEpic({
@@ -825,8 +933,12 @@ var IterationTools = class IterationTools extends BaseTools {
825
933
  iterationPublicId: z.number().positive().describe("The public ID of the iteration"),
826
934
  includeStoryDescriptions: z.boolean().optional().default(false).describe("Indicate whether story descriptions should be included. Including descriptions may take longer and will increase the size of the response.")
827
935
  }, async ({ iterationPublicId, includeStoryDescriptions }) => await tools.getIterationStories(iterationPublicId, includeStoryDescriptions));
828
- server$1.tool("get-iteration", "Get a Shortcut iteration by public ID", { iterationPublicId: z.number().positive().describe("The public ID of the iteration to get") }, async ({ iterationPublicId }) => await tools.getIteration(iterationPublicId));
936
+ server$1.tool("get-iteration", "Get a Shortcut iteration by public ID", {
937
+ iterationPublicId: z.number().positive().describe("The public ID of the iteration to get"),
938
+ full: z.boolean().optional().default(false).describe("True to return all iteration fields from the API. False to return a slim version that excludes uncommon fields")
939
+ }, async ({ iterationPublicId, full }) => await tools.getIteration(iterationPublicId, full));
829
940
  server$1.tool("search-iterations", "Find Shortcut iterations.", {
941
+ nextPageToken: z.string().optional().describe("If a next_page_token was returned from the search result, pass it in to get the next page of results. Should be combined with the original search parameters."),
830
942
  id: z.number().optional().describe("Find only iterations with the specified public ID"),
831
943
  name: z.string().optional().describe("Find only iterations matching the specified name"),
832
944
  description: z.string().optional().describe("Find only iterations matching the specified description"),
@@ -840,7 +952,7 @@ var IterationTools = class IterationTools extends BaseTools {
840
952
  updated: date(),
841
953
  startDate: date(),
842
954
  endDate: date()
843
- }, async (params) => await tools.searchIterations(params));
955
+ }, async ({ nextPageToken,...params }) => await tools.searchIterations(params, nextPageToken));
844
956
  server$1.tool("create-iteration", "Create a new Shortcut iteration", {
845
957
  name: z.string().describe("The name of the iteration"),
846
958
  startDate: z.string().describe("The start date of the iteration in YYYY-MM-DD format"),
@@ -857,18 +969,18 @@ var IterationTools = class IterationTools extends BaseTools {
857
969
  if (!stories) throw new Error(`Failed to retrieve Shortcut stories in iteration with public ID: ${iterationPublicId}.`);
858
970
  return this.toResult(`Result (${stories.length} stories found):`, await this.entitiesWithRelatedEntities(stories, "stories"));
859
971
  }
860
- async searchIterations(params) {
972
+ async searchIterations(params, nextToken) {
861
973
  const currentUser = await this.client.getCurrentUser();
862
974
  const query = await buildSearchQuery(params, currentUser);
863
- const { iterations, total } = await this.client.searchIterations(query);
975
+ const { iterations, total, next_page_token } = await this.client.searchIterations(query, nextToken);
864
976
  if (!iterations) throw new Error(`Failed to search for iterations matching your query: "${query}".`);
865
977
  if (!iterations.length) return this.toResult(`Result: No iterations found.`);
866
- return this.toResult(`Result (first ${iterations.length} shown of ${total} total iterations found):`, await this.entitiesWithRelatedEntities(iterations, "iterations"));
978
+ return this.toResult(`Result (${iterations.length} shown of ${total} total iterations found):`, await this.entitiesWithRelatedEntities(iterations, "iterations"), next_page_token);
867
979
  }
868
- async getIteration(iterationPublicId) {
980
+ async getIteration(iterationPublicId, full = false) {
869
981
  const iteration = await this.client.getIteration(iterationPublicId);
870
982
  if (!iteration) throw new Error(`Failed to retrieve Shortcut iteration with public ID: ${iterationPublicId}.`);
871
- return this.toResult(`Iteration: ${iterationPublicId}`, await this.entityWithRelatedEntities(iteration, "iteration"));
983
+ return this.toResult(`Iteration: ${iterationPublicId}`, await this.entityWithRelatedEntities(iteration, "iteration", full));
872
984
  }
873
985
  async createIteration({ name: name$1, startDate, endDate, teamId, description }) {
874
986
  const iteration = await this.client.createIteration({
@@ -928,8 +1040,12 @@ var IterationTools = class IterationTools extends BaseTools {
928
1040
  var ObjectiveTools = class ObjectiveTools extends BaseTools {
929
1041
  static create(client$1, server$1) {
930
1042
  const tools = new ObjectiveTools(client$1);
931
- server$1.tool("get-objective", "Get a Shortcut objective by public ID", { objectivePublicId: z.number().positive().describe("The public ID of the objective to get") }, async ({ objectivePublicId }) => await tools.getObjective(objectivePublicId));
1043
+ server$1.tool("get-objective", "Get a Shortcut objective by public ID", {
1044
+ objectivePublicId: z.number().positive().describe("The public ID of the objective to get"),
1045
+ full: z.boolean().optional().default(false).describe("True to return all objective fields from the API. False to return a slim version that excludes uncommon fields")
1046
+ }, async ({ objectivePublicId, full }) => await tools.getObjective(objectivePublicId, full));
932
1047
  server$1.tool("search-objectives", "Find Shortcut objectives.", {
1048
+ nextPageToken: z.string().optional().describe("If a next_page_token was returned from the search result, pass it in to get the next page of results. Should be combined with the original search parameters."),
933
1049
  id: z.number().optional().describe("Find objectives matching the specified id"),
934
1050
  name: z.string().optional().describe("Find objectives matching the specified name"),
935
1051
  description: z.string().optional().describe("Find objectives matching the specified description"),
@@ -949,21 +1065,21 @@ var ObjectiveTools = class ObjectiveTools extends BaseTools {
949
1065
  created: date(),
950
1066
  updated: date(),
951
1067
  completed: date()
952
- }, async (params) => await tools.searchObjectives(params));
1068
+ }, async ({ nextPageToken,...params }) => await tools.searchObjectives(params, nextPageToken));
953
1069
  return tools;
954
1070
  }
955
- async searchObjectives(params) {
1071
+ async searchObjectives(params, nextToken) {
956
1072
  const currentUser = await this.client.getCurrentUser();
957
1073
  const query = await buildSearchQuery(params, currentUser);
958
- const { milestones, total } = await this.client.searchMilestones(query);
1074
+ const { milestones, total, next_page_token } = await this.client.searchMilestones(query, nextToken);
959
1075
  if (!milestones) throw new Error(`Failed to search for milestones matching your query: "${query}"`);
960
1076
  if (!milestones.length) return this.toResult(`Result: No milestones found.`);
961
- return this.toResult(`Result (first ${milestones.length} shown of ${total} total milestones found):`, await this.entitiesWithRelatedEntities(milestones, "objectives"));
1077
+ return this.toResult(`Result (${milestones.length} shown of ${total} total milestones found):`, await this.entitiesWithRelatedEntities(milestones, "objectives"), next_page_token);
962
1078
  }
963
- async getObjective(objectivePublicId) {
1079
+ async getObjective(objectivePublicId, full = false) {
964
1080
  const objective = await this.client.getMilestone(objectivePublicId);
965
1081
  if (!objective) throw new Error(`Failed to retrieve Shortcut objective with public ID: ${objectivePublicId}`);
966
- return this.toResult(`Objective: ${objectivePublicId}`, await this.entityWithRelatedEntities(objective, "objective"));
1082
+ return this.toResult(`Objective: ${objectivePublicId}`, await this.entityWithRelatedEntities(objective, "objective", full));
967
1083
  }
968
1084
  };
969
1085
 
@@ -972,9 +1088,12 @@ var ObjectiveTools = class ObjectiveTools extends BaseTools {
972
1088
  var StoryTools = class StoryTools extends BaseTools {
973
1089
  static create(client$1, server$1) {
974
1090
  const tools = new StoryTools(client$1);
975
- server$1.tool("get-story-branch-name", "Get a valid branch name for a specific story.", { storyPublicId: z.number().positive().describe("The public Id of the story") }, async ({ storyPublicId }) => await tools.getStoryBranchName(storyPublicId));
976
- server$1.tool("get-story", "Get a Shortcut story by public ID", { storyPublicId: z.number().positive().describe("The public ID of the story to get") }, async ({ storyPublicId }) => await tools.getStory(storyPublicId));
1091
+ server$1.tool("get-story", "Get a Shortcut story by public ID", {
1092
+ storyPublicId: z.number().positive().describe("The public ID of the story to get"),
1093
+ full: z.boolean().optional().default(false).describe("True to return all story fields from the API. False to return a slim version that excludes uncommon fields")
1094
+ }, async ({ storyPublicId, full }) => await tools.getStory(storyPublicId, full));
977
1095
  server$1.tool("search-stories", "Find Shortcut stories.", {
1096
+ nextPageToken: z.string().optional().describe("If a next_page_token was returned from the search result, pass it in to get the next page of results. Should be combined with the original search parameters."),
978
1097
  id: z.number().optional().describe("Find only stories with the specified public ID"),
979
1098
  name: z.string().optional().describe("Find only stories matching the specified name"),
980
1099
  description: z.string().optional().describe("Find only stories matching the specified description"),
@@ -1023,7 +1142,8 @@ var StoryTools = class StoryTools extends BaseTools {
1023
1142
  updated: date(),
1024
1143
  completed: date(),
1025
1144
  due: date()
1026
- }, async (params) => await tools.searchStories(params));
1145
+ }, async ({ nextPageToken,...params }) => await tools.searchStories(params, nextPageToken));
1146
+ server$1.tool("get-story-branch-name", "Get a valid branch name for a specific story.", { storyPublicId: z.number().positive().describe("The public Id of the story") }, async ({ storyPublicId }) => await tools.getStoryBranchName(storyPublicId));
1027
1147
  server$1.tool("create-story", `Create a new Shortcut story.
1028
1148
  Name is required, and either a Team or Workflow must be specified:
1029
1149
  - If only Team is specified, we will use the default workflow for that team.
@@ -1166,18 +1286,18 @@ The story will be added to the default state for the workflow.
1166
1286
  });
1167
1287
  return this.toResult(`Created story: ${story.id}`);
1168
1288
  }
1169
- async searchStories(params) {
1289
+ async searchStories(params, nextToken) {
1170
1290
  const currentUser = await this.client.getCurrentUser();
1171
1291
  const query = await buildSearchQuery(params, currentUser);
1172
- const { stories, total } = await this.client.searchStories(query);
1292
+ const { stories, total, next_page_token } = await this.client.searchStories(query, nextToken);
1173
1293
  if (!stories) throw new Error(`Failed to search for stories matching your query: "${query}".`);
1174
1294
  if (!stories.length) return this.toResult(`Result: No stories found.`);
1175
- return this.toResult(`Result (first ${stories.length} shown of ${total} total stories found):`, await this.entitiesWithRelatedEntities(stories, "stories"));
1295
+ return this.toResult(`Result (${stories.length} shown of ${total} total stories found):`, await this.entitiesWithRelatedEntities(stories, "stories"), next_page_token);
1176
1296
  }
1177
- async getStory(storyPublicId) {
1297
+ async getStory(storyPublicId, full = false) {
1178
1298
  const story = await this.client.getStory(storyPublicId);
1179
1299
  if (!story) throw new Error(`Failed to retrieve Shortcut story with public ID: ${storyPublicId}.`);
1180
- return this.toResult(`Story: sc-${storyPublicId}`, await this.entityWithRelatedEntities(story, "story"));
1300
+ return this.toResult(`Story: sc-${storyPublicId}`, await this.entityWithRelatedEntities(story, "story", full));
1181
1301
  }
1182
1302
  async createStoryComment({ storyPublicId, text }) {
1183
1303
  if (!storyPublicId) throw new Error("Story public ID is required");
@@ -1285,14 +1405,17 @@ The story will be added to the default state for the workflow.
1285
1405
  var TeamTools = class TeamTools extends BaseTools {
1286
1406
  static create(client$1, server$1) {
1287
1407
  const tools = new TeamTools(client$1);
1288
- server$1.tool("get-team", "Get a Shortcut team by public ID", { teamPublicId: z.string().describe("The public ID of the team to get") }, async ({ teamPublicId }) => await tools.getTeam(teamPublicId));
1408
+ server$1.tool("get-team", "Get a Shortcut team by public ID", {
1409
+ teamPublicId: z.string().describe("The public ID of the team to get"),
1410
+ full: z.boolean().optional().default(false).describe("True to return all team fields from the API. False to return a slim version that excludes uncommon fields")
1411
+ }, async ({ teamPublicId, full }) => await tools.getTeam(teamPublicId, full));
1289
1412
  server$1.tool("list-teams", "List all Shortcut teams", async () => await tools.getTeams());
1290
1413
  return tools;
1291
1414
  }
1292
- async getTeam(teamPublicId) {
1415
+ async getTeam(teamPublicId, full = false) {
1293
1416
  const team = await this.client.getTeam(teamPublicId);
1294
1417
  if (!team) return this.toResult(`Team with public ID: ${teamPublicId} not found.`);
1295
- return this.toResult(`Team: ${team.id}`, await this.entityWithRelatedEntities(team, "team"));
1418
+ return this.toResult(`Team: ${team.id}`, await this.entityWithRelatedEntities(team, "team", full));
1296
1419
  }
1297
1420
  async getTeams() {
1298
1421
  const teams = await this.client.getTeams();
@@ -1326,14 +1449,17 @@ var UserTools = class UserTools extends BaseTools {
1326
1449
  var WorkflowTools = class WorkflowTools extends BaseTools {
1327
1450
  static create(client$1, server$1) {
1328
1451
  const tools = new WorkflowTools(client$1);
1329
- server$1.tool("get-workflow", "Get a Shortcut workflow by public ID", { workflowPublicId: z.number().positive().describe("The public ID of the workflow to get") }, async ({ workflowPublicId }) => await tools.getWorkflow(workflowPublicId));
1452
+ server$1.tool("get-workflow", "Get a Shortcut workflow by public ID", {
1453
+ workflowPublicId: z.number().positive().describe("The public ID of the workflow to get"),
1454
+ full: z.boolean().optional().default(false).describe("True to return all workflow fields from the API. False to return a slim version that excludes uncommon fields")
1455
+ }, async ({ workflowPublicId, full }) => await tools.getWorkflow(workflowPublicId, full));
1330
1456
  server$1.tool("list-workflows", "List all Shortcut workflows", async () => await tools.listWorkflows());
1331
1457
  return tools;
1332
1458
  }
1333
- async getWorkflow(workflowPublicId) {
1459
+ async getWorkflow(workflowPublicId, full = false) {
1334
1460
  const workflow = await this.client.getWorkflow(workflowPublicId);
1335
1461
  if (!workflow) return this.toResult(`Workflow with public ID: ${workflowPublicId} not found.`);
1336
- return this.toResult(`Workflow: ${workflow.id}`, await this.entityWithRelatedEntities(workflow, "workflow"));
1462
+ return this.toResult(`Workflow: ${workflow.id}`, await this.entityWithRelatedEntities(workflow, "workflow", full));
1337
1463
  }
1338
1464
  async listWorkflows() {
1339
1465
  const workflows = await this.client.getWorkflows();
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "modelcontextprotocol"
13
13
  ],
14
14
  "license": "MIT",
15
- "version": "0.10.1",
15
+ "version": "0.10.3",
16
16
  "type": "module",
17
17
  "main": "dist/index.js",
18
18
  "bin": {