create_issue
Create a new Jira issue or subtask in a project, specifying type, summary, and optional details. Returns the issue key, ID, and URL.
Instructions
Create a new Jira issue (Bug, Story, Task, Epic, etc.) or subtask. Returns the created issue key, ID, and URL. Use get_issue_types to find valid issueType values for the project. To create a subtask, specify the parent issue key.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectKey | Yes | Project key (e.g., "PROJ") where the issue will be created. Use get_projects to find available keys. | |
| summary | Yes | Issue title/summary (max 255 characters). This is the main identifier shown in issue lists. | |
| description | No | Detailed issue description. Supports plain text, Markdown, or Atlassian Document Format (ADF) for rich formatting. Markdown will be automatically converted to ADF. For mentions, use format: @[accountId:displayName] (get accountId from get_users tool). | |
| issueType | Yes | Issue type name (e.g., "Bug", "Story", "Task", "Epic"). Use get_issue_types to find valid values. | |
| priority | No | Priority level: "Highest", "High", "Medium", "Low", "Lowest". Defaults to project default if not specified. | |
| assignee | No | Account ID of the user to assign the issue to. Use get_users to find account IDs. | |
| parent | No | Issue key of the parent issue (e.g., "PROJ-123"). Required to create a subtask. | |
| labels | No | Array of label names for categorization and filtering (e.g., ["bug", "urgent", "frontend"]). | |
| components | No | Array of component names that this issue affects (e.g., ["API", "Database", "UI"]). | |
| fixVersions | No | Array of version names where this issue will be fixed (e.g., ["v1.2", "v2.0"]). | |
| customFields | No | Custom field values as key-value pairs. Field keys are project-specific. |
Implementation Reference
- src/tools/issues.ts:69-165 (registration)The 'create_issue' tool is registered as part of the issue tools array in createIssueTools(). Its name is 'create_issue' with a description and inputSchema defining the required/optional parameters (projectKey, summary, issueType required; description, priority, assignee, parent, labels, components, fixVersions, customFields optional).
}, { name: 'get_issue', description: 'Retrieve detailed information about a specific Jira issue including status, assignee, description, comments, and workflow data. Use this to get current state before making updates.', inputSchema: { type: 'object', properties: { issueKey: { type: 'string', description: 'Issue key (e.g., "PROJ-123") or numeric issue ID. This is the unique identifier for the issue.', }, expand: { type: 'string', description: 'Comma-separated list of additional data: renderedFields,names,schema,transitions,operations,editmeta,changelog', }, fields: { type: 'array', items: { type: 'string' }, description: 'Specific fields to return (e.g., ["summary", "status", "assignee"]). If not specified, returns all fields.', }, }, required: ['issueKey'], }, }, { name: 'update_issue', description: '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.', inputSchema: { type: 'object', properties: { issueKey: { type: 'string', description: 'Issue key (e.g., "PROJ-123") to update. This is the unique identifier for the issue.', }, summary: { type: 'string', description: 'New issue title/summary (max 255 characters). Replaces the existing summary.', }, description: { type: 'string', description: '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: { type: 'string', description: 'New priority: "Highest", "High", "Medium", "Low", "Lowest". Replaces current priority.', }, assignee: { type: 'string', description: 'Account ID of new assignee. Use get_users to find account IDs. Set to null to unassign.', }, parent: { type: 'string', description: 'Issue key of the parent issue (e.g., "PROJ-123"). Use to convert issue to subtask or change parent.', }, labels: { type: 'array', items: { type: 'string' }, description: 'Complete array of labels (replaces all existing labels). Use empty array to remove all labels.', }, components: { type: 'array', items: { type: 'string' }, description: 'Complete array of components (replaces all existing components). Use empty array to remove all components.', }, fixVersions: { type: 'array', items: { type: 'string' }, description: 'Complete array of fix versions (replaces all existing versions). Use empty array to remove all versions.', }, customFields: { type: 'object', description: 'Custom field values as key-value pairs. Only specified fields will be updated.', }, }, required: ['issueKey'], }, }, { name: 'delete_issue', description: 'Permanently delete a Jira issue. This action cannot be undone. Use with caution. Returns success confirmation.', inputSchema: { type: 'object', properties: { issueKey: { type: 'string', description: 'Issue key (e.g., "PROJ-123") to delete. This is the unique identifier for the issue.', }, deleteSubtasks: { type: 'boolean', description: 'Whether to also delete all subtasks of this issue. Defaults to false (subtasks will remain).', default: false, }, }, required: ['issueKey'], }, }, ]; - src/tools/issues.ts:175-187 (handler)The handler for 'create_issue' in handleIssueTool(). Validates args using createIssueSchema, calls jiraClient.createIssue(validatedArgs), and returns a success message with the created issue key.
case 'create_issue': { const validatedArgs = await createIssueSchema.validate(args); const issue = await jiraClient.createIssue(validatedArgs); return { content: [ { type: 'text', text: `Issue ${issue.key} created successfully`, }, ], }; } - src/schemas/index.ts:9-29 (schema)The yup validation schema for 'create_issue'. Defines validation rules: projectKey (string, required), summary (string, required, max 255), description (mixed, optional, transforms markdown to ADF), issueType (string, required), priority (string, optional), assignee (string, optional), parent (string, optional), labels (string[], optional), components (string[], optional), fixVersions (string[], optional), customFields (object, optional).
export const createIssueSchema = yup.object({ projectKey: yup.string().required('Project key is required'), summary: yup.string().required('Summary is required').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; }), issueType: yup.string().required('Issue type is required'), 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:107-154 (helper)The JiraClient.createIssue() method that executes the actual Jira API call. Builds issueData with fields from input, conditionally adds optional fields (description, priority, assignee, parent, labels, components, fixVersions, customFields), then calls this.jira.issues.createIssue(issueData).
async createIssue(input: CreateIssueInput) { try { const issueData: CreateIssue = { fields: { project: { key: input.projectKey }, summary: input.summary, issuetype: { name: input.issueType }, }, }; if (input.description) { issueData.fields.description = input.description as Document; } if (input.priority) { issueData.fields.priority = { name: input.priority }; } if (input.assignee) { issueData.fields.assignee = { accountId: input.assignee }; } if (input.parent) { issueData.fields.parent = { key: input.parent }; } if (input.labels && input.labels.length > 0) { issueData.fields.labels = input.labels.filter(label => label !== undefined) as string[]; } if (input.components && input.components.length > 0) { issueData.fields.components = input.components.map(name => ({ name })); } if (input.fixVersions && input.fixVersions.length > 0) { issueData.fields.fixVersions = input.fixVersions.map(name => ({ name })); } if (input.customFields) { Object.assign(issueData.fields, input.customFields); } const response = await this.jira.issues.createIssue(issueData); return response; } catch (error) { throw new Error(`Failed to create issue: ${error instanceof Error ? error.message : 'Unknown error'}`); } } - src/index.ts:72-77 (registration)In the main server's CallToolRequestSchema handler, the 'create_issue' name (via name.startsWith('create_issue')) is routed to handleIssueTool().
name.startsWith('create_issue') || name.startsWith('get_issue') || name.startsWith('update_issue') || name.startsWith('delete_issue') ) { return await handleIssueTool(name, args || {}, this.jiraClient);