update-story
Modify existing Shortcut stories by updating fields like name, description, type, epic, estimate, iteration, owners, workflow state, and labels using the story's public ID.
Instructions
Update an existing Shortcut story. Only provide fields you want to update. The story public ID will always be included in updates.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| storyPublicId | Yes | The public ID of the story to update | |
| name | No | The name of the story | |
| description | No | The description of the story | |
| type | No | The type of the story | |
| epic | No | The epic id of the epic the story belongs to, or null to unset | |
| estimate | No | The point estimate of the story, or null to unset | |
| iteration | No | The iteration id of the iteration the story belongs to, or null to unset | |
| owner_ids | No | Array of user UUIDs to assign as owners of the story | |
| workflow_state_id | No | The workflow state ID to move the story to | |
| labels | No | Labels to assign to the story |
Input Schema (JSON Schema)
{
"properties": {
"description": {
"description": "The description of the story",
"maxLength": 10000,
"type": "string"
},
"epic": {
"description": "The epic id of the epic the story belongs to, or null to unset",
"type": [
"number",
"null"
]
},
"estimate": {
"description": "The point estimate of the story, or null to unset",
"type": [
"number",
"null"
]
},
"iteration": {
"description": "The iteration id of the iteration the story belongs to, or null to unset",
"type": [
"number",
"null"
]
},
"labels": {
"description": "Labels to assign to the story",
"items": {
"additionalProperties": false,
"properties": {
"color": {
"description": "The color of the label",
"type": "string"
},
"description": {
"description": "The description of the label",
"type": "string"
},
"name": {
"description": "The name of the label",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array"
},
"name": {
"description": "The name of the story",
"maxLength": 512,
"type": "string"
},
"owner_ids": {
"description": "Array of user UUIDs to assign as owners of the story",
"items": {
"type": "string"
},
"type": "array"
},
"storyPublicId": {
"description": "The public ID of the story to update",
"exclusiveMinimum": 0,
"type": "number"
},
"type": {
"description": "The type of the story",
"enum": [
"feature",
"bug",
"chore"
],
"type": "string"
},
"workflow_state_id": {
"description": "The workflow state ID to move the story to",
"type": "number"
}
},
"required": [
"storyPublicId"
],
"type": "object"
}
Implementation Reference
- src/tools/stories.ts:473-517 (handler)Handler function that performs the actual update of a Shortcut story by mapping parameters and calling the client.updateStory method.async updateStory({ storyPublicId, ...updates }: { storyPublicId: number; name?: string; description?: string; type?: "feature" | "bug" | "chore"; epic?: number | null; estimate?: number | null; iteration?: number | null; owner_ids?: string[]; workflow_state_id?: number; labels?: Array<{ name: string; color?: string; description?: string; }>; }) { if (!storyPublicId) throw new Error("Story public ID is required"); // Verify the story exists const story = await this.client.getStory(storyPublicId); if (!story) throw new Error(`Failed to retrieve Shortcut story with public ID: ${storyPublicId}`); // Convert API parameters const updateParams: Record<string, unknown> = {}; if (updates.name !== undefined) updateParams.name = updates.name; if (updates.description !== undefined) updateParams.description = updates.description; if (updates.type !== undefined) updateParams.story_type = updates.type; if (updates.epic !== undefined) updateParams.epic_id = updates.epic; if (updates.estimate !== undefined) updateParams.estimate = updates.estimate; if (updates.iteration !== undefined) updateParams.iteration_id = updates.iteration; if (updates.owner_ids !== undefined) updateParams.owner_ids = updates.owner_ids; if (updates.workflow_state_id !== undefined) updateParams.workflow_state_id = updates.workflow_state_id; if (updates.labels !== undefined) updateParams.labels = updates.labels; // Update the story const updatedStory = await this.client.updateStory(storyPublicId, updateParams); return this.toResult(`Updated story sc-${storyPublicId}. Story URL: ${updatedStory.app_url}`); }
- src/tools/stories.ts:163-201 (schema)Zod schema defining the input parameters for the 'update-story' tool.{ storyPublicId: z.number().positive().describe("The public ID of the story to update"), name: z.string().max(512).optional().describe("The name of the story"), description: z.string().max(10_000).optional().describe("The description of the story"), type: z.enum(["feature", "bug", "chore"]).optional().describe("The type of the story"), epic: z .number() .nullable() .optional() .describe("The epic id of the epic the story belongs to, or null to unset"), estimate: z .number() .nullable() .optional() .describe("The point estimate of the story, or null to unset"), iteration: z .number() .nullable() .optional() .describe("The iteration id of the iteration the story belongs to, or null to unset"), owner_ids: z .array(z.string()) .optional() .describe("Array of user UUIDs to assign as owners of the story"), workflow_state_id: z .number() .optional() .describe("The workflow state ID to move the story to"), labels: z .array( z.object({ name: z.string().describe("The name of the label"), color: z.string().optional().describe("The color of the label"), description: z.string().optional().describe("The description of the label"), }), ) .optional() .describe("Labels to assign to the story"), },
- src/tools/stories.ts:160-203 (registration)Registers the 'update-story' tool with the MCP server, specifying name, description, input schema, and handler.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.", { storyPublicId: z.number().positive().describe("The public ID of the story to update"), name: z.string().max(512).optional().describe("The name of the story"), description: z.string().max(10_000).optional().describe("The description of the story"), type: z.enum(["feature", "bug", "chore"]).optional().describe("The type of the story"), epic: z .number() .nullable() .optional() .describe("The epic id of the epic the story belongs to, or null to unset"), estimate: z .number() .nullable() .optional() .describe("The point estimate of the story, or null to unset"), iteration: z .number() .nullable() .optional() .describe("The iteration id of the iteration the story belongs to, or null to unset"), owner_ids: z .array(z.string()) .optional() .describe("Array of user UUIDs to assign as owners of the story"), workflow_state_id: z .number() .optional() .describe("The workflow state ID to move the story to"), labels: z .array( z.object({ name: z.string().describe("The name of the label"), color: z.string().optional().describe("The color of the label"), description: z.string().optional().describe("The description of the label"), }), ) .optional() .describe("Labels to assign to the story"), }, async (params) => await tools.updateStory(params), );