update_issue
Update any field of an existing Jira issue, including summary, description, priority, assignee, labels, or convert it to a subtask. Only specified fields are modified.
Instructions
Update fields of an existing Jira issue or convert to subtask. Only provided fields will be updated. Use get_issue first to see current values. Returns success confirmation.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| issueKey | Yes | Issue key (e.g., "PROJ-123") to update. This is the unique identifier for the issue. | |
| summary | No | New issue title/summary (max 255 characters). Replaces the existing summary. | |
| description | No | New issue description. Replaces the existing description. Supports plain text, Markdown, or ADF. Markdown will be automatically converted to ADF. For mentions, use format: @[accountId:displayName] (get accountId from get_users tool). | |
| priority | No | New priority: "Highest", "High", "Medium", "Low", "Lowest". Replaces current priority. | |
| assignee | No | Account ID of new assignee. Use get_users to find account IDs. Set to null to unassign. | |
| parent | No | Issue key of the parent issue (e.g., "PROJ-123"). Use to convert issue to subtask or change parent. | |
| labels | No | Complete array of labels (replaces all existing labels). Use empty array to remove all labels. | |
| components | No | Complete array of components (replaces all existing components). Use empty array to remove all components. | |
| fixVersions | No | Complete array of fix versions (replaces all existing versions). Use empty array to remove all versions. | |
| customFields | No | Custom field values as key-value pairs. Only specified fields will be updated. |
Implementation Reference
- src/index.ts:39-61 (registration)The MCP server registers the update_issue tool via createIssueTools() and routes handleIssueTool() when name starts with 'update_issue' (see line 74).
private setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { const projectTools = createProjectTools(this.jiraClient); const issueTools = createIssueTools(this.jiraClient); const commentTools = createCommentTools(this.jiraClient); const transitionTools = createTransitionTools(this.jiraClient); const assignmentTools = createAssignmentTools(this.jiraClient); const sprintTools = createSprintTools(this.jiraClient); const wikiTools = createWikiTools(); return { tools: [ ...projectTools, ...issueTools, ...commentTools, ...transitionTools, ...assignmentTools, ...sprintTools, ...wikiTools, ], }; }); - src/index.ts:71-77 (registration)Routes 'update_issue' calls to handleIssueTool dispatch function.
} else if ( name.startsWith('create_issue') || name.startsWith('get_issue') || name.startsWith('update_issue') || name.startsWith('delete_issue') ) { return await handleIssueTool(name, args || {}, this.jiraClient); - src/tools/issues.ts:275-287 (handler)The handler case for 'update_issue': validates args via updateIssueSchema, calls jiraClient.updateIssue(), and returns success message.
case 'update_issue': { const validatedArgs = await updateIssueSchema.validate(args); const _result = await jiraClient.updateIssue(validatedArgs); return { content: [ { type: 'text', text: `Issue ${validatedArgs.issueKey} updated successfully`, }, ], }; } - src/schemas/index.ts:32-51 (schema)Validation schema for update_issue input: issueKey (required), summary, description (with markdown-to-ADF transform), priority, assignee, parent, labels, components, fixVersions, customFields (all optional).
export const updateIssueSchema = yup.object({ issueKey: yup.string().required('Issue key is required'), summary: yup.string().optional().max(255, 'Summary too long'), description: yup.mixed() .optional() .transform(function (value) { // If it's a string and looks like markdown, convert to ADF if (typeof value === 'string' && isMarkdown(value)) { return markdownToADF(value); } return value; }), priority: yup.string().optional(), assignee: yup.string().optional(), parent: yup.string().optional(), labels: yup.array().of(yup.string()).optional(), components: yup.array().of(yup.string()).optional(), fixVersions: yup.array().of(yup.string()).optional(), customFields: yup.object().optional(), }); - src/jira-client.ts:170-221 (helper)JiraClient.updateIssue() builds a fields object from validated input and calls jira.issues.editIssue() to perform the API update.
// Update an issue async updateIssue(input: UpdateIssueInput) { try { const updateData: { fields: Record<string, unknown> } = { fields: {}, }; if (input.summary) { updateData.fields.summary = input.summary; } if (input.description) { updateData.fields.description = input.description; } if (input.priority) { updateData.fields.priority = { name: input.priority }; } if (input.assignee) { updateData.fields.assignee = { accountId: input.assignee }; } if (input.parent) { updateData.fields.parent = { key: input.parent }; } if (input.labels) { updateData.fields.labels = input.labels; } if (input.components) { updateData.fields.components = input.components.map(name => ({ name })); } if (input.fixVersions) { updateData.fields.fixVersions = input.fixVersions.map(name => ({ name })); } if (input.customFields) { Object.assign(updateData.fields, input.customFields); } const response = await this.jira.issues.editIssue({ issueIdOrKey: input.issueKey, fields: updateData.fields, }); return response; } catch (error) { throw new Error(`Failed to update issue: ${error instanceof Error ? error.message : 'Unknown error'}`); } }