@shortcut/mcp 0.10.2 → 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.
- package/dist/index.js +64 -36
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -61,6 +61,14 @@ var ShortcutClientWrapper = class {
|
|
|
61
61
|
this.workflowCache = new Cache();
|
|
62
62
|
this.customFieldCache = new Cache();
|
|
63
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;
|
|
71
|
+
}
|
|
64
72
|
async loadMembers() {
|
|
65
73
|
if (this.userCache.isStale) {
|
|
66
74
|
const response = await this.client.listMembers({});
|
|
@@ -181,38 +189,46 @@ var ShortcutClientWrapper = class {
|
|
|
181
189
|
if (!milestone) return null;
|
|
182
190
|
return milestone;
|
|
183
191
|
}
|
|
184
|
-
async searchStories(query) {
|
|
192
|
+
async searchStories(query, nextToken) {
|
|
185
193
|
const response = await this.client.searchStories({
|
|
186
194
|
query,
|
|
187
195
|
page_size: 25,
|
|
188
|
-
detail: "full"
|
|
196
|
+
detail: "full",
|
|
197
|
+
next: nextToken
|
|
189
198
|
});
|
|
190
199
|
const stories = response?.data?.data;
|
|
191
200
|
const total = response?.data?.total;
|
|
201
|
+
const next = response?.data?.next;
|
|
192
202
|
if (!stories) return {
|
|
193
203
|
stories: null,
|
|
194
|
-
total: null
|
|
204
|
+
total: null,
|
|
205
|
+
next_page_token: null
|
|
195
206
|
};
|
|
196
207
|
return {
|
|
197
208
|
stories,
|
|
198
|
-
total
|
|
209
|
+
total,
|
|
210
|
+
next_page_token: this.getNextPageToken(next)
|
|
199
211
|
};
|
|
200
212
|
}
|
|
201
|
-
async searchIterations(query) {
|
|
213
|
+
async searchIterations(query, nextToken) {
|
|
202
214
|
const response = await this.client.searchIterations({
|
|
203
215
|
query,
|
|
204
216
|
page_size: 25,
|
|
205
|
-
detail: "full"
|
|
217
|
+
detail: "full",
|
|
218
|
+
next: nextToken
|
|
206
219
|
});
|
|
207
220
|
const iterations = response?.data?.data;
|
|
208
221
|
const total = response?.data?.total;
|
|
222
|
+
const next = response?.data?.next;
|
|
209
223
|
if (!iterations) return {
|
|
210
224
|
iterations: null,
|
|
211
|
-
total: null
|
|
225
|
+
total: null,
|
|
226
|
+
next_page_token: null
|
|
212
227
|
};
|
|
213
228
|
return {
|
|
214
229
|
iterations,
|
|
215
|
-
total
|
|
230
|
+
total,
|
|
231
|
+
next_page_token: this.getNextPageToken(next)
|
|
216
232
|
};
|
|
217
233
|
}
|
|
218
234
|
async getActiveIteration(teamIds) {
|
|
@@ -259,38 +275,46 @@ var ShortcutClientWrapper = class {
|
|
|
259
275
|
}, /* @__PURE__ */ new Map());
|
|
260
276
|
return upcomingIterationByTeam;
|
|
261
277
|
}
|
|
262
|
-
async searchEpics(query) {
|
|
278
|
+
async searchEpics(query, nextToken) {
|
|
263
279
|
const response = await this.client.searchEpics({
|
|
264
280
|
query,
|
|
265
281
|
page_size: 25,
|
|
266
|
-
detail: "full"
|
|
282
|
+
detail: "full",
|
|
283
|
+
next: nextToken
|
|
267
284
|
});
|
|
268
285
|
const epics = response?.data?.data;
|
|
269
286
|
const total = response?.data?.total;
|
|
287
|
+
const next = response?.data?.next;
|
|
270
288
|
if (!epics) return {
|
|
271
289
|
epics: null,
|
|
272
|
-
total: null
|
|
290
|
+
total: null,
|
|
291
|
+
next_page_token: null
|
|
273
292
|
};
|
|
274
293
|
return {
|
|
275
294
|
epics,
|
|
276
|
-
total
|
|
295
|
+
total,
|
|
296
|
+
next_page_token: this.getNextPageToken(next)
|
|
277
297
|
};
|
|
278
298
|
}
|
|
279
|
-
async searchMilestones(query) {
|
|
299
|
+
async searchMilestones(query, nextToken) {
|
|
280
300
|
const response = await this.client.searchMilestones({
|
|
281
301
|
query,
|
|
282
302
|
page_size: 25,
|
|
283
|
-
detail: "full"
|
|
303
|
+
detail: "full",
|
|
304
|
+
next: nextToken
|
|
284
305
|
});
|
|
285
306
|
const milestones = response?.data?.data;
|
|
286
307
|
const total = response?.data?.total;
|
|
308
|
+
const next = response?.data?.next;
|
|
287
309
|
if (!milestones) return {
|
|
288
310
|
milestones: null,
|
|
289
|
-
total: null
|
|
311
|
+
total: null,
|
|
312
|
+
next_page_token: null
|
|
290
313
|
};
|
|
291
314
|
return {
|
|
292
315
|
milestones,
|
|
293
|
-
total
|
|
316
|
+
total,
|
|
317
|
+
next_page_token: this.getNextPageToken(next)
|
|
294
318
|
};
|
|
295
319
|
}
|
|
296
320
|
async listIterationStories(iterationPublicId, includeDescription = false) {
|
|
@@ -411,7 +435,7 @@ var ShortcutClientWrapper = class {
|
|
|
411
435
|
//#endregion
|
|
412
436
|
//#region package.json
|
|
413
437
|
var name = "@shortcut/mcp";
|
|
414
|
-
var version = "0.10.
|
|
438
|
+
var version = "0.10.3";
|
|
415
439
|
|
|
416
440
|
//#endregion
|
|
417
441
|
//#region src/tools/base.ts
|
|
@@ -739,10 +763,10 @@ var BaseTools = class {
|
|
|
739
763
|
relatedEntities: this.mergeRelatedEntities(relatedEntities)
|
|
740
764
|
};
|
|
741
765
|
}
|
|
742
|
-
toResult(message, data) {
|
|
766
|
+
toResult(message, data, paginationToken) {
|
|
743
767
|
return { content: [{
|
|
744
768
|
type: "text",
|
|
745
|
-
text: `${message}${data !== void 0 ? `\n\n<json>\n${JSON.stringify(data, null, 2)}\n</json>` : ""}`
|
|
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>` : ""}` : ""}`
|
|
746
770
|
}] };
|
|
747
771
|
}
|
|
748
772
|
};
|
|
@@ -840,6 +864,7 @@ var EpicTools = class EpicTools extends BaseTools {
|
|
|
840
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")
|
|
841
865
|
}, async ({ epicPublicId, full }) => await tools.getEpic(epicPublicId, full));
|
|
842
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."),
|
|
843
868
|
id: z.number().optional().describe("Find only epics with the specified public ID"),
|
|
844
869
|
name: z.string().optional().describe("Find only epics matching the specified name"),
|
|
845
870
|
description: z.string().optional().describe("Find only epics matching the specified description"),
|
|
@@ -866,7 +891,7 @@ var EpicTools = class EpicTools extends BaseTools {
|
|
|
866
891
|
updated: date(),
|
|
867
892
|
completed: date(),
|
|
868
893
|
due: date()
|
|
869
|
-
}, async (params) => await tools.searchEpics(params));
|
|
894
|
+
}, async ({ nextPageToken,...params }) => await tools.searchEpics(params, nextPageToken));
|
|
870
895
|
server$1.tool("create-epic", "Create a new Shortcut epic.", {
|
|
871
896
|
name: z.string().describe("The name of the epic"),
|
|
872
897
|
owner: z.string().optional().describe("The user ID of the owner of the epic"),
|
|
@@ -875,13 +900,13 @@ var EpicTools = class EpicTools extends BaseTools {
|
|
|
875
900
|
}, async (params) => await tools.createEpic(params));
|
|
876
901
|
return tools;
|
|
877
902
|
}
|
|
878
|
-
async searchEpics(params) {
|
|
903
|
+
async searchEpics(params, nextToken) {
|
|
879
904
|
const currentUser = await this.client.getCurrentUser();
|
|
880
905
|
const query = await buildSearchQuery(params, currentUser);
|
|
881
|
-
const { epics, total } = await this.client.searchEpics(query);
|
|
906
|
+
const { epics, total, next_page_token } = await this.client.searchEpics(query, nextToken);
|
|
882
907
|
if (!epics) throw new Error(`Failed to search for epics matching your query: "${query}"`);
|
|
883
908
|
if (!epics.length) return this.toResult(`Result: No epics found.`);
|
|
884
|
-
return this.toResult(`Result (
|
|
909
|
+
return this.toResult(`Result (${epics.length} shown of ${total} total epics found):`, await this.entitiesWithRelatedEntities(epics, "epics"), next_page_token);
|
|
885
910
|
}
|
|
886
911
|
async getEpic(epicPublicId, full = false) {
|
|
887
912
|
const epic = await this.client.getEpic(epicPublicId);
|
|
@@ -913,6 +938,7 @@ var IterationTools = class IterationTools extends BaseTools {
|
|
|
913
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")
|
|
914
939
|
}, async ({ iterationPublicId, full }) => await tools.getIteration(iterationPublicId, full));
|
|
915
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."),
|
|
916
942
|
id: z.number().optional().describe("Find only iterations with the specified public ID"),
|
|
917
943
|
name: z.string().optional().describe("Find only iterations matching the specified name"),
|
|
918
944
|
description: z.string().optional().describe("Find only iterations matching the specified description"),
|
|
@@ -926,7 +952,7 @@ var IterationTools = class IterationTools extends BaseTools {
|
|
|
926
952
|
updated: date(),
|
|
927
953
|
startDate: date(),
|
|
928
954
|
endDate: date()
|
|
929
|
-
}, async (params) => await tools.searchIterations(params));
|
|
955
|
+
}, async ({ nextPageToken,...params }) => await tools.searchIterations(params, nextPageToken));
|
|
930
956
|
server$1.tool("create-iteration", "Create a new Shortcut iteration", {
|
|
931
957
|
name: z.string().describe("The name of the iteration"),
|
|
932
958
|
startDate: z.string().describe("The start date of the iteration in YYYY-MM-DD format"),
|
|
@@ -943,13 +969,13 @@ var IterationTools = class IterationTools extends BaseTools {
|
|
|
943
969
|
if (!stories) throw new Error(`Failed to retrieve Shortcut stories in iteration with public ID: ${iterationPublicId}.`);
|
|
944
970
|
return this.toResult(`Result (${stories.length} stories found):`, await this.entitiesWithRelatedEntities(stories, "stories"));
|
|
945
971
|
}
|
|
946
|
-
async searchIterations(params) {
|
|
972
|
+
async searchIterations(params, nextToken) {
|
|
947
973
|
const currentUser = await this.client.getCurrentUser();
|
|
948
974
|
const query = await buildSearchQuery(params, currentUser);
|
|
949
|
-
const { iterations, total } = await this.client.searchIterations(query);
|
|
975
|
+
const { iterations, total, next_page_token } = await this.client.searchIterations(query, nextToken);
|
|
950
976
|
if (!iterations) throw new Error(`Failed to search for iterations matching your query: "${query}".`);
|
|
951
977
|
if (!iterations.length) return this.toResult(`Result: No iterations found.`);
|
|
952
|
-
return this.toResult(`Result (
|
|
978
|
+
return this.toResult(`Result (${iterations.length} shown of ${total} total iterations found):`, await this.entitiesWithRelatedEntities(iterations, "iterations"), next_page_token);
|
|
953
979
|
}
|
|
954
980
|
async getIteration(iterationPublicId, full = false) {
|
|
955
981
|
const iteration = await this.client.getIteration(iterationPublicId);
|
|
@@ -1019,6 +1045,7 @@ var ObjectiveTools = class ObjectiveTools extends BaseTools {
|
|
|
1019
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")
|
|
1020
1046
|
}, async ({ objectivePublicId, full }) => await tools.getObjective(objectivePublicId, full));
|
|
1021
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."),
|
|
1022
1049
|
id: z.number().optional().describe("Find objectives matching the specified id"),
|
|
1023
1050
|
name: z.string().optional().describe("Find objectives matching the specified name"),
|
|
1024
1051
|
description: z.string().optional().describe("Find objectives matching the specified description"),
|
|
@@ -1038,16 +1065,16 @@ var ObjectiveTools = class ObjectiveTools extends BaseTools {
|
|
|
1038
1065
|
created: date(),
|
|
1039
1066
|
updated: date(),
|
|
1040
1067
|
completed: date()
|
|
1041
|
-
}, async (params) => await tools.searchObjectives(params));
|
|
1068
|
+
}, async ({ nextPageToken,...params }) => await tools.searchObjectives(params, nextPageToken));
|
|
1042
1069
|
return tools;
|
|
1043
1070
|
}
|
|
1044
|
-
async searchObjectives(params) {
|
|
1071
|
+
async searchObjectives(params, nextToken) {
|
|
1045
1072
|
const currentUser = await this.client.getCurrentUser();
|
|
1046
1073
|
const query = await buildSearchQuery(params, currentUser);
|
|
1047
|
-
const { milestones, total } = await this.client.searchMilestones(query);
|
|
1074
|
+
const { milestones, total, next_page_token } = await this.client.searchMilestones(query, nextToken);
|
|
1048
1075
|
if (!milestones) throw new Error(`Failed to search for milestones matching your query: "${query}"`);
|
|
1049
1076
|
if (!milestones.length) return this.toResult(`Result: No milestones found.`);
|
|
1050
|
-
return this.toResult(`Result (
|
|
1077
|
+
return this.toResult(`Result (${milestones.length} shown of ${total} total milestones found):`, await this.entitiesWithRelatedEntities(milestones, "objectives"), next_page_token);
|
|
1051
1078
|
}
|
|
1052
1079
|
async getObjective(objectivePublicId, full = false) {
|
|
1053
1080
|
const objective = await this.client.getMilestone(objectivePublicId);
|
|
@@ -1061,12 +1088,12 @@ var ObjectiveTools = class ObjectiveTools extends BaseTools {
|
|
|
1061
1088
|
var StoryTools = class StoryTools extends BaseTools {
|
|
1062
1089
|
static create(client$1, server$1) {
|
|
1063
1090
|
const tools = new StoryTools(client$1);
|
|
1064
|
-
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));
|
|
1065
1091
|
server$1.tool("get-story", "Get a Shortcut story by public ID", {
|
|
1066
1092
|
storyPublicId: z.number().positive().describe("The public ID of the story to get"),
|
|
1067
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")
|
|
1068
1094
|
}, async ({ storyPublicId, full }) => await tools.getStory(storyPublicId, full));
|
|
1069
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."),
|
|
1070
1097
|
id: z.number().optional().describe("Find only stories with the specified public ID"),
|
|
1071
1098
|
name: z.string().optional().describe("Find only stories matching the specified name"),
|
|
1072
1099
|
description: z.string().optional().describe("Find only stories matching the specified description"),
|
|
@@ -1115,7 +1142,8 @@ var StoryTools = class StoryTools extends BaseTools {
|
|
|
1115
1142
|
updated: date(),
|
|
1116
1143
|
completed: date(),
|
|
1117
1144
|
due: date()
|
|
1118
|
-
}, 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));
|
|
1119
1147
|
server$1.tool("create-story", `Create a new Shortcut story.
|
|
1120
1148
|
Name is required, and either a Team or Workflow must be specified:
|
|
1121
1149
|
- If only Team is specified, we will use the default workflow for that team.
|
|
@@ -1258,13 +1286,13 @@ The story will be added to the default state for the workflow.
|
|
|
1258
1286
|
});
|
|
1259
1287
|
return this.toResult(`Created story: ${story.id}`);
|
|
1260
1288
|
}
|
|
1261
|
-
async searchStories(params) {
|
|
1289
|
+
async searchStories(params, nextToken) {
|
|
1262
1290
|
const currentUser = await this.client.getCurrentUser();
|
|
1263
1291
|
const query = await buildSearchQuery(params, currentUser);
|
|
1264
|
-
const { stories, total } = await this.client.searchStories(query);
|
|
1292
|
+
const { stories, total, next_page_token } = await this.client.searchStories(query, nextToken);
|
|
1265
1293
|
if (!stories) throw new Error(`Failed to search for stories matching your query: "${query}".`);
|
|
1266
1294
|
if (!stories.length) return this.toResult(`Result: No stories found.`);
|
|
1267
|
-
return this.toResult(`Result (
|
|
1295
|
+
return this.toResult(`Result (${stories.length} shown of ${total} total stories found):`, await this.entitiesWithRelatedEntities(stories, "stories"), next_page_token);
|
|
1268
1296
|
}
|
|
1269
1297
|
async getStory(storyPublicId, full = false) {
|
|
1270
1298
|
const story = await this.client.getStory(storyPublicId);
|