@shortcut/mcp 0.4.1 → 0.5.1
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/README.md +3 -3
- package/dist/index.js +548 -79
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ See the [official Windsurf docs](https://codeium.com/docs/windsurf/mcp) for more
|
|
|
17
17
|
"command": "npx",
|
|
18
18
|
"args": [
|
|
19
19
|
"-y",
|
|
20
|
-
"@shortcut/mcp"
|
|
20
|
+
"@shortcut/mcp@latest"
|
|
21
21
|
],
|
|
22
22
|
"env": {
|
|
23
23
|
"SHORTCUT_API_TOKEN": "<YOUR_SHORTCUT_API_TOKEN>"
|
|
@@ -41,7 +41,7 @@ See the [official Cursor docs](https://docs.cursor.com/context/model-context-pro
|
|
|
41
41
|
"command": "npx",
|
|
42
42
|
"args": [
|
|
43
43
|
"-y",
|
|
44
|
-
"@shortcut/mcp"
|
|
44
|
+
"@shortcut/mcp@latest"
|
|
45
45
|
],
|
|
46
46
|
"env": {
|
|
47
47
|
"SHORTCUT_API_TOKEN": "<YOUR_SHORTCUT_API_TOKEN>"
|
|
@@ -68,7 +68,7 @@ _You can add a new MCP server from the Claude Code CLI. But modifying the json f
|
|
|
68
68
|
"command": "npx",
|
|
69
69
|
"args": [
|
|
70
70
|
"-y",
|
|
71
|
-
"@shortcut/mcp"
|
|
71
|
+
"@shortcut/mcp@latest"
|
|
72
72
|
],
|
|
73
73
|
"env": {
|
|
74
74
|
"SHORTCUT_API_TOKEN": "<YOUR_SHORTCUT_API_TOKEN>"
|
package/dist/index.js
CHANGED
|
@@ -14651,6 +14651,11 @@ class ShortcutClientWrapper {
|
|
|
14651
14651
|
await this.loadMembers();
|
|
14652
14652
|
return userIds.map((id) => this.userCache.get(id)).filter((user) => user !== null);
|
|
14653
14653
|
}
|
|
14654
|
+
async listMembers() {
|
|
14655
|
+
await this.loadMembers();
|
|
14656
|
+
const members = Array.from(this.userCache.values());
|
|
14657
|
+
return members;
|
|
14658
|
+
}
|
|
14654
14659
|
async getWorkflowMap(workflowIds) {
|
|
14655
14660
|
await this.loadWorkflows();
|
|
14656
14661
|
return new Map(workflowIds.map((id) => [id, this.workflowCache.get(id)]).filter((workflow) => workflow[1] !== null));
|
|
@@ -14782,6 +14787,49 @@ class ShortcutClientWrapper {
|
|
|
14782
14787
|
throw new Error(`Failed to create the epic: ${response.status}`);
|
|
14783
14788
|
return epic;
|
|
14784
14789
|
}
|
|
14790
|
+
async addTaskToStory(storyPublicId, taskParams) {
|
|
14791
|
+
const { description, ownerIds } = taskParams;
|
|
14792
|
+
const params = {
|
|
14793
|
+
description,
|
|
14794
|
+
owner_ids: ownerIds
|
|
14795
|
+
};
|
|
14796
|
+
const response = await this.client.createTask(storyPublicId, params);
|
|
14797
|
+
const task = response?.data ?? null;
|
|
14798
|
+
if (!task)
|
|
14799
|
+
throw new Error(`Failed to create the task: ${response.status}`);
|
|
14800
|
+
return task;
|
|
14801
|
+
}
|
|
14802
|
+
async addRelationToStory(storyPublicId, linkedStoryId) {
|
|
14803
|
+
const response = await this.client.createStoryLink({
|
|
14804
|
+
object_id: linkedStoryId,
|
|
14805
|
+
subject_id: storyPublicId,
|
|
14806
|
+
verb: "relates to"
|
|
14807
|
+
});
|
|
14808
|
+
const storyLink = response?.data ?? null;
|
|
14809
|
+
if (!storyLink)
|
|
14810
|
+
throw new Error(`Failed to create the story links: ${response.status}`);
|
|
14811
|
+
return storyLink;
|
|
14812
|
+
}
|
|
14813
|
+
async getTask(storyPublicId, taskPublicId) {
|
|
14814
|
+
const response = await this.client.getTask(storyPublicId, taskPublicId);
|
|
14815
|
+
const task = response?.data ?? null;
|
|
14816
|
+
if (!task)
|
|
14817
|
+
throw new Error(`Failed to get the task: ${response.status}`);
|
|
14818
|
+
return task;
|
|
14819
|
+
}
|
|
14820
|
+
async updateTask(storyPublicId, taskPublicId, taskParams) {
|
|
14821
|
+
const { description, ownerIds } = taskParams;
|
|
14822
|
+
const params = {
|
|
14823
|
+
description,
|
|
14824
|
+
owner_ids: ownerIds,
|
|
14825
|
+
complete: taskParams.isCompleted
|
|
14826
|
+
};
|
|
14827
|
+
const response = await this.client.updateTask(storyPublicId, taskPublicId, params);
|
|
14828
|
+
const task = response?.data ?? null;
|
|
14829
|
+
if (!task)
|
|
14830
|
+
throw new Error(`Failed to update the task: ${response.status}`);
|
|
14831
|
+
return task;
|
|
14832
|
+
}
|
|
14785
14833
|
}
|
|
14786
14834
|
|
|
14787
14835
|
// node_modules/zod/lib/index.mjs
|
|
@@ -15631,13 +15679,14 @@ var base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_
|
|
|
15631
15679
|
var dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
|
|
15632
15680
|
var dateRegex = new RegExp(`^${dateRegexSource}$`);
|
|
15633
15681
|
function timeRegexSource(args) {
|
|
15634
|
-
let
|
|
15682
|
+
let secondsRegexSource = `[0-5]\\d`;
|
|
15635
15683
|
if (args.precision) {
|
|
15636
|
-
|
|
15684
|
+
secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
|
|
15637
15685
|
} else if (args.precision == null) {
|
|
15638
|
-
|
|
15686
|
+
secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
|
|
15639
15687
|
}
|
|
15640
|
-
|
|
15688
|
+
const secondsQuantifier = args.precision ? "+" : "?";
|
|
15689
|
+
return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
|
|
15641
15690
|
}
|
|
15642
15691
|
function timeRegex(args) {
|
|
15643
15692
|
return new RegExp(`^${timeRegexSource(args)}$`);
|
|
@@ -18790,18 +18839,20 @@ var z = /* @__PURE__ */ Object.freeze({
|
|
|
18790
18839
|
});
|
|
18791
18840
|
|
|
18792
18841
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
18793
|
-
var LATEST_PROTOCOL_VERSION = "
|
|
18842
|
+
var LATEST_PROTOCOL_VERSION = "2025-03-26";
|
|
18794
18843
|
var SUPPORTED_PROTOCOL_VERSIONS = [
|
|
18795
18844
|
LATEST_PROTOCOL_VERSION,
|
|
18845
|
+
"2024-11-05",
|
|
18796
18846
|
"2024-10-07"
|
|
18797
18847
|
];
|
|
18798
18848
|
var JSONRPC_VERSION = "2.0";
|
|
18799
18849
|
var ProgressTokenSchema = z.union([z.string(), z.number().int()]);
|
|
18800
18850
|
var CursorSchema = z.string();
|
|
18851
|
+
var RequestMetaSchema = z.object({
|
|
18852
|
+
progressToken: z.optional(ProgressTokenSchema)
|
|
18853
|
+
}).passthrough();
|
|
18801
18854
|
var BaseRequestParamsSchema = z.object({
|
|
18802
|
-
_meta: z.optional(
|
|
18803
|
-
progressToken: z.optional(ProgressTokenSchema)
|
|
18804
|
-
}).passthrough())
|
|
18855
|
+
_meta: z.optional(RequestMetaSchema)
|
|
18805
18856
|
}).passthrough();
|
|
18806
18857
|
var RequestSchema = z.object({
|
|
18807
18858
|
method: z.string(),
|
|
@@ -18822,14 +18873,17 @@ var JSONRPCRequestSchema = z.object({
|
|
|
18822
18873
|
jsonrpc: z.literal(JSONRPC_VERSION),
|
|
18823
18874
|
id: RequestIdSchema
|
|
18824
18875
|
}).merge(RequestSchema).strict();
|
|
18876
|
+
var isJSONRPCRequest = (value) => JSONRPCRequestSchema.safeParse(value).success;
|
|
18825
18877
|
var JSONRPCNotificationSchema = z.object({
|
|
18826
18878
|
jsonrpc: z.literal(JSONRPC_VERSION)
|
|
18827
18879
|
}).merge(NotificationSchema).strict();
|
|
18880
|
+
var isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(value).success;
|
|
18828
18881
|
var JSONRPCResponseSchema = z.object({
|
|
18829
18882
|
jsonrpc: z.literal(JSONRPC_VERSION),
|
|
18830
18883
|
id: RequestIdSchema,
|
|
18831
18884
|
result: ResultSchema
|
|
18832
18885
|
}).strict();
|
|
18886
|
+
var isJSONRPCResponse = (value) => JSONRPCResponseSchema.safeParse(value).success;
|
|
18833
18887
|
var ErrorCode;
|
|
18834
18888
|
(function(ErrorCode2) {
|
|
18835
18889
|
ErrorCode2[ErrorCode2["ConnectionClosed"] = -32000] = "ConnectionClosed";
|
|
@@ -18849,6 +18903,7 @@ var JSONRPCErrorSchema = z.object({
|
|
|
18849
18903
|
data: z.optional(z.unknown())
|
|
18850
18904
|
})
|
|
18851
18905
|
}).strict();
|
|
18906
|
+
var isJSONRPCError = (value) => JSONRPCErrorSchema.safeParse(value).success;
|
|
18852
18907
|
var JSONRPCMessageSchema = z.union([
|
|
18853
18908
|
JSONRPCRequestSchema,
|
|
18854
18909
|
JSONRPCNotificationSchema,
|
|
@@ -18885,6 +18940,7 @@ var InitializeRequestSchema = RequestSchema.extend({
|
|
|
18885
18940
|
var ServerCapabilitiesSchema = z.object({
|
|
18886
18941
|
experimental: z.optional(z.object({}).passthrough()),
|
|
18887
18942
|
logging: z.optional(z.object({}).passthrough()),
|
|
18943
|
+
completions: z.optional(z.object({}).passthrough()),
|
|
18888
18944
|
prompts: z.optional(z.object({
|
|
18889
18945
|
listChanged: z.optional(z.boolean())
|
|
18890
18946
|
}).passthrough()),
|
|
@@ -19022,6 +19078,11 @@ var ImageContentSchema = z.object({
|
|
|
19022
19078
|
data: z.string().base64(),
|
|
19023
19079
|
mimeType: z.string()
|
|
19024
19080
|
}).passthrough();
|
|
19081
|
+
var AudioContentSchema = z.object({
|
|
19082
|
+
type: z.literal("audio"),
|
|
19083
|
+
data: z.string().base64(),
|
|
19084
|
+
mimeType: z.string()
|
|
19085
|
+
}).passthrough();
|
|
19025
19086
|
var EmbeddedResourceSchema = z.object({
|
|
19026
19087
|
type: z.literal("resource"),
|
|
19027
19088
|
resource: z.union([TextResourceContentsSchema, BlobResourceContentsSchema])
|
|
@@ -19031,6 +19092,7 @@ var PromptMessageSchema = z.object({
|
|
|
19031
19092
|
content: z.union([
|
|
19032
19093
|
TextContentSchema,
|
|
19033
19094
|
ImageContentSchema,
|
|
19095
|
+
AudioContentSchema,
|
|
19034
19096
|
EmbeddedResourceSchema
|
|
19035
19097
|
])
|
|
19036
19098
|
}).passthrough();
|
|
@@ -19041,13 +19103,21 @@ var GetPromptResultSchema = ResultSchema.extend({
|
|
|
19041
19103
|
var PromptListChangedNotificationSchema = NotificationSchema.extend({
|
|
19042
19104
|
method: z.literal("notifications/prompts/list_changed")
|
|
19043
19105
|
});
|
|
19106
|
+
var ToolAnnotationsSchema = z.object({
|
|
19107
|
+
title: z.optional(z.string()),
|
|
19108
|
+
readOnlyHint: z.optional(z.boolean()),
|
|
19109
|
+
destructiveHint: z.optional(z.boolean()),
|
|
19110
|
+
idempotentHint: z.optional(z.boolean()),
|
|
19111
|
+
openWorldHint: z.optional(z.boolean())
|
|
19112
|
+
}).passthrough();
|
|
19044
19113
|
var ToolSchema = z.object({
|
|
19045
19114
|
name: z.string(),
|
|
19046
19115
|
description: z.optional(z.string()),
|
|
19047
19116
|
inputSchema: z.object({
|
|
19048
19117
|
type: z.literal("object"),
|
|
19049
19118
|
properties: z.optional(z.object({}).passthrough())
|
|
19050
|
-
}).passthrough()
|
|
19119
|
+
}).passthrough(),
|
|
19120
|
+
annotations: z.optional(ToolAnnotationsSchema)
|
|
19051
19121
|
}).passthrough();
|
|
19052
19122
|
var ListToolsRequestSchema = PaginatedRequestSchema.extend({
|
|
19053
19123
|
method: z.literal("tools/list")
|
|
@@ -19056,7 +19126,7 @@ var ListToolsResultSchema = PaginatedResultSchema.extend({
|
|
|
19056
19126
|
tools: z.array(ToolSchema)
|
|
19057
19127
|
});
|
|
19058
19128
|
var CallToolResultSchema = ResultSchema.extend({
|
|
19059
|
-
content: z.array(z.union([TextContentSchema, ImageContentSchema, EmbeddedResourceSchema])),
|
|
19129
|
+
content: z.array(z.union([TextContentSchema, ImageContentSchema, AudioContentSchema, EmbeddedResourceSchema])),
|
|
19060
19130
|
isError: z.boolean().default(false).optional()
|
|
19061
19131
|
});
|
|
19062
19132
|
var CompatibilityCallToolResultSchema = CallToolResultSchema.or(ResultSchema.extend({
|
|
@@ -19107,7 +19177,7 @@ var ModelPreferencesSchema = z.object({
|
|
|
19107
19177
|
}).passthrough();
|
|
19108
19178
|
var SamplingMessageSchema = z.object({
|
|
19109
19179
|
role: z.enum(["user", "assistant"]),
|
|
19110
|
-
content: z.union([TextContentSchema, ImageContentSchema])
|
|
19180
|
+
content: z.union([TextContentSchema, ImageContentSchema, AudioContentSchema])
|
|
19111
19181
|
}).passthrough();
|
|
19112
19182
|
var CreateMessageRequestSchema = RequestSchema.extend({
|
|
19113
19183
|
method: z.literal("sampling/createMessage"),
|
|
@@ -19128,7 +19198,8 @@ var CreateMessageResultSchema = ResultSchema.extend({
|
|
|
19128
19198
|
role: z.enum(["user", "assistant"]),
|
|
19129
19199
|
content: z.discriminatedUnion("type", [
|
|
19130
19200
|
TextContentSchema,
|
|
19131
|
-
ImageContentSchema
|
|
19201
|
+
ImageContentSchema,
|
|
19202
|
+
AudioContentSchema
|
|
19132
19203
|
])
|
|
19133
19204
|
});
|
|
19134
19205
|
var ResourceReferenceSchema = z.object({
|
|
@@ -19253,12 +19324,13 @@ class Protocol {
|
|
|
19253
19324
|
});
|
|
19254
19325
|
this.setRequestHandler(PingRequestSchema, (_request) => ({}));
|
|
19255
19326
|
}
|
|
19256
|
-
_setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout) {
|
|
19327
|
+
_setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout, resetTimeoutOnProgress = false) {
|
|
19257
19328
|
this._timeoutInfo.set(messageId, {
|
|
19258
19329
|
timeoutId: setTimeout(onTimeout, timeout),
|
|
19259
19330
|
startTime: Date.now(),
|
|
19260
19331
|
timeout,
|
|
19261
19332
|
maxTotalTimeout,
|
|
19333
|
+
resetTimeoutOnProgress,
|
|
19262
19334
|
onTimeout
|
|
19263
19335
|
});
|
|
19264
19336
|
}
|
|
@@ -19290,13 +19362,15 @@ class Protocol {
|
|
|
19290
19362
|
this._transport.onerror = (error) => {
|
|
19291
19363
|
this._onerror(error);
|
|
19292
19364
|
};
|
|
19293
|
-
this._transport.onmessage = (message) => {
|
|
19294
|
-
if (
|
|
19365
|
+
this._transport.onmessage = (message, extra) => {
|
|
19366
|
+
if (isJSONRPCResponse(message) || isJSONRPCError(message)) {
|
|
19295
19367
|
this._onresponse(message);
|
|
19296
|
-
} else if (
|
|
19297
|
-
this._onrequest(message);
|
|
19298
|
-
} else {
|
|
19368
|
+
} else if (isJSONRPCRequest(message)) {
|
|
19369
|
+
this._onrequest(message, extra);
|
|
19370
|
+
} else if (isJSONRPCNotification(message)) {
|
|
19299
19371
|
this._onnotification(message);
|
|
19372
|
+
} else {
|
|
19373
|
+
this._onerror(new Error(`Unknown message type: ${JSON.stringify(message)}`));
|
|
19300
19374
|
}
|
|
19301
19375
|
};
|
|
19302
19376
|
await this._transport.start();
|
|
@@ -19325,8 +19399,8 @@ class Protocol {
|
|
|
19325
19399
|
}
|
|
19326
19400
|
Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
|
|
19327
19401
|
}
|
|
19328
|
-
_onrequest(request) {
|
|
19329
|
-
var _a, _b;
|
|
19402
|
+
_onrequest(request, extra) {
|
|
19403
|
+
var _a, _b, _c, _d;
|
|
19330
19404
|
const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== undefined ? _a : this.fallbackRequestHandler;
|
|
19331
19405
|
if (handler === undefined) {
|
|
19332
19406
|
(_b = this._transport) === null || _b === undefined || _b.send({
|
|
@@ -19341,7 +19415,16 @@ class Protocol {
|
|
|
19341
19415
|
}
|
|
19342
19416
|
const abortController = new AbortController;
|
|
19343
19417
|
this._requestHandlerAbortControllers.set(request.id, abortController);
|
|
19344
|
-
|
|
19418
|
+
const fullExtra = {
|
|
19419
|
+
signal: abortController.signal,
|
|
19420
|
+
sessionId: (_c = this._transport) === null || _c === undefined ? undefined : _c.sessionId,
|
|
19421
|
+
_meta: (_d = request.params) === null || _d === undefined ? undefined : _d._meta,
|
|
19422
|
+
sendNotification: (notification) => this.notification(notification, { relatedRequestId: request.id }),
|
|
19423
|
+
sendRequest: (r, resultSchema, options) => this.request(r, resultSchema, { ...options, relatedRequestId: request.id }),
|
|
19424
|
+
authInfo: extra === null || extra === undefined ? undefined : extra.authInfo,
|
|
19425
|
+
requestId: request.id
|
|
19426
|
+
};
|
|
19427
|
+
Promise.resolve().then(() => handler(request, fullExtra)).then((result) => {
|
|
19345
19428
|
var _a2;
|
|
19346
19429
|
if (abortController.signal.aborted) {
|
|
19347
19430
|
return;
|
|
@@ -19377,7 +19460,8 @@ class Protocol {
|
|
|
19377
19460
|
return;
|
|
19378
19461
|
}
|
|
19379
19462
|
const responseHandler = this._responseHandlers.get(messageId);
|
|
19380
|
-
|
|
19463
|
+
const timeoutInfo = this._timeoutInfo.get(messageId);
|
|
19464
|
+
if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) {
|
|
19381
19465
|
try {
|
|
19382
19466
|
this._resetTimeout(messageId);
|
|
19383
19467
|
} catch (error) {
|
|
@@ -19397,7 +19481,7 @@ class Protocol {
|
|
|
19397
19481
|
this._responseHandlers.delete(messageId);
|
|
19398
19482
|
this._progressHandlers.delete(messageId);
|
|
19399
19483
|
this._cleanupTimeout(messageId);
|
|
19400
|
-
if (
|
|
19484
|
+
if (isJSONRPCResponse(response)) {
|
|
19401
19485
|
handler(response);
|
|
19402
19486
|
} else {
|
|
19403
19487
|
const error = new McpError(response.error.code, response.error.message, response.error.data);
|
|
@@ -19412,8 +19496,9 @@ class Protocol {
|
|
|
19412
19496
|
await ((_a = this._transport) === null || _a === undefined ? undefined : _a.close());
|
|
19413
19497
|
}
|
|
19414
19498
|
request(request, resultSchema, options) {
|
|
19499
|
+
const { relatedRequestId, resumptionToken, onresumptiontoken } = options !== null && options !== undefined ? options : {};
|
|
19415
19500
|
return new Promise((resolve, reject) => {
|
|
19416
|
-
var _a, _b, _c, _d;
|
|
19501
|
+
var _a, _b, _c, _d, _e;
|
|
19417
19502
|
if (!this._transport) {
|
|
19418
19503
|
reject(new Error("Not connected"));
|
|
19419
19504
|
return;
|
|
@@ -19447,7 +19532,7 @@ class Protocol {
|
|
|
19447
19532
|
requestId: messageId,
|
|
19448
19533
|
reason: String(reason)
|
|
19449
19534
|
}
|
|
19450
|
-
}).catch((error) => this._onerror(new Error(`Failed to send cancellation: ${error}`)));
|
|
19535
|
+
}, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => this._onerror(new Error(`Failed to send cancellation: ${error}`)));
|
|
19451
19536
|
reject(reason);
|
|
19452
19537
|
};
|
|
19453
19538
|
this._responseHandlers.set(messageId, (response) => {
|
|
@@ -19471,14 +19556,14 @@ class Protocol {
|
|
|
19471
19556
|
});
|
|
19472
19557
|
const timeout = (_d = options === null || options === undefined ? undefined : options.timeout) !== null && _d !== undefined ? _d : DEFAULT_REQUEST_TIMEOUT_MSEC;
|
|
19473
19558
|
const timeoutHandler = () => cancel(new McpError(ErrorCode.RequestTimeout, "Request timed out", { timeout }));
|
|
19474
|
-
this._setupTimeout(messageId, timeout, options === null || options === undefined ? undefined : options.maxTotalTimeout, timeoutHandler);
|
|
19475
|
-
this._transport.send(jsonrpcRequest).catch((error) => {
|
|
19559
|
+
this._setupTimeout(messageId, timeout, options === null || options === undefined ? undefined : options.maxTotalTimeout, timeoutHandler, (_e = options === null || options === undefined ? undefined : options.resetTimeoutOnProgress) !== null && _e !== undefined ? _e : false);
|
|
19560
|
+
this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => {
|
|
19476
19561
|
this._cleanupTimeout(messageId);
|
|
19477
19562
|
reject(error);
|
|
19478
19563
|
});
|
|
19479
19564
|
});
|
|
19480
19565
|
}
|
|
19481
|
-
async notification(notification) {
|
|
19566
|
+
async notification(notification, options) {
|
|
19482
19567
|
if (!this._transport) {
|
|
19483
19568
|
throw new Error("Not connected");
|
|
19484
19569
|
}
|
|
@@ -19487,12 +19572,14 @@ class Protocol {
|
|
|
19487
19572
|
...notification,
|
|
19488
19573
|
jsonrpc: "2.0"
|
|
19489
19574
|
};
|
|
19490
|
-
await this._transport.send(jsonrpcNotification);
|
|
19575
|
+
await this._transport.send(jsonrpcNotification, options);
|
|
19491
19576
|
}
|
|
19492
19577
|
setRequestHandler(requestSchema, handler) {
|
|
19493
19578
|
const method = requestSchema.shape.method.value;
|
|
19494
19579
|
this.assertRequestHandlerCapability(method);
|
|
19495
|
-
this._requestHandlers.set(method, (request, extra) =>
|
|
19580
|
+
this._requestHandlers.set(method, (request, extra) => {
|
|
19581
|
+
return Promise.resolve(handler(requestSchema.parse(request), extra));
|
|
19582
|
+
});
|
|
19496
19583
|
}
|
|
19497
19584
|
removeRequestHandler(method) {
|
|
19498
19585
|
this._requestHandlers.delete(method);
|
|
@@ -20932,16 +21019,19 @@ class McpServer {
|
|
|
20932
21019
|
this.server.assertCanSetRequestHandler(ListToolsRequestSchema.shape.method.value);
|
|
20933
21020
|
this.server.assertCanSetRequestHandler(CallToolRequestSchema.shape.method.value);
|
|
20934
21021
|
this.server.registerCapabilities({
|
|
20935
|
-
tools: {
|
|
21022
|
+
tools: {
|
|
21023
|
+
listChanged: true
|
|
21024
|
+
}
|
|
20936
21025
|
});
|
|
20937
21026
|
this.server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
20938
|
-
tools: Object.entries(this._registeredTools).map(([name, tool]) => {
|
|
21027
|
+
tools: Object.entries(this._registeredTools).filter(([, tool]) => tool.enabled).map(([name, tool]) => {
|
|
20939
21028
|
return {
|
|
20940
21029
|
name,
|
|
20941
21030
|
description: tool.description,
|
|
20942
21031
|
inputSchema: tool.inputSchema ? zodToJsonSchema(tool.inputSchema, {
|
|
20943
21032
|
strictUnions: true
|
|
20944
|
-
}) : EMPTY_OBJECT_JSON_SCHEMA
|
|
21033
|
+
}) : EMPTY_OBJECT_JSON_SCHEMA,
|
|
21034
|
+
annotations: tool.annotations
|
|
20945
21035
|
};
|
|
20946
21036
|
})
|
|
20947
21037
|
}));
|
|
@@ -20950,6 +21040,9 @@ class McpServer {
|
|
|
20950
21040
|
if (!tool) {
|
|
20951
21041
|
throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} not found`);
|
|
20952
21042
|
}
|
|
21043
|
+
if (!tool.enabled) {
|
|
21044
|
+
throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} disabled`);
|
|
21045
|
+
}
|
|
20953
21046
|
if (tool.inputSchema) {
|
|
20954
21047
|
const parseResult = await tool.inputSchema.safeParseAsync(request.params.arguments);
|
|
20955
21048
|
if (!parseResult.success) {
|
|
@@ -21009,7 +21102,10 @@ class McpServer {
|
|
|
21009
21102
|
async handlePromptCompletion(request, ref) {
|
|
21010
21103
|
const prompt = this._registeredPrompts[ref.name];
|
|
21011
21104
|
if (!prompt) {
|
|
21012
|
-
throw new McpError(ErrorCode.InvalidParams, `Prompt ${
|
|
21105
|
+
throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} not found`);
|
|
21106
|
+
}
|
|
21107
|
+
if (!prompt.enabled) {
|
|
21108
|
+
throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} disabled`);
|
|
21013
21109
|
}
|
|
21014
21110
|
if (!prompt.argsSchema) {
|
|
21015
21111
|
return EMPTY_COMPLETION_RESULT;
|
|
@@ -21045,10 +21141,12 @@ class McpServer {
|
|
|
21045
21141
|
this.server.assertCanSetRequestHandler(ListResourceTemplatesRequestSchema.shape.method.value);
|
|
21046
21142
|
this.server.assertCanSetRequestHandler(ReadResourceRequestSchema.shape.method.value);
|
|
21047
21143
|
this.server.registerCapabilities({
|
|
21048
|
-
resources: {
|
|
21144
|
+
resources: {
|
|
21145
|
+
listChanged: true
|
|
21146
|
+
}
|
|
21049
21147
|
});
|
|
21050
21148
|
this.server.setRequestHandler(ListResourcesRequestSchema, async (request, extra) => {
|
|
21051
|
-
const resources = Object.entries(this._registeredResources).map(([uri, resource]) => ({
|
|
21149
|
+
const resources = Object.entries(this._registeredResources).filter(([_, resource]) => resource.enabled).map(([uri, resource]) => ({
|
|
21052
21150
|
uri,
|
|
21053
21151
|
name: resource.name,
|
|
21054
21152
|
...resource.metadata
|
|
@@ -21080,6 +21178,9 @@ class McpServer {
|
|
|
21080
21178
|
const uri = new URL(request.params.uri);
|
|
21081
21179
|
const resource = this._registeredResources[uri.toString()];
|
|
21082
21180
|
if (resource) {
|
|
21181
|
+
if (!resource.enabled) {
|
|
21182
|
+
throw new McpError(ErrorCode.InvalidParams, `Resource ${uri} disabled`);
|
|
21183
|
+
}
|
|
21083
21184
|
return resource.readCallback(uri, extra);
|
|
21084
21185
|
}
|
|
21085
21186
|
for (const template of Object.values(this._registeredResourceTemplates)) {
|
|
@@ -21100,10 +21201,12 @@ class McpServer {
|
|
|
21100
21201
|
this.server.assertCanSetRequestHandler(ListPromptsRequestSchema.shape.method.value);
|
|
21101
21202
|
this.server.assertCanSetRequestHandler(GetPromptRequestSchema.shape.method.value);
|
|
21102
21203
|
this.server.registerCapabilities({
|
|
21103
|
-
prompts: {
|
|
21204
|
+
prompts: {
|
|
21205
|
+
listChanged: true
|
|
21206
|
+
}
|
|
21104
21207
|
});
|
|
21105
21208
|
this.server.setRequestHandler(ListPromptsRequestSchema, () => ({
|
|
21106
|
-
prompts: Object.entries(this._registeredPrompts).map(([name, prompt]) => {
|
|
21209
|
+
prompts: Object.entries(this._registeredPrompts).filter(([, prompt]) => prompt.enabled).map(([name, prompt]) => {
|
|
21107
21210
|
return {
|
|
21108
21211
|
name,
|
|
21109
21212
|
description: prompt.description,
|
|
@@ -21116,6 +21219,9 @@ class McpServer {
|
|
|
21116
21219
|
if (!prompt) {
|
|
21117
21220
|
throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} not found`);
|
|
21118
21221
|
}
|
|
21222
|
+
if (!prompt.enabled) {
|
|
21223
|
+
throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} disabled`);
|
|
21224
|
+
}
|
|
21119
21225
|
if (prompt.argsSchema) {
|
|
21120
21226
|
const parseResult = await prompt.argsSchema.safeParseAsync(request.params.arguments);
|
|
21121
21227
|
if (!parseResult.success) {
|
|
@@ -21142,22 +21248,69 @@ class McpServer {
|
|
|
21142
21248
|
if (this._registeredResources[uriOrTemplate]) {
|
|
21143
21249
|
throw new Error(`Resource ${uriOrTemplate} is already registered`);
|
|
21144
21250
|
}
|
|
21145
|
-
|
|
21251
|
+
const registeredResource = {
|
|
21146
21252
|
name,
|
|
21147
21253
|
metadata,
|
|
21148
|
-
readCallback
|
|
21254
|
+
readCallback,
|
|
21255
|
+
enabled: true,
|
|
21256
|
+
disable: () => registeredResource.update({ enabled: false }),
|
|
21257
|
+
enable: () => registeredResource.update({ enabled: true }),
|
|
21258
|
+
remove: () => registeredResource.update({ uri: null }),
|
|
21259
|
+
update: (updates) => {
|
|
21260
|
+
if (typeof updates.uri !== "undefined" && updates.uri !== uriOrTemplate) {
|
|
21261
|
+
delete this._registeredResources[uriOrTemplate];
|
|
21262
|
+
if (updates.uri)
|
|
21263
|
+
this._registeredResources[updates.uri] = registeredResource;
|
|
21264
|
+
}
|
|
21265
|
+
if (typeof updates.name !== "undefined")
|
|
21266
|
+
registeredResource.name = updates.name;
|
|
21267
|
+
if (typeof updates.metadata !== "undefined")
|
|
21268
|
+
registeredResource.metadata = updates.metadata;
|
|
21269
|
+
if (typeof updates.callback !== "undefined")
|
|
21270
|
+
registeredResource.readCallback = updates.callback;
|
|
21271
|
+
if (typeof updates.enabled !== "undefined")
|
|
21272
|
+
registeredResource.enabled = updates.enabled;
|
|
21273
|
+
this.sendResourceListChanged();
|
|
21274
|
+
}
|
|
21149
21275
|
};
|
|
21276
|
+
this._registeredResources[uriOrTemplate] = registeredResource;
|
|
21277
|
+
this.setResourceRequestHandlers();
|
|
21278
|
+
this.sendResourceListChanged();
|
|
21279
|
+
return registeredResource;
|
|
21150
21280
|
} else {
|
|
21151
21281
|
if (this._registeredResourceTemplates[name]) {
|
|
21152
21282
|
throw new Error(`Resource template ${name} is already registered`);
|
|
21153
21283
|
}
|
|
21154
|
-
|
|
21284
|
+
const registeredResourceTemplate = {
|
|
21155
21285
|
resourceTemplate: uriOrTemplate,
|
|
21156
21286
|
metadata,
|
|
21157
|
-
readCallback
|
|
21287
|
+
readCallback,
|
|
21288
|
+
enabled: true,
|
|
21289
|
+
disable: () => registeredResourceTemplate.update({ enabled: false }),
|
|
21290
|
+
enable: () => registeredResourceTemplate.update({ enabled: true }),
|
|
21291
|
+
remove: () => registeredResourceTemplate.update({ name: null }),
|
|
21292
|
+
update: (updates) => {
|
|
21293
|
+
if (typeof updates.name !== "undefined" && updates.name !== name) {
|
|
21294
|
+
delete this._registeredResourceTemplates[name];
|
|
21295
|
+
if (updates.name)
|
|
21296
|
+
this._registeredResourceTemplates[updates.name] = registeredResourceTemplate;
|
|
21297
|
+
}
|
|
21298
|
+
if (typeof updates.template !== "undefined")
|
|
21299
|
+
registeredResourceTemplate.resourceTemplate = updates.template;
|
|
21300
|
+
if (typeof updates.metadata !== "undefined")
|
|
21301
|
+
registeredResourceTemplate.metadata = updates.metadata;
|
|
21302
|
+
if (typeof updates.callback !== "undefined")
|
|
21303
|
+
registeredResourceTemplate.readCallback = updates.callback;
|
|
21304
|
+
if (typeof updates.enabled !== "undefined")
|
|
21305
|
+
registeredResourceTemplate.enabled = updates.enabled;
|
|
21306
|
+
this.sendResourceListChanged();
|
|
21307
|
+
}
|
|
21158
21308
|
};
|
|
21309
|
+
this._registeredResourceTemplates[name] = registeredResourceTemplate;
|
|
21310
|
+
this.setResourceRequestHandlers();
|
|
21311
|
+
this.sendResourceListChanged();
|
|
21312
|
+
return registeredResourceTemplate;
|
|
21159
21313
|
}
|
|
21160
|
-
this.setResourceRequestHandlers();
|
|
21161
21314
|
}
|
|
21162
21315
|
tool(name, ...rest) {
|
|
21163
21316
|
if (this._registeredTools[name]) {
|
|
@@ -21168,16 +21321,51 @@ class McpServer {
|
|
|
21168
21321
|
description = rest.shift();
|
|
21169
21322
|
}
|
|
21170
21323
|
let paramsSchema;
|
|
21324
|
+
let annotations;
|
|
21171
21325
|
if (rest.length > 1) {
|
|
21172
|
-
|
|
21326
|
+
const firstArg = rest[0];
|
|
21327
|
+
if (isZodRawShape(firstArg)) {
|
|
21328
|
+
paramsSchema = rest.shift();
|
|
21329
|
+
if (rest.length > 1 && typeof rest[0] === "object" && rest[0] !== null && !isZodRawShape(rest[0])) {
|
|
21330
|
+
annotations = rest.shift();
|
|
21331
|
+
}
|
|
21332
|
+
} else if (typeof firstArg === "object" && firstArg !== null) {
|
|
21333
|
+
annotations = rest.shift();
|
|
21334
|
+
}
|
|
21173
21335
|
}
|
|
21174
21336
|
const cb = rest[0];
|
|
21175
|
-
|
|
21337
|
+
const registeredTool = {
|
|
21176
21338
|
description,
|
|
21177
21339
|
inputSchema: paramsSchema === undefined ? undefined : z.object(paramsSchema),
|
|
21178
|
-
|
|
21340
|
+
annotations,
|
|
21341
|
+
callback: cb,
|
|
21342
|
+
enabled: true,
|
|
21343
|
+
disable: () => registeredTool.update({ enabled: false }),
|
|
21344
|
+
enable: () => registeredTool.update({ enabled: true }),
|
|
21345
|
+
remove: () => registeredTool.update({ name: null }),
|
|
21346
|
+
update: (updates) => {
|
|
21347
|
+
if (typeof updates.name !== "undefined" && updates.name !== name) {
|
|
21348
|
+
delete this._registeredTools[name];
|
|
21349
|
+
if (updates.name)
|
|
21350
|
+
this._registeredTools[updates.name] = registeredTool;
|
|
21351
|
+
}
|
|
21352
|
+
if (typeof updates.description !== "undefined")
|
|
21353
|
+
registeredTool.description = updates.description;
|
|
21354
|
+
if (typeof updates.paramsSchema !== "undefined")
|
|
21355
|
+
registeredTool.inputSchema = z.object(updates.paramsSchema);
|
|
21356
|
+
if (typeof updates.callback !== "undefined")
|
|
21357
|
+
registeredTool.callback = updates.callback;
|
|
21358
|
+
if (typeof updates.annotations !== "undefined")
|
|
21359
|
+
registeredTool.annotations = updates.annotations;
|
|
21360
|
+
if (typeof updates.enabled !== "undefined")
|
|
21361
|
+
registeredTool.enabled = updates.enabled;
|
|
21362
|
+
this.sendToolListChanged();
|
|
21363
|
+
}
|
|
21179
21364
|
};
|
|
21365
|
+
this._registeredTools[name] = registeredTool;
|
|
21180
21366
|
this.setToolRequestHandlers();
|
|
21367
|
+
this.sendToolListChanged();
|
|
21368
|
+
return registeredTool;
|
|
21181
21369
|
}
|
|
21182
21370
|
prompt(name, ...rest) {
|
|
21183
21371
|
if (this._registeredPrompts[name]) {
|
|
@@ -21192,17 +21380,67 @@ class McpServer {
|
|
|
21192
21380
|
argsSchema = rest.shift();
|
|
21193
21381
|
}
|
|
21194
21382
|
const cb = rest[0];
|
|
21195
|
-
|
|
21383
|
+
const registeredPrompt = {
|
|
21196
21384
|
description,
|
|
21197
21385
|
argsSchema: argsSchema === undefined ? undefined : z.object(argsSchema),
|
|
21198
|
-
callback: cb
|
|
21386
|
+
callback: cb,
|
|
21387
|
+
enabled: true,
|
|
21388
|
+
disable: () => registeredPrompt.update({ enabled: false }),
|
|
21389
|
+
enable: () => registeredPrompt.update({ enabled: true }),
|
|
21390
|
+
remove: () => registeredPrompt.update({ name: null }),
|
|
21391
|
+
update: (updates) => {
|
|
21392
|
+
if (typeof updates.name !== "undefined" && updates.name !== name) {
|
|
21393
|
+
delete this._registeredPrompts[name];
|
|
21394
|
+
if (updates.name)
|
|
21395
|
+
this._registeredPrompts[updates.name] = registeredPrompt;
|
|
21396
|
+
}
|
|
21397
|
+
if (typeof updates.description !== "undefined")
|
|
21398
|
+
registeredPrompt.description = updates.description;
|
|
21399
|
+
if (typeof updates.argsSchema !== "undefined")
|
|
21400
|
+
registeredPrompt.argsSchema = z.object(updates.argsSchema);
|
|
21401
|
+
if (typeof updates.callback !== "undefined")
|
|
21402
|
+
registeredPrompt.callback = updates.callback;
|
|
21403
|
+
if (typeof updates.enabled !== "undefined")
|
|
21404
|
+
registeredPrompt.enabled = updates.enabled;
|
|
21405
|
+
this.sendPromptListChanged();
|
|
21406
|
+
}
|
|
21199
21407
|
};
|
|
21408
|
+
this._registeredPrompts[name] = registeredPrompt;
|
|
21200
21409
|
this.setPromptRequestHandlers();
|
|
21410
|
+
this.sendPromptListChanged();
|
|
21411
|
+
return registeredPrompt;
|
|
21412
|
+
}
|
|
21413
|
+
isConnected() {
|
|
21414
|
+
return this.server.transport !== undefined;
|
|
21415
|
+
}
|
|
21416
|
+
sendResourceListChanged() {
|
|
21417
|
+
if (this.isConnected()) {
|
|
21418
|
+
this.server.sendResourceListChanged();
|
|
21419
|
+
}
|
|
21420
|
+
}
|
|
21421
|
+
sendToolListChanged() {
|
|
21422
|
+
if (this.isConnected()) {
|
|
21423
|
+
this.server.sendToolListChanged();
|
|
21424
|
+
}
|
|
21425
|
+
}
|
|
21426
|
+
sendPromptListChanged() {
|
|
21427
|
+
if (this.isConnected()) {
|
|
21428
|
+
this.server.sendPromptListChanged();
|
|
21429
|
+
}
|
|
21201
21430
|
}
|
|
21202
21431
|
}
|
|
21203
21432
|
var EMPTY_OBJECT_JSON_SCHEMA = {
|
|
21204
21433
|
type: "object"
|
|
21205
21434
|
};
|
|
21435
|
+
function isZodRawShape(obj) {
|
|
21436
|
+
if (typeof obj !== "object" || obj === null)
|
|
21437
|
+
return false;
|
|
21438
|
+
const isEmptyObject = Object.keys(obj).length === 0;
|
|
21439
|
+
return isEmptyObject || Object.values(obj).some(isZodTypeLike);
|
|
21440
|
+
}
|
|
21441
|
+
function isZodTypeLike(value) {
|
|
21442
|
+
return value !== null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function";
|
|
21443
|
+
}
|
|
21206
21444
|
function promptArgumentsFromSchema(schema) {
|
|
21207
21445
|
return Object.entries(schema.shape).map(([name, field]) => ({
|
|
21208
21446
|
name,
|
|
@@ -21243,7 +21481,7 @@ class ReadBuffer {
|
|
|
21243
21481
|
if (index === -1) {
|
|
21244
21482
|
return null;
|
|
21245
21483
|
}
|
|
21246
|
-
const line = this._buffer.toString("utf8", 0, index);
|
|
21484
|
+
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
21247
21485
|
this._buffer = this._buffer.subarray(index + 1);
|
|
21248
21486
|
return deserializeMessage(line);
|
|
21249
21487
|
}
|
|
@@ -21325,7 +21563,7 @@ var import_client = __toESM(require_lib(), 1);
|
|
|
21325
21563
|
|
|
21326
21564
|
// package.json
|
|
21327
21565
|
var name = "@shortcut/mcp";
|
|
21328
|
-
var version = "0.
|
|
21566
|
+
var version = "0.5.1";
|
|
21329
21567
|
|
|
21330
21568
|
// src/tools/base.ts
|
|
21331
21569
|
class BaseTools {
|
|
@@ -21339,13 +21577,98 @@ class BaseTools {
|
|
|
21339
21577
|
}
|
|
21340
21578
|
|
|
21341
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
|
+
});
|
|
21636
|
+
}
|
|
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
|
+
}
|
|
21342
21666
|
var formatAsUnorderedList = (items, label) => {
|
|
21343
21667
|
return `${label ? `${label}:` : ""}${items?.length ? `${label ? `
|
|
21344
|
-
` : ""}${items
|
|
21345
|
-
`)}` : `${label ? " " : ""}[None]`}`;
|
|
21668
|
+
` : ""}${formatArray(items)}` : `${label ? " " : ""}(none)`}`;
|
|
21346
21669
|
};
|
|
21347
21670
|
var formatStoryList = (stories, users, label) => {
|
|
21348
|
-
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}` : "
|
|
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);
|
|
21349
21672
|
};
|
|
21350
21673
|
var formatMemberList = (ids, users, label = "Members") => {
|
|
21351
21674
|
return formatAsUnorderedList((ids || []).map((id) => {
|
|
@@ -21382,20 +21705,31 @@ var formatStats = (stats, showPoints) => {
|
|
|
21382
21705
|
- (${stats.num_stories_unestimated} of the stories are unestimated)`;
|
|
21383
21706
|
return statsString;
|
|
21384
21707
|
};
|
|
21708
|
+
var formatUsersList = (users) => {
|
|
21709
|
+
return formatAsUnorderedList(users.map((user) => `id=${user.id} ${user?.profile?.mention_name ? `@${user.profile.mention_name}` : ""} : ""}`));
|
|
21710
|
+
};
|
|
21385
21711
|
|
|
21386
21712
|
// src/tools/utils/search.ts
|
|
21713
|
+
var keyRenames = { team: "group", name: "title" };
|
|
21714
|
+
var mapKeyName = (key) => {
|
|
21715
|
+
const lowercaseKey = key.toLowerCase();
|
|
21716
|
+
return keyRenames[lowercaseKey] || lowercaseKey;
|
|
21717
|
+
};
|
|
21387
21718
|
var getKey = (prop) => {
|
|
21388
21719
|
if (prop.startsWith("is"))
|
|
21389
|
-
return `is:${prop.slice(2)
|
|
21720
|
+
return `is:${mapKeyName(prop.slice(2))}`;
|
|
21390
21721
|
if (prop.startsWith("has"))
|
|
21391
|
-
return `has:${prop.slice(3)
|
|
21392
|
-
return prop;
|
|
21722
|
+
return `has:${mapKeyName(prop.slice(3))}`;
|
|
21723
|
+
return mapKeyName(prop);
|
|
21393
21724
|
};
|
|
21394
21725
|
var buildSearchQuery = async (params, currentUser) => {
|
|
21395
21726
|
const query = Object.entries(params).map(([key, value]) => {
|
|
21396
21727
|
const q = getKey(key);
|
|
21397
|
-
if (
|
|
21398
|
-
|
|
21728
|
+
if (key === "owner" || key === "requester") {
|
|
21729
|
+
if (value === "me")
|
|
21730
|
+
return `${q}:${currentUser?.mention_name || value}`;
|
|
21731
|
+
return `${q}:${String(value || "").replace(/^@/, "")}`;
|
|
21732
|
+
}
|
|
21399
21733
|
if (typeof value === "boolean")
|
|
21400
21734
|
return value ? q : `!${q}`;
|
|
21401
21735
|
if (typeof value === "number")
|
|
@@ -21429,9 +21763,9 @@ var variations = [
|
|
|
21429
21763
|
range({ f: dateformat, t: dateformat })
|
|
21430
21764
|
];
|
|
21431
21765
|
var DATE_REGEXP = new RegExp(`^(${variations.join("|")})$`);
|
|
21432
|
-
var date2 = z.string().regex(DATE_REGEXP).optional().describe('The date in "YYYY-MM-DD" format, or one of the keywords: "yesterday", "today", "tomorrow", or a date range in the format "YYYY-MM-DD..YYYY-MM-DD". The date range can also be open ended by using "*" for one of the bounds.
|
|
21766
|
+
var date2 = z.string().regex(DATE_REGEXP).optional().describe('The date in "YYYY-MM-DD" format, or one of the keywords: "yesterday", "today", "tomorrow", or a date range in the format "YYYY-MM-DD..YYYY-MM-DD". The date range can also be open ended by using "*" for one of the bounds. Examples: "2023-01-01", "today", "2023-01-01..*" (from Jan 1, 2023 to any future date), "*.2023-01-31" (any date up to Jan 31, 2023), "today..*" (from today onwards), "*.yesterday" (any date up to yesterday). The keywords cannot be used to calculate relative dates (e.g. the following are not valid: "today-1" or "tomorrow+1").');
|
|
21433
21767
|
var is = (field) => z.boolean().optional().describe(`Find only entities that are ${field} when true, or only entities that are not ${field} when false.`);
|
|
21434
|
-
var has = (field) => z.boolean().optional().describe(`Find only entities that have ${field} when true, or only entities that do not have ${field} when false.`);
|
|
21768
|
+
var has = (field) => z.boolean().optional().describe(`Find only entities that have ${field} when true, or only entities that do not have ${field} when false. Example: hasOwner: true will find stories with an owner, hasOwner: false will find stories without an owner.`);
|
|
21435
21769
|
var user = (field) => z.string().optional().describe(`Find entities where the ${field} match the specified user. This must either be the user's mention name or the keyword "me" for the current user.`);
|
|
21436
21770
|
|
|
21437
21771
|
// src/tools/epics.ts
|
|
@@ -21467,7 +21801,7 @@ class EpicTools extends BaseTools {
|
|
|
21467
21801
|
name: z.string().describe("The name of the epic"),
|
|
21468
21802
|
owner: z.string().optional().describe("The user ID of the owner of the epic"),
|
|
21469
21803
|
description: z.string().optional().describe("A description of the epic"),
|
|
21470
|
-
|
|
21804
|
+
teamId: z.string().optional().describe("The ID of a team to assign the epic to")
|
|
21471
21805
|
}, async (params) => await tools.createEpic(params));
|
|
21472
21806
|
return tools;
|
|
21473
21807
|
}
|
|
@@ -21495,8 +21829,8 @@ Archived: ${epic.archived ? "Yes" : "No"}
|
|
|
21495
21829
|
Completed: ${epic.completed ? "Yes" : "No"}
|
|
21496
21830
|
Started: ${epic.started ? "Yes" : "No"}
|
|
21497
21831
|
Due date: ${epic.deadline ? epic.deadline : "[Not set]"}
|
|
21498
|
-
Team: ${epic.group_id ? `${epic.group_id}` : "
|
|
21499
|
-
Objective: ${epic.milestone_id ? `${epic.milestone_id}` : "
|
|
21832
|
+
Team: ${epic.group_id ? `${epic.group_id}` : "(none)"}
|
|
21833
|
+
Objective: ${epic.milestone_id ? `${epic.milestone_id}` : "(none)"}
|
|
21500
21834
|
|
|
21501
21835
|
${formatStats(epic.stats, showPoints)}
|
|
21502
21836
|
|
|
@@ -21506,7 +21840,7 @@ ${epic.description}`);
|
|
|
21506
21840
|
async createEpic({
|
|
21507
21841
|
name: name2,
|
|
21508
21842
|
owner,
|
|
21509
|
-
|
|
21843
|
+
teamId: group_id,
|
|
21510
21844
|
description
|
|
21511
21845
|
}) {
|
|
21512
21846
|
const epic = await this.client.createEpic({
|
|
@@ -21532,7 +21866,7 @@ class IterationTools extends BaseTools {
|
|
|
21532
21866
|
name: z.string().optional().describe("Find only iterations matching the specified name"),
|
|
21533
21867
|
description: z.string().optional().describe("Find only iterations matching the specified description"),
|
|
21534
21868
|
state: z.enum(["started", "unstarted", "done"]).optional().describe("Find only iterations matching the specified state"),
|
|
21535
|
-
team: z.string().optional().describe("Find only iterations matching the specified team.
|
|
21869
|
+
team: z.string().optional().describe("Find only iterations matching the specified team. This can be a team ID or mention name."),
|
|
21536
21870
|
created: date2,
|
|
21537
21871
|
updated: date2,
|
|
21538
21872
|
startDate: date2,
|
|
@@ -21540,9 +21874,9 @@ class IterationTools extends BaseTools {
|
|
|
21540
21874
|
}, async (params) => await tools.searchIterations(params));
|
|
21541
21875
|
server.tool("create-iteration", "Create a new Shortcut iteration", {
|
|
21542
21876
|
name: z.string().describe("The name of the iteration"),
|
|
21543
|
-
startDate: z.string().describe("The start date of the iteration"),
|
|
21544
|
-
endDate: z.string().describe("The end date of the iteration"),
|
|
21545
|
-
|
|
21877
|
+
startDate: z.string().describe("The start date of the iteration in YYYY-MM-DD format"),
|
|
21878
|
+
endDate: z.string().describe("The end date of the iteration in YYYY-MM-DD format"),
|
|
21879
|
+
teamId: z.string().optional().describe("The ID of a team to assign the iteration to"),
|
|
21546
21880
|
description: z.string().optional().describe("A description of the iteration")
|
|
21547
21881
|
}, async (params) => await tools.createIteration(params));
|
|
21548
21882
|
return tools;
|
|
@@ -21579,7 +21913,7 @@ Start date: ${iteration.start_date}
|
|
|
21579
21913
|
End date: ${iteration.end_date}
|
|
21580
21914
|
Completed: ${iteration.status === "completed" ? "Yes" : "No"}
|
|
21581
21915
|
Started: ${iteration.status === "started" ? "Yes" : "No"}
|
|
21582
|
-
Team: ${iteration.group_ids?.length ? `${iteration.group_ids.join(", ")}` : "
|
|
21916
|
+
Team: ${iteration.group_ids?.length ? `${iteration.group_ids.join(", ")}` : "(none)"}
|
|
21583
21917
|
|
|
21584
21918
|
${formatStats(iteration.stats, showPoints)}
|
|
21585
21919
|
|
|
@@ -21590,14 +21924,14 @@ ${iteration.description}`);
|
|
|
21590
21924
|
name: name2,
|
|
21591
21925
|
startDate,
|
|
21592
21926
|
endDate,
|
|
21593
|
-
|
|
21927
|
+
teamId,
|
|
21594
21928
|
description
|
|
21595
21929
|
}) {
|
|
21596
21930
|
const iteration = await this.client.createIteration({
|
|
21597
21931
|
name: name2,
|
|
21598
21932
|
start_date: startDate,
|
|
21599
21933
|
end_date: endDate,
|
|
21600
|
-
group_ids:
|
|
21934
|
+
group_ids: teamId ? [teamId] : undefined,
|
|
21601
21935
|
description
|
|
21602
21936
|
});
|
|
21603
21937
|
if (!iteration)
|
|
@@ -21663,7 +21997,7 @@ ${objective.description}`);
|
|
|
21663
21997
|
class StoryTools extends BaseTools {
|
|
21664
21998
|
static create(client, server) {
|
|
21665
21999
|
const tools = new StoryTools(client);
|
|
21666
|
-
server.tool("get-story-branch-name",
|
|
22000
|
+
server.tool("get-story-branch-name", "Get a valid branch name for a specific story.", {
|
|
21667
22001
|
storyPublicId: z.number().positive().describe("The public Id of the story")
|
|
21668
22002
|
}, async ({ storyPublicId }) => await tools.getStoryBranchName(storyPublicId));
|
|
21669
22003
|
server.tool("get-story", "Get a Shortcut story by public ID", {
|
|
@@ -21716,7 +22050,9 @@ class StoryTools extends BaseTools {
|
|
|
21716
22050
|
due: date2
|
|
21717
22051
|
}, async (params) => await tools.searchStories(params));
|
|
21718
22052
|
server.tool("create-story", `Create a new Shortcut story.
|
|
21719
|
-
Name
|
|
22053
|
+
Name is required, and either a Team or Workflow must be specified:
|
|
22054
|
+
- If only Team is specified, we will use the default workflow for that team.
|
|
22055
|
+
- If Workflow is specified, it will be used regardless of Team.
|
|
21720
22056
|
The story will be added to the default state for the workflow.
|
|
21721
22057
|
`, {
|
|
21722
22058
|
name: z.string().min(1).max(512).describe("The name of the story. Required."),
|
|
@@ -21724,8 +22060,8 @@ The story will be added to the default state for the workflow.
|
|
|
21724
22060
|
type: z.enum(["feature", "bug", "chore"]).default("feature").describe("The type of the story"),
|
|
21725
22061
|
owner: z.string().optional().describe("The user id of the owner of the story"),
|
|
21726
22062
|
epic: z.number().optional().describe("The epic id of the epic the story belongs to"),
|
|
21727
|
-
team: z.string().optional().describe("The team
|
|
21728
|
-
workflow: z.number().optional().describe("The workflow to add the story to. Required unless a team is specified.")
|
|
22063
|
+
team: z.string().optional().describe("The team ID or mention name of the team the story belongs to. Required unless a workflow is specified."),
|
|
22064
|
+
workflow: z.number().optional().describe("The workflow ID to add the story to. Required unless a team is specified.")
|
|
21729
22065
|
}, async ({ name: name2, description, type, owner, epic, team, workflow }) => await tools.createStory({
|
|
21730
22066
|
name: name2,
|
|
21731
22067
|
description,
|
|
@@ -21735,6 +22071,21 @@ The story will be added to the default state for the workflow.
|
|
|
21735
22071
|
team,
|
|
21736
22072
|
workflow
|
|
21737
22073
|
}));
|
|
22074
|
+
server.tool("update-story", "Update an existing Shortcut story. Only provide fields you want to update. The story public ID will always be included in updates.", {
|
|
22075
|
+
storyPublicId: z.number().positive().describe("The public ID of the story to update"),
|
|
22076
|
+
name: z.string().max(512).optional().describe("The name of the story"),
|
|
22077
|
+
description: z.string().max(1e4).optional().describe("The description of the story"),
|
|
22078
|
+
type: z.enum(["feature", "bug", "chore"]).optional().describe("The type of the story"),
|
|
22079
|
+
epic: z.number().nullable().optional().describe("The epic id of the epic the story belongs to, or null to unset"),
|
|
22080
|
+
estimate: z.number().nullable().optional().describe("The point estimate of the story, or null to unset"),
|
|
22081
|
+
owner_ids: z.array(z.string()).optional().describe("Array of user UUIDs to assign as owners of the story"),
|
|
22082
|
+
workflow_state_id: z.number().optional().describe("The workflow state ID to move the story to"),
|
|
22083
|
+
labels: z.array(z.object({
|
|
22084
|
+
name: z.string().describe("The name of the label"),
|
|
22085
|
+
color: z.string().optional().describe("The color of the label"),
|
|
22086
|
+
description: z.string().optional().describe("The description of the label")
|
|
22087
|
+
})).optional().describe("Labels to assign to the story")
|
|
22088
|
+
}, async (params) => await tools.updateStory(params));
|
|
21738
22089
|
server.tool("assign-current-user-as-owner", "Assign the current user as the owner of a story", {
|
|
21739
22090
|
storyPublicId: z.number().positive().describe("The public ID of the story")
|
|
21740
22091
|
}, async ({ storyPublicId }) => await tools.assignCurrentUserAsOwner(storyPublicId));
|
|
@@ -21745,6 +22096,22 @@ The story will be added to the default state for the workflow.
|
|
|
21745
22096
|
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
21746
22097
|
text: z.string().min(1).describe("The text of the comment")
|
|
21747
22098
|
}, async (params) => await tools.createStoryComment(params));
|
|
22099
|
+
server.tool("add-task-to-story", "Add a task to a story", {
|
|
22100
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
22101
|
+
taskDescription: z.string().min(1).describe("The description of the task"),
|
|
22102
|
+
taskOwnerIds: z.array(z.string()).optional().describe("Array of user IDs to assign as owners of the task")
|
|
22103
|
+
}, async (params) => await tools.addTaskToStory(params));
|
|
22104
|
+
server.tool("add-relation-to-story", "Add a relation to a story", {
|
|
22105
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
22106
|
+
relatedStoryPublicId: z.number().positive().describe("The public ID of the related story")
|
|
22107
|
+
}, async (params) => await tools.addRelationToStory(params));
|
|
22108
|
+
server.tool("update-task", "Update a task in a story", {
|
|
22109
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
22110
|
+
taskPublicId: z.number().positive().describe("The public ID of the task"),
|
|
22111
|
+
taskDescription: z.string().optional().describe("The description of the task"),
|
|
22112
|
+
taskOwnerIds: z.array(z.string()).optional().describe("Array of user IDs to assign as owners of the task"),
|
|
22113
|
+
isCompleted: z.boolean().optional().describe("Whether the task is completed or not")
|
|
22114
|
+
}, async (params) => await tools.updateTask(params));
|
|
21748
22115
|
return tools;
|
|
21749
22116
|
}
|
|
21750
22117
|
async assignCurrentUserAsOwner(storyPublicId) {
|
|
@@ -21849,11 +22216,11 @@ Completed: ${story.completed ? "Yes" : "No"}
|
|
|
21849
22216
|
Started: ${story.started ? "Yes" : "No"}
|
|
21850
22217
|
Blocked: ${story.blocked ? "Yes" : "No"}
|
|
21851
22218
|
Blocking: ${story.blocker ? "Yes" : "No"}
|
|
21852
|
-
Due date: ${story.deadline ? story.deadline : "
|
|
21853
|
-
Team: ${story.group_id ? `${story.group_id}` : "
|
|
22219
|
+
Due date: ${story.deadline ? story.deadline : "(none)"}
|
|
22220
|
+
Team: ${story.group_id ? `${story.group_id}` : "(none)"}
|
|
21854
22221
|
${formatMemberList(story.owner_ids, users, "Owners")}
|
|
21855
|
-
Epic: ${story.epic_id ? `${story.epic_id}` : "
|
|
21856
|
-
Iteration: ${story.iteration_id ? `${story.iteration_id}` : "
|
|
22222
|
+
Epic: ${story.epic_id ? `${story.epic_id}` : "(none)"}
|
|
22223
|
+
Iteration: ${story.iteration_id ? `${story.iteration_id}` : "(none)"}
|
|
21857
22224
|
|
|
21858
22225
|
Description:
|
|
21859
22226
|
${story.description}
|
|
@@ -21887,6 +22254,103 @@ ${comment.text || ""}`;
|
|
|
21887
22254
|
const storyComment = await this.client.createStoryComment(storyPublicId, { text });
|
|
21888
22255
|
return this.toResult(`Created comment on story sc-${storyPublicId}. Comment URL: ${storyComment.app_url}.`);
|
|
21889
22256
|
}
|
|
22257
|
+
async updateStory({
|
|
22258
|
+
storyPublicId,
|
|
22259
|
+
...updates
|
|
22260
|
+
}) {
|
|
22261
|
+
if (!storyPublicId)
|
|
22262
|
+
throw new Error("Story public ID is required");
|
|
22263
|
+
const story = await this.client.getStory(storyPublicId);
|
|
22264
|
+
if (!story)
|
|
22265
|
+
throw new Error(`Failed to retrieve Shortcut story with public ID: ${storyPublicId}`);
|
|
22266
|
+
const updateParams = {};
|
|
22267
|
+
if (updates.name !== undefined)
|
|
22268
|
+
updateParams.name = updates.name;
|
|
22269
|
+
if (updates.description !== undefined)
|
|
22270
|
+
updateParams.description = updates.description;
|
|
22271
|
+
if (updates.type !== undefined)
|
|
22272
|
+
updateParams.story_type = updates.type;
|
|
22273
|
+
if (updates.epic !== undefined)
|
|
22274
|
+
updateParams.epic_id = updates.epic;
|
|
22275
|
+
if (updates.estimate !== undefined)
|
|
22276
|
+
updateParams.estimate = updates.estimate;
|
|
22277
|
+
if (updates.owner_ids !== undefined)
|
|
22278
|
+
updateParams.owner_ids = updates.owner_ids;
|
|
22279
|
+
if (updates.workflow_state_id !== undefined)
|
|
22280
|
+
updateParams.workflow_state_id = updates.workflow_state_id;
|
|
22281
|
+
if (updates.labels !== undefined)
|
|
22282
|
+
updateParams.labels = updates.labels;
|
|
22283
|
+
const updatedStory = await this.client.updateStory(storyPublicId, updateParams);
|
|
22284
|
+
return this.toResult(`Updated story sc-${storyPublicId}. Story URL: ${updatedStory.app_url}`);
|
|
22285
|
+
}
|
|
22286
|
+
async addTaskToStory({
|
|
22287
|
+
storyPublicId,
|
|
22288
|
+
taskDescription,
|
|
22289
|
+
taskOwnerIds
|
|
22290
|
+
}) {
|
|
22291
|
+
if (!storyPublicId)
|
|
22292
|
+
throw new Error("Story public ID is required");
|
|
22293
|
+
if (!taskDescription)
|
|
22294
|
+
throw new Error("Task description is required");
|
|
22295
|
+
const story = await this.client.getStory(storyPublicId);
|
|
22296
|
+
if (!story)
|
|
22297
|
+
throw new Error(`Failed to retrieve Shortcut story with public ID: ${storyPublicId}`);
|
|
22298
|
+
if (taskOwnerIds?.length) {
|
|
22299
|
+
const owners = await this.client.getUserMap(taskOwnerIds);
|
|
22300
|
+
if (!owners)
|
|
22301
|
+
throw new Error(`Failed to retrieve users with IDs: ${taskOwnerIds.join(", ")}`);
|
|
22302
|
+
}
|
|
22303
|
+
const task = await this.client.addTaskToStory(storyPublicId, {
|
|
22304
|
+
description: taskDescription,
|
|
22305
|
+
ownerIds: taskOwnerIds
|
|
22306
|
+
});
|
|
22307
|
+
return this.toResult(`Created task for story sc-${storyPublicId}. Task ID: ${task.id}.`);
|
|
22308
|
+
}
|
|
22309
|
+
async updateTask({
|
|
22310
|
+
storyPublicId,
|
|
22311
|
+
taskPublicId,
|
|
22312
|
+
taskDescription,
|
|
22313
|
+
taskOwnerIds,
|
|
22314
|
+
isCompleted
|
|
22315
|
+
}) {
|
|
22316
|
+
if (!storyPublicId)
|
|
22317
|
+
throw new Error("Story public ID is required");
|
|
22318
|
+
if (!taskPublicId)
|
|
22319
|
+
throw new Error("Task public ID is required");
|
|
22320
|
+
const story = await this.client.getStory(storyPublicId);
|
|
22321
|
+
if (!story)
|
|
22322
|
+
throw new Error(`Failed to retrieve Shortcut story with public ID: ${storyPublicId}`);
|
|
22323
|
+
const task = await this.client.getTask(storyPublicId, taskPublicId);
|
|
22324
|
+
if (!task)
|
|
22325
|
+
throw new Error(`Failed to retrieve Shortcut task with public ID: ${taskPublicId}`);
|
|
22326
|
+
const updatedTask = await this.client.updateTask(storyPublicId, taskPublicId, {
|
|
22327
|
+
description: taskDescription,
|
|
22328
|
+
ownerIds: taskOwnerIds,
|
|
22329
|
+
isCompleted
|
|
22330
|
+
});
|
|
22331
|
+
let message = `Updated task for story sc-${storyPublicId}. Task ID: ${updatedTask.id}.`;
|
|
22332
|
+
if (isCompleted) {
|
|
22333
|
+
message = `Completed task for story sc-${storyPublicId}. Task ID: ${updatedTask.id}.`;
|
|
22334
|
+
}
|
|
22335
|
+
return this.toResult(message);
|
|
22336
|
+
}
|
|
22337
|
+
async addRelationToStory({
|
|
22338
|
+
storyPublicId,
|
|
22339
|
+
relatedStoryPublicId
|
|
22340
|
+
}) {
|
|
22341
|
+
if (!storyPublicId)
|
|
22342
|
+
throw new Error("Story public ID is required");
|
|
22343
|
+
if (!relatedStoryPublicId)
|
|
22344
|
+
throw new Error("Related story public ID is required");
|
|
22345
|
+
const story = await this.client.getStory(storyPublicId);
|
|
22346
|
+
if (!story)
|
|
22347
|
+
throw new Error(`Failed to retrieve Shortcut story with public ID: ${storyPublicId}`);
|
|
22348
|
+
const relatedStory = await this.client.getStory(relatedStoryPublicId);
|
|
22349
|
+
if (!relatedStory)
|
|
22350
|
+
throw new Error(`Failed to retrieve Shortcut story with public ID: ${relatedStoryPublicId}`);
|
|
22351
|
+
await this.client.addRelationToStory(storyPublicId, relatedStoryPublicId);
|
|
22352
|
+
return this.toResult(`Added relation between stories sc-${storyPublicId} and sc-${relatedStoryPublicId}.`);
|
|
22353
|
+
}
|
|
21890
22354
|
}
|
|
21891
22355
|
|
|
21892
22356
|
// src/tools/teams.ts
|
|
@@ -21930,6 +22394,7 @@ class UserTools extends BaseTools {
|
|
|
21930
22394
|
static create(client, server) {
|
|
21931
22395
|
const tools = new UserTools(client);
|
|
21932
22396
|
server.tool("get-current-user", "Get the current user", async () => await tools.getCurrentUser());
|
|
22397
|
+
server.tool("list-members", "Get all members", async () => await tools.listMembers());
|
|
21933
22398
|
return tools;
|
|
21934
22399
|
}
|
|
21935
22400
|
async getCurrentUser() {
|
|
@@ -21941,6 +22406,10 @@ Id: ${user2.id}
|
|
|
21941
22406
|
Mention name: @${user2.mention_name}
|
|
21942
22407
|
Full name: ${user2.name}`);
|
|
21943
22408
|
}
|
|
22409
|
+
async listMembers() {
|
|
22410
|
+
const members = await this.client.listMembers();
|
|
22411
|
+
return this.toResult(`Found ${members.length} members, ${formatUsersList(members)}`);
|
|
22412
|
+
}
|
|
21944
22413
|
}
|
|
21945
22414
|
|
|
21946
22415
|
// src/tools/workflows.ts
|
package/package.json
CHANGED
|
@@ -6,15 +6,21 @@
|
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/useshortcut/mcp-server-shortcut.git"
|
|
8
8
|
},
|
|
9
|
-
"keywords": [
|
|
9
|
+
"keywords": [
|
|
10
|
+
"shortcut",
|
|
11
|
+
"mcp",
|
|
12
|
+
"modelcontextprotocol"
|
|
13
|
+
],
|
|
10
14
|
"license": "MIT",
|
|
11
|
-
"version": "0.
|
|
15
|
+
"version": "0.5.1",
|
|
12
16
|
"type": "module",
|
|
13
17
|
"main": "dist/index.js",
|
|
14
18
|
"bin": {
|
|
15
19
|
"mcp-server-shortcut": "dist/index.js"
|
|
16
20
|
},
|
|
17
|
-
"files": [
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
18
24
|
"devDependencies": {
|
|
19
25
|
"@biomejs/biome": "^1.9.4",
|
|
20
26
|
"@types/bun": "latest",
|
|
@@ -26,9 +32,9 @@
|
|
|
26
32
|
"typescript": "^5"
|
|
27
33
|
},
|
|
28
34
|
"dependencies": {
|
|
29
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.11.3",
|
|
30
36
|
"@shortcut/client": "^1.1.0",
|
|
31
|
-
"zod": "^3.24.
|
|
37
|
+
"zod": "^3.24.4"
|
|
32
38
|
},
|
|
33
39
|
"scripts": {
|
|
34
40
|
"test": "bun test",
|