@shortcut/mcp 0.6.0 → 0.7.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 (2) hide show
  1. package/dist/index.js +142 -265
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14602,10 +14602,12 @@ class ShortcutClientWrapper {
14602
14602
  client;
14603
14603
  currentUser = null;
14604
14604
  userCache;
14605
+ teamCache;
14605
14606
  workflowCache;
14606
14607
  constructor(client) {
14607
14608
  this.client = client;
14608
14609
  this.userCache = new Cache;
14610
+ this.teamCache = new Cache;
14609
14611
  this.workflowCache = new Cache;
14610
14612
  }
14611
14613
  async loadMembers() {
@@ -14617,6 +14619,15 @@ class ShortcutClientWrapper {
14617
14619
  }
14618
14620
  }
14619
14621
  }
14622
+ async loadTeams() {
14623
+ if (this.teamCache.isStale) {
14624
+ const response = await this.client.listGroups();
14625
+ const groups = response?.data ?? null;
14626
+ if (groups) {
14627
+ this.teamCache.setMany(groups.map((group) => [group.id, group]));
14628
+ }
14629
+ }
14630
+ }
14620
14631
  async loadWorkflows() {
14621
14632
  if (this.workflowCache.isStale) {
14622
14633
  const response = await this.client.listWorkflows();
@@ -14672,9 +14683,13 @@ class ShortcutClientWrapper {
14672
14683
  return workflow;
14673
14684
  }
14674
14685
  async getTeams() {
14675
- const response = await this.client.listGroups();
14676
- const groups = response?.data ?? [];
14677
- return groups;
14686
+ await this.loadTeams();
14687
+ const teams = Array.from(this.teamCache.values());
14688
+ return teams;
14689
+ }
14690
+ async getTeamMap(teamIds) {
14691
+ await this.loadTeams();
14692
+ return new Map(teamIds.map((id) => [id, this.teamCache.get(id)]).filter((team) => team[1] !== null));
14678
14693
  }
14679
14694
  async getTeam(teamPublicId) {
14680
14695
  const response = await this.client.getGroup(teamPublicId);
@@ -14726,7 +14741,7 @@ class ShortcutClientWrapper {
14726
14741
  return milestone;
14727
14742
  }
14728
14743
  async searchStories(query) {
14729
- const response = await this.client.searchStories({ query, page_size: 25, detail: "slim" });
14744
+ const response = await this.client.searchStories({ query, page_size: 25, detail: "full" });
14730
14745
  const stories = response?.data?.data;
14731
14746
  const total = response?.data?.total;
14732
14747
  if (!stories)
@@ -14734,7 +14749,7 @@ class ShortcutClientWrapper {
14734
14749
  return { stories, total };
14735
14750
  }
14736
14751
  async searchIterations(query) {
14737
- const response = await this.client.searchIterations({ query, page_size: 25, detail: "slim" });
14752
+ const response = await this.client.searchIterations({ query, page_size: 25, detail: "full" });
14738
14753
  const iterations = response?.data?.data;
14739
14754
  const total = response?.data?.total;
14740
14755
  if (!iterations)
@@ -14742,7 +14757,7 @@ class ShortcutClientWrapper {
14742
14757
  return { iterations, total };
14743
14758
  }
14744
14759
  async searchEpics(query) {
14745
- const response = await this.client.searchEpics({ query, page_size: 25, detail: "slim" });
14760
+ const response = await this.client.searchEpics({ query, page_size: 25, detail: "full" });
14746
14761
  const epics = response?.data?.data;
14747
14762
  const total = response?.data?.total;
14748
14763
  if (!epics)
@@ -14750,7 +14765,7 @@ class ShortcutClientWrapper {
14750
14765
  return { epics, total };
14751
14766
  }
14752
14767
  async searchMilestones(query) {
14753
- const response = await this.client.searchMilestones({ query, page_size: 25, detail: "slim" });
14768
+ const response = await this.client.searchMilestones({ query, page_size: 25, detail: "full" });
14754
14769
  const milestones = response?.data?.data;
14755
14770
  const total = response?.data?.total;
14756
14771
  if (!milestones)
@@ -21563,7 +21578,7 @@ var import_client = __toESM(require_lib(), 1);
21563
21578
 
21564
21579
  // package.json
21565
21580
  var name = "@shortcut/mcp";
21566
- var version = "0.6.0";
21581
+ var version = "0.7.0";
21567
21582
 
21568
21583
  // src/tools/base.ts
21569
21584
  class BaseTools {
@@ -21571,146 +21586,116 @@ class BaseTools {
21571
21586
  constructor(client) {
21572
21587
  this.client = client;
21573
21588
  }
21574
- toResult(content) {
21575
- return { content: [{ type: "text", text: content }] };
21589
+ async correctMember(entity) {
21590
+ if (!entity)
21591
+ return null;
21592
+ const {
21593
+ id,
21594
+ disabled,
21595
+ role,
21596
+ profile: { name: name2, email_address, mention_name }
21597
+ } = entity;
21598
+ return { id, name: name2, email_address, mention_name, role, disabled };
21599
+ }
21600
+ async correctWorkflow(entity) {
21601
+ if (!entity)
21602
+ return null;
21603
+ const { team_id, ...withoutTeam } = entity;
21604
+ return { ...withoutTeam };
21576
21605
  }
21577
- }
21606
+ async correctTeam(entity) {
21607
+ if (!entity)
21608
+ return null;
21609
+ const { member_ids, workflow_ids, ...withoutIds } = entity;
21610
+ const users = await this.client.getUserMap(member_ids);
21611
+ const workflows = await this.client.getWorkflowMap(workflow_ids);
21612
+ const correctedEntity = {
21613
+ ...withoutIds,
21614
+ members: await Promise.all(member_ids.map((id) => this.correctMember(users.get(id))).filter(Boolean)),
21615
+ workflows: await Promise.all(workflow_ids.map((id) => this.correctWorkflow(workflows.get(id))).filter(Boolean))
21616
+ };
21617
+ return correctedEntity;
21618
+ }
21619
+ async correctIteration(entity) {
21620
+ if (!entity)
21621
+ return null;
21622
+ const { group_ids, ...withoutGroupIds } = entity;
21623
+ const teams = await this.client.getTeamMap(group_ids?.filter(Boolean));
21624
+ const correctedEntity = {
21625
+ ...withoutGroupIds,
21626
+ teams: await Promise.all(group_ids?.map((id) => this.correctTeam(teams.get(id)))?.filter(Boolean) ?? [])
21627
+ };
21628
+ return correctedEntity;
21629
+ }
21630
+ async correctMilestone(entity) {
21631
+ return entity;
21632
+ }
21633
+ async correctEpic(entity) {
21634
+ const { group_id, owner_ids, requested_by_id, follower_ids, ...withoutIds } = entity;
21635
+ const users = await this.client.getUserMap([
21636
+ ...new Set([...owner_ids, requested_by_id, ...follower_ids])
21637
+ ]);
21638
+ const teams = await this.client.getTeamMap(group_id ? [group_id] : []);
21639
+ const correctedEntity = {
21640
+ ...withoutIds,
21641
+ owners: (await Promise.all(owner_ids?.map((id) => this.correctMember(users.get(id))))).filter(Boolean) ?? [],
21642
+ requested_by: requested_by_id ? await this.correctMember(users.get(requested_by_id)) : null,
21643
+ followers: (await Promise.all(follower_ids?.map((id) => this.correctMember(users.get(id))))).filter(Boolean) ?? [],
21644
+ team: group_id ? await this.correctTeam(teams.get(group_id)) : null
21645
+ };
21646
+ return correctedEntity;
21647
+ }
21648
+ async correctStory(entity) {
21649
+ const { group_id, owner_ids, requested_by_id, follower_ids, workflow_id, ...withoutIds } = entity;
21650
+ const users = await this.client.getUserMap([
21651
+ ...new Set([...owner_ids, requested_by_id, ...follower_ids])
21652
+ ]);
21653
+ const teams = await this.client.getTeamMap(group_id ? [group_id] : []);
21654
+ const workflows = await this.client.getWorkflowMap(workflow_id ? [workflow_id] : []);
21655
+ const correctedEntity = {
21656
+ ...withoutIds,
21657
+ owners: (await Promise.all(owner_ids?.map((id) => this.correctMember(users.get(id)))))?.filter(Boolean) ?? [],
21658
+ requested_by: requested_by_id ? await this.correctMember(users.get(requested_by_id)) : null,
21659
+ followers: (await Promise.all(follower_ids?.map((id) => this.correctMember(users.get(id)))))?.filter(Boolean) ?? [],
21660
+ team: group_id ? await this.correctTeam(teams.get(group_id)) : null,
21661
+ workflow: workflow_id ? await this.correctWorkflow(workflows.get(workflow_id)) : null
21662
+ };
21663
+ return correctedEntity;
21664
+ }
21665
+ async toCorrectedEntity(entity) {
21666
+ if (entity.entity_type === "workflow")
21667
+ return this.correctWorkflow(entity);
21668
+ if (entity.entity_type === "group")
21669
+ return this.correctTeam(entity);
21670
+ if (entity.entity_type === "iteration")
21671
+ return this.correctIteration(entity);
21672
+ if (entity.entity_type === "milestone")
21673
+ return this.correctMilestone(entity);
21674
+ if (entity.entity_type === "epic")
21675
+ return this.correctEpic(entity);
21676
+ if (entity.entity_type === "story")
21677
+ return this.correctStory(entity);
21678
+ return entity;
21679
+ }
21680
+ async toCorrectedEntities(entities) {
21681
+ return Promise.all(entities.map((entity) => this.toCorrectedEntity(entity)));
21682
+ }
21683
+ toResult(message, data) {
21684
+ return {
21685
+ content: [
21686
+ {
21687
+ type: "text",
21688
+ text: `${message}${data !== undefined ? `
21578
21689
 
21579
- // src/tools/utils/format.ts
21580
- function jsonToText(data, options = {}) {
21581
- const indent = options.indent || "";
21582
- if (data === null || data === undefined)
21583
- return "";
21584
- if (Array.isArray(data))
21585
- return formatArray(data, { ...options, indent });
21586
- if (typeof data === "object")
21587
- return formatObject(data, { ...options, indent });
21588
- return formatPrimitive(data);
21589
- }
21590
- function formatPrimitive(value) {
21591
- if (typeof value === "boolean")
21592
- return value ? "Yes" : "No";
21593
- return String(value);
21594
- }
21595
- function formatArray(arr, options = {}) {
21596
- if (arr.length === 0)
21597
- return "(empty)";
21598
- const indent = options.indent || "";
21599
- const nextIndent = `${indent} `;
21600
- return arr.map((item) => {
21601
- let formattedItem;
21602
- if (typeof item === "object" && item !== null) {
21603
- formattedItem = jsonToText(item, {
21604
- ...options,
21605
- indent: nextIndent,
21606
- depth: options.depth !== undefined ? options.depth - 1 : undefined
21607
- });
21608
- if (formattedItem.includes(`
21609
- `))
21610
- return `${indent}-
21611
- ${formattedItem}`;
21612
- } else
21613
- formattedItem = formatPrimitive(item);
21614
- return `${indent}- ${formattedItem}`;
21615
- }).join(`
21616
- `);
21617
- }
21618
- function formatObject(obj, options = {}) {
21619
- const indent = options.indent || "";
21620
- const nextIndent = `${indent} `;
21621
- if (options.depth !== undefined && options.depth <= 0)
21622
- return `${indent}[Object]`;
21623
- if (Object.keys(obj).length === 0)
21624
- return `${indent}(empty)`;
21625
- let keys;
21626
- if (!options.include) {
21627
- keys = Object.keys(obj);
21628
- } else if (Array.isArray(options.include)) {
21629
- const arr = options.include;
21630
- keys = Object.keys(obj).filter((key) => arr.includes(key));
21631
- } else {
21632
- keys = Object.keys(obj).filter((key) => {
21633
- const include = options.include;
21634
- return key in include;
21635
- });
21690
+ ${JSON.stringify(data, null, 2)}` : ""}`
21691
+ }
21692
+ ]
21693
+ };
21636
21694
  }
21637
- return keys.map((key) => {
21638
- const value = obj[key];
21639
- const formattedKey = formatKey(key);
21640
- let nestedInclude;
21641
- if (options.include && !Array.isArray(options.include)) {
21642
- const includeValue = options.include[key];
21643
- if (includeValue === true)
21644
- nestedInclude = undefined;
21645
- else
21646
- nestedInclude = includeValue;
21647
- }
21648
- const formattedValue = jsonToText(value, {
21649
- ...options,
21650
- include: nestedInclude,
21651
- indent: nextIndent,
21652
- depth: options.depth !== undefined ? options.depth - 1 : undefined
21653
- });
21654
- if (!formattedValue.includes(`
21655
- `)) {
21656
- return `${indent}${formattedKey}: ${formattedValue}`;
21657
- }
21658
- return `${indent}${formattedKey}:
21659
- ${formattedValue}`;
21660
- }).join(`
21661
- `);
21662
- }
21663
- function formatKey(key) {
21664
- return key.replace(/([A-Z])/g, " $1").replace(/_/g, " ").trim().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
21665
21695
  }
21666
- var formatAsUnorderedList = (items, label) => {
21667
- return `${label ? `${label}:` : ""}${items?.length ? `${label ? `
21668
- ` : ""}${formatArray(items)}` : `${label ? " " : ""}(none)`}`;
21669
- };
21670
- var formatStoryList = (stories, users, label) => {
21671
- return formatAsUnorderedList(stories.map((story) => `sc-${story.id}: ${story.name} (Type: ${story.story_type}, State: ${story.completed ? "Completed" : story.started ? "In Progress" : "Not Started"}, Team: ${story.group_id ? `${story.group_id}` : "(none)"}, Epic: ${story.epic_id ? `${story.epic_id}` : "(none)"}, Iteration: ${story.iteration_id ? `${story.iteration_id}` : "(none)"}, Owners: ${story.owner_ids.map((ownerId) => users.get(ownerId)).filter((owner) => owner !== null).map((owner) => `@${owner.profile.mention_name}`).join(", ") || "(none)"})`), label);
21672
- };
21673
- var formatMemberList = (ids, users, label = "Members") => {
21674
- return formatAsUnorderedList((ids || []).map((id) => {
21675
- const user = users.get(id);
21676
- return user ? `id=${user.id} @${user.profile.mention_name}` : `id=${id} [Unknown]`;
21677
- }), label);
21678
- };
21679
- var formatWorkflowList = (ids, workflows) => {
21680
- return formatAsUnorderedList((ids || []).map((id) => workflows.get(id)).filter((workflow) => !!workflow).map((workflow) => {
21681
- const defaultState = workflow.states.find((state) => state.id === workflow.default_state_id);
21682
- return `id=${workflow.id} name=${workflow.name}. Default state: ${defaultState ? `id=${defaultState.id} name=${defaultState.name}` : "[Unknown]"}`;
21683
- }), "Workflows");
21684
- };
21685
- var formatPullRequestList = (branches) => {
21686
- return formatAsUnorderedList((branches || []).flatMap((branch) => branch.pull_requests || []).map((pr) => `Title: ${pr.title}, Merged: ${pr.merged ? "Yes" : "No"}, URL: ${pr.url}`), "Pull Requests");
21687
- };
21688
- var formatTaskList = (tasks) => {
21689
- return formatAsUnorderedList((tasks || []).map((task) => `[${task.complete ? "X" : " "}] ${task.description}`), "Tasks");
21690
- };
21691
- var formatStats = (stats, showPoints) => {
21692
- const { num_stories_backlog, num_stories_unstarted, num_stories_started, num_stories_done } = stats;
21693
- const { num_points_backlog, num_points_unstarted, num_points_started, num_points_done } = stats;
21694
- const totalCount = num_stories_backlog + num_stories_unstarted + num_stories_started + num_stories_done;
21695
- const totalUnstarted = num_stories_backlog + num_stories_unstarted;
21696
- const totalPoints = (num_points_backlog || 0) + (num_points_unstarted || 0) + (num_points_started || 0) + (num_points_done || 0);
21697
- const totalUnstartedPoints = (num_points_backlog || 0) + (num_points_unstarted || 0);
21698
- const statsString = `Stats:
21699
- - Total stories: ${totalCount}${showPoints ? ` (${totalPoints} points)` : ""}
21700
- - Unstarted stories: ${totalUnstarted}${showPoints ? ` (${totalUnstartedPoints} points)` : ""}
21701
- - Stories in progress: ${num_stories_started}${showPoints ? ` (${num_points_started || 0} points)` : ""}
21702
- - Completed stories: ${num_stories_done}${showPoints ? ` (${num_points_done || 0} points)` : ""}`;
21703
- if (showPoints && stats.num_stories_unestimated)
21704
- return `${statsString}
21705
- - (${stats.num_stories_unestimated} of the stories are unestimated)`;
21706
- return statsString;
21707
- };
21708
- var formatUsersList = (users) => {
21709
- return formatAsUnorderedList(users.map((user) => `id=${user.id} ${user?.profile?.mention_name ? `@${user.profile.mention_name}` : ""} : ""}`));
21710
- };
21711
21696
 
21712
21697
  // src/tools/utils/search.ts
21713
- var keyRenames = { team: "group", name: "title" };
21698
+ var keyRenames = { name: "title" };
21714
21699
  var mapKeyName = (key) => {
21715
21700
  const lowercaseKey = key.toLowerCase();
21716
21701
  return keyRenames[lowercaseKey] || lowercaseKey;
@@ -21813,29 +21798,13 @@ class EpicTools extends BaseTools {
21813
21798
  throw new Error(`Failed to search for epics matching your query: "${query}"`);
21814
21799
  if (!epics.length)
21815
21800
  return this.toResult(`Result: No epics found.`);
21816
- return this.toResult(`Result (first ${epics.length} shown of ${total} total epics found):
21817
- ${formatAsUnorderedList(epics.map((epic) => `${epic.id}: ${epic.name}`))}`);
21801
+ return this.toResult(`Result (first ${epics.length} shown of ${total} total epics found):`, await this.toCorrectedEntities(epics));
21818
21802
  }
21819
21803
  async getEpic(epicPublicId) {
21820
21804
  const epic = await this.client.getEpic(epicPublicId);
21821
21805
  if (!epic)
21822
21806
  throw new Error(`Failed to retrieve Shortcut epic with public ID: ${epicPublicId}`);
21823
- const currentUser = await this.client.getCurrentUser();
21824
- const showPoints = !!currentUser?.workspace2?.estimate_scale?.length;
21825
- return this.toResult(`Epic: ${epicPublicId}
21826
- URL: ${epic.app_url}
21827
- Name: ${epic.name}
21828
- Archived: ${epic.archived ? "Yes" : "No"}
21829
- Completed: ${epic.completed ? "Yes" : "No"}
21830
- Started: ${epic.started ? "Yes" : "No"}
21831
- Due date: ${epic.deadline ? epic.deadline : "[Not set]"}
21832
- Team: ${epic.group_id ? `${epic.group_id}` : "(none)"}
21833
- Objective: ${epic.milestone_id ? `${epic.milestone_id}` : "(none)"}
21834
-
21835
- ${formatStats(epic.stats, showPoints)}
21836
-
21837
- Description:
21838
- ${epic.description}`);
21807
+ return this.toResult(`Epic: ${epicPublicId}`, await this.toCorrectedEntity(epic));
21839
21808
  }
21840
21809
  async createEpic({
21841
21810
  name: name2,
@@ -21885,9 +21854,7 @@ class IterationTools extends BaseTools {
21885
21854
  const { stories } = await this.client.listIterationStories(iterationPublicId);
21886
21855
  if (!stories)
21887
21856
  throw new Error(`Failed to retrieve Shortcut stories in iteration with public ID: ${iterationPublicId}.`);
21888
- const owners = await this.client.getUserMap(stories.flatMap((story) => story.owner_ids));
21889
- return this.toResult(`Result (${stories.length} stories found):
21890
- ${formatStoryList(stories, owners)}`);
21857
+ return this.toResult(`Result (${stories.length} stories found):`, this.toCorrectedEntities(stories));
21891
21858
  }
21892
21859
  async searchIterations(params) {
21893
21860
  const currentUser = await this.client.getCurrentUser();
@@ -21897,28 +21864,13 @@ ${formatStoryList(stories, owners)}`);
21897
21864
  throw new Error(`Failed to search for iterations matching your query: "${query}".`);
21898
21865
  if (!iterations.length)
21899
21866
  return this.toResult(`Result: No iterations found.`);
21900
- return this.toResult(`Result (first ${iterations.length} shown of ${total} total iterations found):
21901
- ${formatAsUnorderedList(iterations.map((iteration) => `${iteration.id}: ${iteration.name} (Start date: ${iteration.start_date}, End date: ${iteration.end_date})`))}`);
21867
+ return this.toResult(`Result (first ${iterations.length} shown of ${total} total iterations found):`, await this.toCorrectedEntities(iterations));
21902
21868
  }
21903
21869
  async getIteration(iterationPublicId) {
21904
21870
  const iteration = await this.client.getIteration(iterationPublicId);
21905
21871
  if (!iteration)
21906
21872
  throw new Error(`Failed to retrieve Shortcut iteration with public ID: ${iterationPublicId}.`);
21907
- const currentUser = await this.client.getCurrentUser();
21908
- const showPoints = !!currentUser?.workspace2?.estimate_scale?.length;
21909
- return this.toResult(`Iteration: ${iterationPublicId}
21910
- Url: ${iteration.app_url}
21911
- Name: ${iteration.name}
21912
- Start date: ${iteration.start_date}
21913
- End date: ${iteration.end_date}
21914
- Completed: ${iteration.status === "completed" ? "Yes" : "No"}
21915
- Started: ${iteration.status === "started" ? "Yes" : "No"}
21916
- Team: ${iteration.group_ids?.length ? `${iteration.group_ids.join(", ")}` : "(none)"}
21917
-
21918
- ${formatStats(iteration.stats, showPoints)}
21919
-
21920
- Description:
21921
- ${iteration.description}`);
21873
+ return this.toResult(`Iteration: ${iterationPublicId}`, await this.toCorrectedEntity(iteration));
21922
21874
  }
21923
21875
  async createIteration({
21924
21876
  name: name2,
@@ -21974,22 +21926,13 @@ class ObjectiveTools extends BaseTools {
21974
21926
  throw new Error(`Failed to search for milestones matching your query: "${query}"`);
21975
21927
  if (!milestones.length)
21976
21928
  return this.toResult(`Result: No milestones found.`);
21977
- return this.toResult(`Result (first ${milestones.length} shown of ${total} total milestones found):
21978
- ${formatAsUnorderedList(milestones.map((milestone) => `${milestone.id}: ${milestone.name}`))}`);
21929
+ return this.toResult(`Result (first ${milestones.length} shown of ${total} total milestones found):`, await this.toCorrectedEntities(milestones));
21979
21930
  }
21980
21931
  async getObjective(objectivePublicId) {
21981
21932
  const objective = await this.client.getMilestone(objectivePublicId);
21982
21933
  if (!objective)
21983
21934
  throw new Error(`Failed to retrieve Shortcut objective with public ID: ${objectivePublicId}`);
21984
- return this.toResult(`Objective: ${objectivePublicId}
21985
- Url: ${objective.app_url}
21986
- Name: ${objective.name}
21987
- Archived: ${objective.archived ? "Yes" : "No"}
21988
- Completed: ${objective.completed ? "Yes" : "No"}
21989
- Started: ${objective.started ? "Yes" : "No"}
21990
-
21991
- Description:
21992
- ${objective.description}`);
21935
+ return this.toResult(`Objective: ${objectivePublicId}`, await this.toCorrectedEntity(objective));
21993
21936
  }
21994
21937
  }
21995
21938
 
@@ -22195,51 +22138,13 @@ The story will be added to the default state for the workflow.
22195
22138
  throw new Error(`Failed to search for stories matching your query: "${query}".`);
22196
22139
  if (!stories.length)
22197
22140
  return this.toResult(`Result: No stories found.`);
22198
- const users = await this.client.getUserMap(stories.flatMap((story) => story.owner_ids));
22199
- return this.toResult(`Result (first ${stories.length} shown of ${total} total stories found):
22200
- ${formatStoryList(stories, users)}`);
22141
+ return this.toResult(`Result (first ${stories.length} shown of ${total} total stories found):`, await this.toCorrectedEntities(stories));
22201
22142
  }
22202
22143
  async getStory(storyPublicId) {
22203
22144
  const story = await this.client.getStory(storyPublicId);
22204
22145
  if (!story)
22205
22146
  throw new Error(`Failed to retrieve Shortcut story with public ID: ${storyPublicId}.`);
22206
- const relatedUsers = new Set([
22207
- ...story.owner_ids,
22208
- ...story.comments.flatMap((c) => c.author_id)
22209
- ]);
22210
- const users = await this.client.getUserMap([...relatedUsers].filter((id) => !!id));
22211
- return this.toResult(`Story: sc-${storyPublicId}
22212
- URL: ${story.app_url}
22213
- Name: ${story.name}
22214
- Type: ${story.story_type}
22215
- Archived: ${story.archived ? "Yes" : "No"}
22216
- Completed: ${story.completed ? "Yes" : "No"}
22217
- Started: ${story.started ? "Yes" : "No"}
22218
- Blocked: ${story.blocked ? "Yes" : "No"}
22219
- Blocking: ${story.blocker ? "Yes" : "No"}
22220
- Due date: ${story.deadline ? story.deadline : "(none)"}
22221
- Team: ${story.group_id ? `${story.group_id}` : "(none)"}
22222
- ${formatMemberList(story.owner_ids, users, "Owners")}
22223
- Epic: ${story.epic_id ? `${story.epic_id}` : "(none)"}
22224
- Iteration: ${story.iteration_id ? `${story.iteration_id}` : "(none)"}
22225
-
22226
- Description:
22227
- ${story.description}
22228
-
22229
- ${formatAsUnorderedList(story.external_links, "External Links")}
22230
-
22231
- ${formatPullRequestList(story.branches)}
22232
-
22233
- ${formatTaskList(story.tasks)}
22234
-
22235
- Comments:
22236
- ${(story.comments || []).map((comment) => {
22237
- const mentionName = comment.author_id ? users.get(comment.author_id)?.profile?.mention_name : null;
22238
- return `- From: ${mentionName ? `@${mentionName}` : `id=${comment.author_id}` || "[Unknown]"} on ${comment.created_at}.
22239
- ${comment.text || ""}`;
22240
- }).join(`
22241
-
22242
- `)}`);
22147
+ return this.toResult(`Story: sc-${storyPublicId}`, await this.toCorrectedEntity(story));
22243
22148
  }
22244
22149
  async createStoryComment({
22245
22150
  storyPublicId,
@@ -22374,27 +22279,13 @@ class TeamTools extends BaseTools {
22374
22279
  const team = await this.client.getTeam(teamPublicId);
22375
22280
  if (!team)
22376
22281
  return this.toResult(`Team with public ID: ${teamPublicId} not found.`);
22377
- const users = await this.client.getUserMap(team.member_ids);
22378
- return this.toResult(`Id: ${team.id}
22379
- Name: ${team.name}
22380
- Mention name: ${team.mention_name}
22381
- Description: ${team.description}
22382
- ${formatMemberList(team.member_ids, users)}`);
22282
+ return this.toResult(`Team: ${team.id}`, await this.toCorrectedEntity(team));
22383
22283
  }
22384
22284
  async getTeams() {
22385
22285
  const teams = await this.client.getTeams();
22386
22286
  if (!teams.length)
22387
22287
  return this.toResult(`No teams found.`);
22388
- const workflows = await this.client.getWorkflowMap(teams.flatMap((team) => team.workflow_ids));
22389
- return this.toResult(`Result (first ${teams.length} shown of ${teams.length} total teams found):
22390
-
22391
- ${teams.map((team) => `Id: ${team.id}
22392
- Name: ${team.name}
22393
- Description: ${team.description}
22394
- Number of Members: ${team.member_ids.length}
22395
- ${formatWorkflowList(team.workflow_ids, workflows)}`).join(`
22396
-
22397
- `)}`);
22288
+ return this.toResult(`Result (first ${teams.length} shown of ${teams.length} total teams found):`, await this.toCorrectedEntities(teams));
22398
22289
  }
22399
22290
  }
22400
22291
 
@@ -22410,14 +22301,11 @@ class UserTools extends BaseTools {
22410
22301
  const user2 = await this.client.getCurrentUser();
22411
22302
  if (!user2)
22412
22303
  throw new Error("Failed to retrieve current user.");
22413
- return this.toResult(`Current user:
22414
- Id: ${user2.id}
22415
- Mention name: @${user2.mention_name}
22416
- Full name: ${user2.name}`);
22304
+ return this.toResult(`Current user:`, user2);
22417
22305
  }
22418
22306
  async listMembers() {
22419
22307
  const members = await this.client.listMembers();
22420
- return this.toResult(`Found ${members.length} members, ${formatUsersList(members)}`);
22308
+ return this.toResult(`Found ${members.length} members:`, members);
22421
22309
  }
22422
22310
  }
22423
22311
 
@@ -22433,24 +22321,13 @@ class WorkflowTools extends BaseTools {
22433
22321
  const workflow = await this.client.getWorkflow(workflowPublicId);
22434
22322
  if (!workflow)
22435
22323
  return this.toResult(`Workflow with public ID: ${workflowPublicId} not found.`);
22436
- return this.toResult(`Id: ${workflow.id}
22437
- Name: ${workflow.name}
22438
- Description: ${workflow.description}
22439
- States:
22440
- ${formatAsUnorderedList(workflow.states.map((state) => `id=${state.id} name=${state.name} (default: ${state.id === workflow.default_state_id ? "yes" : "no"}, type: ${state.type})`))}`);
22324
+ return this.toResult(`Workflow: ${workflow.id}`, await this.toCorrectedEntity(workflow));
22441
22325
  }
22442
22326
  async listWorkflows() {
22443
22327
  const workflows = await this.client.getWorkflows();
22444
22328
  if (!workflows.length)
22445
22329
  return this.toResult(`No workflows found.`);
22446
- return this.toResult(`Result (first ${workflows.length} shown of ${workflows.length} total workflows found):
22447
-
22448
- ${workflows.map((workflow) => `Id: ${workflow.id}
22449
- Name: ${workflow.name}
22450
- Description: ${workflow.description}
22451
- Default State: ${workflow.states.find((state) => state.id === workflow.default_state_id)?.name || "[Unknown]"}`).join(`
22452
-
22453
- `)}`);
22330
+ return this.toResult(`Result (first ${workflows.length} shown of ${workflows.length} total workflows found):`, await this.toCorrectedEntities(workflows));
22454
22331
  }
22455
22332
  }
22456
22333
 
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "modelcontextprotocol"
13
13
  ],
14
14
  "license": "MIT",
15
- "version": "0.6.0",
15
+ "version": "0.7.0",
16
16
  "type": "module",
17
17
  "main": "dist/index.js",
18
18
  "bin": {