@shortcut/mcp 0.12.0 → 0.13.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.
- package/README.md +86 -0
- package/dist/index.js +127 -122
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -125,6 +125,92 @@ Or you can edit the local JSON file directly:
|
|
|
125
125
|
}
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
+
## Available Tools
|
|
129
|
+
|
|
130
|
+
### Stories
|
|
131
|
+
|
|
132
|
+
- **get-story** - Get a single Shortcut story by ID
|
|
133
|
+
- **search-stories** - Find Shortcut stories with filtering and search options
|
|
134
|
+
- **get-story-branch-name** - Get the recommended branch name (based on workspace settings) for a specific story.
|
|
135
|
+
- **create-story** - Create a new Shortcut story
|
|
136
|
+
- **update-story** - Update an existing Shortcut story
|
|
137
|
+
- **upload-file-to-story** - Upload a file and link it to a story
|
|
138
|
+
- **assign-current-user-as-owner** - Assign the current user as the owner of a story
|
|
139
|
+
- **unassign-current-user-as-owner** - Unassign the current user as the owner of a story
|
|
140
|
+
- **create-story-comment** - Create a comment on a story
|
|
141
|
+
- **add-task-to-story** - Add a task to a story
|
|
142
|
+
- **update-task** - Update a task in a story
|
|
143
|
+
- **add-relation-to-story** - Add a story relationship (relates to, blocks, duplicates, etc.)
|
|
144
|
+
- **add-external-link-to-story** - Add an external link to a Shortcut story
|
|
145
|
+
- **remove-external-link-from-story** - Remove an external link from a Shortcut story
|
|
146
|
+
- **set-story-external-links** - Replace all external links on a story with a new set of links
|
|
147
|
+
- **get-stories-by-external-link** - Find all stories that contain a specific external link
|
|
148
|
+
|
|
149
|
+
### Epics
|
|
150
|
+
|
|
151
|
+
- **get-epic** - Get a Shortcut epic by ID
|
|
152
|
+
- **search-epics** - Find Shortcut epics with filtering and search options
|
|
153
|
+
- **create-epic** - Create a new Shortcut epic
|
|
154
|
+
|
|
155
|
+
### Iterations
|
|
156
|
+
|
|
157
|
+
- **get-iteration-stories** - Get stories in a specific iteration by iteration ID
|
|
158
|
+
- **get-iteration** - Get a Shortcut iteration by ID
|
|
159
|
+
- **search-iterations** - Find Shortcut iterations with filtering and search options
|
|
160
|
+
- **create-iteration** - Create a new Shortcut iteration with start/end dates
|
|
161
|
+
- **get-active-iterations** - Get active iterations for the current user based on team memberships
|
|
162
|
+
- **get-upcoming-iterations** - Get upcoming iterations for the current user based on team memberships
|
|
163
|
+
|
|
164
|
+
### Objectives
|
|
165
|
+
|
|
166
|
+
- **get-objective** - Get a Shortcut objective by ID
|
|
167
|
+
- **search-objectives** - Find Shortcut objectives with filtering and search options
|
|
168
|
+
|
|
169
|
+
### Teams
|
|
170
|
+
|
|
171
|
+
- **get-team** - Get a Shortcut team by ID
|
|
172
|
+
- **list-teams** - List all Shortcut teams
|
|
173
|
+
|
|
174
|
+
### Workflows
|
|
175
|
+
|
|
176
|
+
- **get-default-workflow** - Get the default workflow for a specific team or the workspace default
|
|
177
|
+
- **get-workflow** - Get a Shortcut workflow by ID
|
|
178
|
+
- **list-workflows** - List all Shortcut workflows
|
|
179
|
+
|
|
180
|
+
### Users
|
|
181
|
+
|
|
182
|
+
- **get-current-user** - Get the current user information
|
|
183
|
+
- **get-current-user-teams** - Get a list of teams where the current user is a member
|
|
184
|
+
- **list-users** - Get all workspace users
|
|
185
|
+
|
|
186
|
+
### Documents
|
|
187
|
+
|
|
188
|
+
- **create-document** - Create a new document in Shortcut with HTML content
|
|
189
|
+
|
|
190
|
+
## Read-only mode
|
|
191
|
+
|
|
192
|
+
You can run the MCP server in read-only mode by setting the `SHORTCUT_READONLY` environment variable to `true`. This will disable all tools that modify data in Shortcut.
|
|
193
|
+
|
|
194
|
+
Example:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"mcpServers": {
|
|
199
|
+
"shortcut": {
|
|
200
|
+
"command": "npx",
|
|
201
|
+
"args": [
|
|
202
|
+
"-y",
|
|
203
|
+
"@shortcut/mcp@latest"
|
|
204
|
+
],
|
|
205
|
+
"env": {
|
|
206
|
+
"SHORTCUT_API_TOKEN": "<YOUR_SHORTCUT_API_TOKEN>",
|
|
207
|
+
"SHORTCUT_READONLY": "true"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
128
214
|
## Issues and Troubleshooting
|
|
129
215
|
|
|
130
216
|
Before doing anything else, please make sure you are running the latest version!
|
package/dist/index.js
CHANGED
|
@@ -450,7 +450,7 @@ var ShortcutClientWrapper = class {
|
|
|
450
450
|
//#endregion
|
|
451
451
|
//#region package.json
|
|
452
452
|
var name = "@shortcut/mcp";
|
|
453
|
-
var version = "0.
|
|
453
|
+
var version = "0.13.0";
|
|
454
454
|
|
|
455
455
|
//#endregion
|
|
456
456
|
//#region src/tools/base.ts
|
|
@@ -458,8 +458,9 @@ var version = "0.12.0";
|
|
|
458
458
|
* Base class for all tools.
|
|
459
459
|
*/
|
|
460
460
|
var BaseTools = class {
|
|
461
|
-
constructor(client$1) {
|
|
461
|
+
constructor(client$1, isReadonly$1 = false) {
|
|
462
462
|
this.client = client$1;
|
|
463
|
+
this.isReadonly = isReadonly$1;
|
|
463
464
|
}
|
|
464
465
|
renameEntityProps(entity) {
|
|
465
466
|
if (!entity || typeof entity !== "object") return entity;
|
|
@@ -791,12 +792,13 @@ var BaseTools = class {
|
|
|
791
792
|
//#endregion
|
|
792
793
|
//#region src/tools/documents.ts
|
|
793
794
|
var DocumentTools = class DocumentTools extends BaseTools {
|
|
794
|
-
static create(client$1, server$1) {
|
|
795
|
-
const tools = new DocumentTools(client$1);
|
|
796
|
-
server$1.tool("create-document", "Create a new document in Shortcut with a title and content. Returns the document's id, title, and app_url. Note: Use HTML markup for the content (e.g., <p>, <h1>, <ul>, <strong>) rather than Markdown.", {
|
|
795
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
796
|
+
const tools = new DocumentTools(client$1, isReadonly$1);
|
|
797
|
+
if (!isReadonly$1) server$1.tool("create-document", "Create a new document in Shortcut with a title and content. Returns the document's id, title, and app_url. Note: Use HTML markup for the content (e.g., <p>, <h1>, <ul>, <strong>) rather than Markdown.", {
|
|
797
798
|
title: z.string().max(256).describe("The title for the new document (max 256 characters)"),
|
|
798
799
|
content: z.string().describe("The content for the new document in HTML format (e.g., <p>Hello</p>, <h1>Title</h1>, <ul><li>Item</li></ul>)")
|
|
799
800
|
}, async ({ title, content }) => await tools.createDocument(title, content));
|
|
801
|
+
return tools;
|
|
800
802
|
}
|
|
801
803
|
async createDocument(title, content) {
|
|
802
804
|
try {
|
|
@@ -874,8 +876,8 @@ const user = (field) => z.string().optional().describe(`Find entities where the
|
|
|
874
876
|
//#endregion
|
|
875
877
|
//#region src/tools/epics.ts
|
|
876
878
|
var EpicTools = class EpicTools extends BaseTools {
|
|
877
|
-
static create(client$1, server$1) {
|
|
878
|
-
const tools = new EpicTools(client$1);
|
|
879
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
880
|
+
const tools = new EpicTools(client$1, isReadonly$1);
|
|
879
881
|
server$1.tool("get-epic", "Get a Shortcut epic by public ID", {
|
|
880
882
|
epicPublicId: z.number().positive().describe("The public ID of the epic to get"),
|
|
881
883
|
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")
|
|
@@ -909,7 +911,7 @@ var EpicTools = class EpicTools extends BaseTools {
|
|
|
909
911
|
completed: date(),
|
|
910
912
|
due: date()
|
|
911
913
|
}, async ({ nextPageToken,...params }) => await tools.searchEpics(params, nextPageToken));
|
|
912
|
-
server$1.tool("create-epic", "Create a new Shortcut epic.", {
|
|
914
|
+
if (!isReadonly$1) server$1.tool("create-epic", "Create a new Shortcut epic.", {
|
|
913
915
|
name: z.string().describe("The name of the epic"),
|
|
914
916
|
owner: z.string().optional().describe("The user ID of the owner of the epic"),
|
|
915
917
|
description: z.string().optional().describe("A description of the epic"),
|
|
@@ -944,8 +946,8 @@ var EpicTools = class EpicTools extends BaseTools {
|
|
|
944
946
|
//#endregion
|
|
945
947
|
//#region src/tools/iterations.ts
|
|
946
948
|
var IterationTools = class IterationTools extends BaseTools {
|
|
947
|
-
static create(client$1, server$1) {
|
|
948
|
-
const tools = new IterationTools(client$1);
|
|
949
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
950
|
+
const tools = new IterationTools(client$1, isReadonly$1);
|
|
949
951
|
server$1.tool("get-iteration-stories", "Get stories in a specific iteration by iteration public ID", {
|
|
950
952
|
iterationPublicId: z.number().positive().describe("The public ID of the iteration"),
|
|
951
953
|
includeStoryDescriptions: z.boolean().optional().default(false).describe("Indicate whether story descriptions should be included. Including descriptions may take longer and will increase the size of the response.")
|
|
@@ -970,7 +972,7 @@ var IterationTools = class IterationTools extends BaseTools {
|
|
|
970
972
|
startDate: date(),
|
|
971
973
|
endDate: date()
|
|
972
974
|
}, async ({ nextPageToken,...params }) => await tools.searchIterations(params, nextPageToken));
|
|
973
|
-
server$1.tool("create-iteration", "Create a new Shortcut iteration", {
|
|
975
|
+
if (!isReadonly$1) server$1.tool("create-iteration", "Create a new Shortcut iteration", {
|
|
974
976
|
name: z.string().describe("The name of the iteration"),
|
|
975
977
|
startDate: z.string().describe("The start date of the iteration in YYYY-MM-DD format"),
|
|
976
978
|
endDate: z.string().describe("The end date of the iteration in YYYY-MM-DD format"),
|
|
@@ -1055,8 +1057,8 @@ var IterationTools = class IterationTools extends BaseTools {
|
|
|
1055
1057
|
//#endregion
|
|
1056
1058
|
//#region src/tools/objectives.ts
|
|
1057
1059
|
var ObjectiveTools = class ObjectiveTools extends BaseTools {
|
|
1058
|
-
static create(client$1, server$1) {
|
|
1059
|
-
const tools = new ObjectiveTools(client$1);
|
|
1060
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
1061
|
+
const tools = new ObjectiveTools(client$1, isReadonly$1);
|
|
1060
1062
|
server$1.tool("get-objective", "Get a Shortcut objective by public ID", {
|
|
1061
1063
|
objectivePublicId: z.number().positive().describe("The public ID of the objective to get"),
|
|
1062
1064
|
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")
|
|
@@ -1103,8 +1105,8 @@ var ObjectiveTools = class ObjectiveTools extends BaseTools {
|
|
|
1103
1105
|
//#endregion
|
|
1104
1106
|
//#region src/tools/stories.ts
|
|
1105
1107
|
var StoryTools = class StoryTools extends BaseTools {
|
|
1106
|
-
static create(client$1, server$1) {
|
|
1107
|
-
const tools = new StoryTools(client$1);
|
|
1108
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
1109
|
+
const tools = new StoryTools(client$1, isReadonly$1);
|
|
1108
1110
|
server$1.tool("get-story", "Get a Shortcut story by public ID", {
|
|
1109
1111
|
storyPublicId: z.number().positive().describe("The public ID of the story to get"),
|
|
1110
1112
|
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")
|
|
@@ -1161,100 +1163,102 @@ var StoryTools = class StoryTools extends BaseTools {
|
|
|
1161
1163
|
due: date()
|
|
1162
1164
|
}, async ({ nextPageToken,...params }) => await tools.searchStories(params, nextPageToken));
|
|
1163
1165
|
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));
|
|
1164
|
-
|
|
1166
|
+
if (!isReadonly$1) {
|
|
1167
|
+
server$1.tool("create-story", `Create a new Shortcut story.
|
|
1165
1168
|
Name is required, and either a Team or Workflow must be specified:
|
|
1166
1169
|
- If only Team is specified, we will use the default workflow for that team.
|
|
1167
1170
|
- If Workflow is specified, it will be used regardless of Team.
|
|
1168
1171
|
The story will be added to the default state for the workflow.
|
|
1169
1172
|
`, {
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
"
|
|
1232
|
-
"
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
"
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1173
|
+
name: z.string().min(1).max(512).describe("The name of the story. Required."),
|
|
1174
|
+
description: z.string().max(1e4).optional().describe("The description of the story"),
|
|
1175
|
+
type: z.enum([
|
|
1176
|
+
"feature",
|
|
1177
|
+
"bug",
|
|
1178
|
+
"chore"
|
|
1179
|
+
]).default("feature").describe("The type of the story"),
|
|
1180
|
+
owner: z.string().optional().describe("The user id of the owner of the story"),
|
|
1181
|
+
epic: z.number().optional().describe("The epic id of the epic the story belongs to"),
|
|
1182
|
+
iteration: z.number().optional().describe("The iteration id of the iteration the story belongs to"),
|
|
1183
|
+
team: z.string().optional().describe("The team ID or mention name of the team the story belongs to. Required unless a workflow is specified."),
|
|
1184
|
+
workflow: z.number().optional().describe("The workflow ID to add the story to. Required unless a team is specified.")
|
|
1185
|
+
}, async ({ name: name$1, description, type, owner, epic, iteration, team, workflow }) => await tools.createStory({
|
|
1186
|
+
name: name$1,
|
|
1187
|
+
description,
|
|
1188
|
+
type,
|
|
1189
|
+
owner,
|
|
1190
|
+
epic,
|
|
1191
|
+
iteration,
|
|
1192
|
+
team,
|
|
1193
|
+
workflow
|
|
1194
|
+
}));
|
|
1195
|
+
server$1.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.", {
|
|
1196
|
+
storyPublicId: z.number().positive().describe("The public ID of the story to update"),
|
|
1197
|
+
name: z.string().max(512).optional().describe("The name of the story"),
|
|
1198
|
+
description: z.string().max(1e4).optional().describe("The description of the story"),
|
|
1199
|
+
type: z.enum([
|
|
1200
|
+
"feature",
|
|
1201
|
+
"bug",
|
|
1202
|
+
"chore"
|
|
1203
|
+
]).optional().describe("The type of the story"),
|
|
1204
|
+
epic: z.number().nullable().optional().describe("The epic id of the epic the story belongs to, or null to unset"),
|
|
1205
|
+
estimate: z.number().nullable().optional().describe("The point estimate of the story, or null to unset"),
|
|
1206
|
+
iteration: z.number().nullable().optional().describe("The iteration id of the iteration the story belongs to, or null to unset"),
|
|
1207
|
+
owner_ids: z.array(z.string()).optional().describe("Array of user UUIDs to assign as owners of the story"),
|
|
1208
|
+
workflow_state_id: z.number().optional().describe("The workflow state ID to move the story to"),
|
|
1209
|
+
labels: z.array(z.object({
|
|
1210
|
+
name: z.string().describe("The name of the label"),
|
|
1211
|
+
color: z.string().optional().describe("The color of the label"),
|
|
1212
|
+
description: z.string().optional().describe("The description of the label")
|
|
1213
|
+
})).optional().describe("Labels to assign to the story")
|
|
1214
|
+
}, async (params) => await tools.updateStory(params));
|
|
1215
|
+
server$1.tool("upload-file-to-story", "Upload a file and link it to a story.", {
|
|
1216
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1217
|
+
filePath: z.string().describe("The path to the file to upload")
|
|
1218
|
+
}, async ({ storyPublicId, filePath }) => await tools.uploadFileToStory(storyPublicId, filePath));
|
|
1219
|
+
server$1.tool("assign-current-user-as-owner", "Assign the current user as the owner of a story", { storyPublicId: z.number().positive().describe("The public ID of the story") }, async ({ storyPublicId }) => await tools.assignCurrentUserAsOwner(storyPublicId));
|
|
1220
|
+
server$1.tool("unassign-current-user-as-owner", "Unassign the current user as the owner of a story", { storyPublicId: z.number().positive().describe("The public ID of the story") }, async ({ storyPublicId }) => await tools.unassignCurrentUserAsOwner(storyPublicId));
|
|
1221
|
+
server$1.tool("create-story-comment", "Create a comment on a story", {
|
|
1222
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1223
|
+
text: z.string().min(1).describe("The text of the comment")
|
|
1224
|
+
}, async (params) => await tools.createStoryComment(params));
|
|
1225
|
+
server$1.tool("add-task-to-story", "Add a task to a story", {
|
|
1226
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1227
|
+
taskDescription: z.string().min(1).describe("The description of the task"),
|
|
1228
|
+
taskOwnerIds: z.array(z.string()).optional().describe("Array of user IDs to assign as owners of the task")
|
|
1229
|
+
}, async (params) => await tools.addTaskToStory(params));
|
|
1230
|
+
server$1.tool("update-task", "Update a task in a story", {
|
|
1231
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1232
|
+
taskPublicId: z.number().positive().describe("The public ID of the task"),
|
|
1233
|
+
taskDescription: z.string().optional().describe("The description of the task"),
|
|
1234
|
+
taskOwnerIds: z.array(z.string()).optional().describe("Array of user IDs to assign as owners of the task"),
|
|
1235
|
+
isCompleted: z.boolean().optional().describe("Whether the task is completed or not")
|
|
1236
|
+
}, async (params) => await tools.updateTask(params));
|
|
1237
|
+
server$1.tool("add-relation-to-story", "Add a story relationship to a story", {
|
|
1238
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1239
|
+
relatedStoryPublicId: z.number().positive().describe("The public ID of the related story"),
|
|
1240
|
+
relationshipType: z.enum([
|
|
1241
|
+
"relates to",
|
|
1242
|
+
"blocks",
|
|
1243
|
+
"blocked by",
|
|
1244
|
+
"duplicates",
|
|
1245
|
+
"duplicated by"
|
|
1246
|
+
]).optional().default("relates to").describe("The type of relationship")
|
|
1247
|
+
}, async (params) => await tools.addRelationToStory(params));
|
|
1248
|
+
server$1.tool("add-external-link-to-story", "Add an external link to a Shortcut story", {
|
|
1249
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1250
|
+
externalLink: z.string().url().max(2048).describe("The external link URL to add")
|
|
1251
|
+
}, async ({ storyPublicId, externalLink }) => await tools.addExternalLinkToStory(storyPublicId, externalLink));
|
|
1252
|
+
server$1.tool("remove-external-link-from-story", "Remove an external link from a Shortcut story", {
|
|
1253
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1254
|
+
externalLink: z.string().url().max(2048).describe("The external link URL to remove")
|
|
1255
|
+
}, async ({ storyPublicId, externalLink }) => await tools.removeExternalLinkFromStory(storyPublicId, externalLink));
|
|
1256
|
+
server$1.tool("set-story-external-links", "Replace all external links on a story with a new set of links", {
|
|
1257
|
+
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1258
|
+
externalLinks: z.array(z.string().url().max(2048)).describe("Array of external link URLs to set (replaces all existing links)")
|
|
1259
|
+
}, async ({ storyPublicId, externalLinks }) => await tools.setStoryExternalLinks(storyPublicId, externalLinks));
|
|
1260
|
+
}
|
|
1253
1261
|
server$1.tool("get-stories-by-external-link", "Find all stories that contain a specific external link", { externalLink: z.string().url().max(2048).describe("The external link URL to search for") }, async ({ externalLink }) => await tools.getStoriesByExternalLink(externalLink));
|
|
1254
|
-
server$1.tool("set-story-external-links", "Replace all external links on a story with a new set of links", {
|
|
1255
|
-
storyPublicId: z.number().positive().describe("The public ID of the story"),
|
|
1256
|
-
externalLinks: z.array(z.string().url().max(2048)).describe("Array of external link URLs to set (replaces all existing links)")
|
|
1257
|
-
}, async ({ storyPublicId, externalLinks }) => await tools.setStoryExternalLinks(storyPublicId, externalLinks));
|
|
1258
1262
|
return tools;
|
|
1259
1263
|
}
|
|
1260
1264
|
async assignCurrentUserAsOwner(storyPublicId) {
|
|
@@ -1433,8 +1437,8 @@ The story will be added to the default state for the workflow.
|
|
|
1433
1437
|
//#endregion
|
|
1434
1438
|
//#region src/tools/teams.ts
|
|
1435
1439
|
var TeamTools = class TeamTools extends BaseTools {
|
|
1436
|
-
static create(client$1, server$1) {
|
|
1437
|
-
const tools = new TeamTools(client$1);
|
|
1440
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
1441
|
+
const tools = new TeamTools(client$1, isReadonly$1);
|
|
1438
1442
|
server$1.tool("get-team", "Get a Shortcut team by public ID", {
|
|
1439
1443
|
teamPublicId: z.string().describe("The public ID of the team to get"),
|
|
1440
1444
|
full: z.boolean().optional().default(false).describe("True to return all team fields from the API. False to return a slim version that excludes uncommon fields")
|
|
@@ -1457,11 +1461,11 @@ var TeamTools = class TeamTools extends BaseTools {
|
|
|
1457
1461
|
//#endregion
|
|
1458
1462
|
//#region src/tools/user.ts
|
|
1459
1463
|
var UserTools = class UserTools extends BaseTools {
|
|
1460
|
-
static create(client$1, server$1) {
|
|
1461
|
-
const tools = new UserTools(client$1);
|
|
1464
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
1465
|
+
const tools = new UserTools(client$1, isReadonly$1);
|
|
1462
1466
|
server$1.tool("get-current-user", "Get the current user", async () => await tools.getCurrentUser());
|
|
1463
1467
|
server$1.tool("get-current-user-teams", "Get a list of teams where the current user is a member", async () => await tools.getCurrentUserTeams());
|
|
1464
|
-
server$1.tool("list-
|
|
1468
|
+
server$1.tool("list-users", "Get all users", async () => await tools.listMembers());
|
|
1465
1469
|
return tools;
|
|
1466
1470
|
}
|
|
1467
1471
|
async getCurrentUser() {
|
|
@@ -1490,8 +1494,8 @@ var UserTools = class UserTools extends BaseTools {
|
|
|
1490
1494
|
//#endregion
|
|
1491
1495
|
//#region src/tools/workflows.ts
|
|
1492
1496
|
var WorkflowTools = class WorkflowTools extends BaseTools {
|
|
1493
|
-
static create(client$1, server$1) {
|
|
1494
|
-
const tools = new WorkflowTools(client$1);
|
|
1497
|
+
static create(client$1, server$1, isReadonly$1 = false) {
|
|
1498
|
+
const tools = new WorkflowTools(client$1, isReadonly$1);
|
|
1495
1499
|
server$1.tool("get-default-workflow", "Get the default workflow for a specific team or the global default if no team is specified.", { teamPublicId: z.string().optional().describe("The public ID of the team to get the default workflow for.") }, async ({ teamPublicId }) => await tools.getDefaultWorkflow(teamPublicId));
|
|
1496
1500
|
server$1.tool("get-workflow", "Get a Shortcut workflow by public ID", {
|
|
1497
1501
|
workflowPublicId: z.number().positive().describe("The public ID of the workflow to get"),
|
|
@@ -1530,10 +1534,11 @@ var WorkflowTools = class WorkflowTools extends BaseTools {
|
|
|
1530
1534
|
//#endregion
|
|
1531
1535
|
//#region src/server.ts
|
|
1532
1536
|
let apiToken = process.env.SHORTCUT_API_TOKEN;
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
if (name$1 === "SHORTCUT_API_TOKEN") apiToken =
|
|
1536
|
-
|
|
1537
|
+
let isReadonly = process.env.SHORTCUT_READONLY === "true";
|
|
1538
|
+
if (process.argv.length >= 3) process.argv.slice(2).map((arg) => arg.split("=")).forEach(([name$1, value]) => {
|
|
1539
|
+
if (name$1 === "SHORTCUT_API_TOKEN") apiToken = value;
|
|
1540
|
+
if (name$1 === "SHORTCUT_READONLY") isReadonly = value === "true";
|
|
1541
|
+
});
|
|
1537
1542
|
if (!apiToken) {
|
|
1538
1543
|
console.error("SHORTCUT_API_TOKEN is required");
|
|
1539
1544
|
process.exit(1);
|
|
@@ -1543,14 +1548,14 @@ const server = new McpServer({
|
|
|
1543
1548
|
version
|
|
1544
1549
|
});
|
|
1545
1550
|
const client = new ShortcutClientWrapper(new ShortcutClient(apiToken));
|
|
1546
|
-
UserTools.create(client, server);
|
|
1547
|
-
StoryTools.create(client, server);
|
|
1548
|
-
IterationTools.create(client, server);
|
|
1549
|
-
EpicTools.create(client, server);
|
|
1550
|
-
ObjectiveTools.create(client, server);
|
|
1551
|
-
TeamTools.create(client, server);
|
|
1552
|
-
WorkflowTools.create(client, server);
|
|
1553
|
-
DocumentTools.create(client, server);
|
|
1551
|
+
UserTools.create(client, server, isReadonly);
|
|
1552
|
+
StoryTools.create(client, server, isReadonly);
|
|
1553
|
+
IterationTools.create(client, server, isReadonly);
|
|
1554
|
+
EpicTools.create(client, server, isReadonly);
|
|
1555
|
+
ObjectiveTools.create(client, server, isReadonly);
|
|
1556
|
+
TeamTools.create(client, server, isReadonly);
|
|
1557
|
+
WorkflowTools.create(client, server, isReadonly);
|
|
1558
|
+
DocumentTools.create(client, server, isReadonly);
|
|
1554
1559
|
async function startServer() {
|
|
1555
1560
|
try {
|
|
1556
1561
|
const transport = new StdioServerTransport();
|