Skip to main content
Glama

jira_create_issue

Create a new Jira issue in a specified project with configurable fields including type, priority, assignee, labels, components, and custom fields. Supports multiple description formats.

Instructions

Creates a new Jira issue in the specified project. Supports setting issue type, priority, assignee, labels, components, and custom fields. Description format is controlled by the "format" parameter (default: markdown). For required custom fields, supply them via customFields (e.g., { "customfield_12345": { id: "..." } }). Returns the created issue with all details.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectKeyYesProject key where the issue will be created
summaryYesIssue summary/title
descriptionNoIssue description. Accepts plain text or ADF object.
issueTypeYesIssue type (e.g., Bug, Story, Task)
priorityNoIssue priority
assigneeNoAssignee account ID
labelsNoIssue labels
componentsNoComponent names
customFieldsNoAdditional Jira field mappings, e.g. { "customfield_12345": value }. Use for required custom fields.
returnIssueNoWhen false, skip fetching full issue after creation
formatNoDescription format: "markdown" (converts Markdown to ADF), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting). Default: "markdown"markdown

Implementation Reference

  • Core API function that sends POST /issue to Jira to create an issue with fields (project, summary, issuetype, description, priority, assignee, labels, components, customFields). Returns issue key string or full JiraIssue.
    export async function createIssue(
      issueData: {
        projectKey: string;
        summary: string;
        description?: string;
        issueType: string;
        priority?: string;
        assignee?: string;
        labels?: string[];
        components?: string[];
        customFields?: Record<string, any>;
        format?: 'markdown' | 'adf' | 'plain';
      },
      options: { returnIssue?: boolean } = { returnIssue: true }
    ): Promise<JiraIssue | string> {
      const fields: Record<string, any> = {
        project: { key: issueData.projectKey },
        summary: issueData.summary,
        issuetype: { name: issueData.issueType },
      };
    
      if (issueData.description !== undefined) {
        fields.description = ensureAdfDescription(
          issueData.description,
          issueData.format || 'markdown'
        );
      }
    
      if (issueData.priority) {
        fields.priority = { name: issueData.priority };
      }
    
      if (issueData.assignee) {
        fields.assignee = { accountId: issueData.assignee };
      }
    
      if (issueData.labels && issueData.labels.length > 0) {
        fields.labels = issueData.labels;
      }
    
      if (issueData.components && issueData.components.length > 0) {
        fields.components = issueData.components.map((name) => ({ name }));
      }
    
      // Merge any custom fields provided by the caller
      if (issueData.customFields && typeof issueData.customFields === 'object') {
        for (const [key, value] of Object.entries(issueData.customFields)) {
          // Do not overwrite standard fields if accidentally duplicated
          if (!(key in fields)) {
            fields[key] = value;
          }
        }
      }
    
      const config: AxiosRequestConfig = {
        method: 'POST',
        url: '/issue',
        data: { fields },
      };
    
      const response = await makeJiraRequest<{ key: string; id: string; self: string }>(config);
    
      if (options.returnIssue === false) {
        return response.key;
      }
    
      // Return the created issue
      return await getIssue(response.key);
    }
  • Tool handler function that validates input via Zod schema, builds createParams, calls createIssue() API helper, and returns formatted success/error response.
    export async function handleCreateIssue(input: unknown): Promise<McpToolResponse> {
      try {
        const validated = validateInput(CreateIssueInputSchema, input);
    
        log.info(`Creating issue in project ${validated.projectKey}...`);
    
        const createParams: any = {
          projectKey: validated.projectKey,
          summary: validated.summary,
          issueType: validated.issueType,
        };
    
        if (validated.description !== undefined) createParams.description = validated.description;
        if (validated.priority !== undefined) createParams.priority = validated.priority;
        if (validated.assignee !== undefined) createParams.assignee = validated.assignee;
        if (validated.labels !== undefined) createParams.labels = validated.labels;
        if (validated.components !== undefined) createParams.components = validated.components;
        if (validated.customFields !== undefined) createParams.customFields = validated.customFields;
        if (validated.format !== undefined) createParams.format = validated.format;
    
        let issueOrKey;
        if (validated.returnIssue === false) {
          issueOrKey = await createIssue(createParams, { returnIssue: false });
        } else {
          // Default behavior: request full issue; keep API surface compatible with tests
          issueOrKey = await createIssue(createParams);
        }
    
        if (validated.returnIssue === false) {
          const key = typeof issueOrKey === 'string' ? issueOrKey : (issueOrKey as any).key;
          log.info(`Created issue ${key}`);
          return formatSuccessResponse(`Issue created: ${key}`);
        }
    
        const issue = issueOrKey as any;
        log.info(`Created issue ${issue.key}`);
        return formatIssueResponse(issue);
      } catch (error) {
        log.error('Error in handleCreateIssue:', error);
        return handleError(error);
      }
    }
  • Tool definition/registration with name TOOL_NAMES.CREATE_ISSUE ('jira_create_issue'), description, and JSON Schema input schema for MCP tool registration.
    export const createIssueTool: Tool = {
      name: TOOL_NAMES.CREATE_ISSUE,
      description:
        'Creates a new Jira issue in the specified project. Supports setting issue type, priority, assignee, labels, components, and custom fields. Description format is controlled by the "format" parameter (default: markdown). For required custom fields, supply them via customFields (e.g., { "customfield_12345": { id: "..." } }). Returns the created issue with all details.',
      inputSchema: {
        type: 'object',
        properties: {
          projectKey: {
            type: 'string',
            description: 'Project key where the issue will be created',
          },
          summary: {
            type: 'string',
            description: 'Issue summary/title',
            minLength: 1,
          },
          description: {
            anyOf: [{ type: 'string' }, { type: 'object' }],
            description:
              'Detailed issue description (optional). Format depends on the "format" parameter.',
          },
          issueType: {
            type: 'string',
            description: 'Issue type name (e.g., Bug, Story, Task, Epic)',
          },
          priority: {
            type: 'string',
            description: 'Issue priority name (e.g., High, Medium, Low) - optional',
          },
          assignee: {
            type: 'string',
            description: 'Assignee account ID (optional)',
          },
          labels: {
            type: 'array',
            items: { type: 'string' },
            description: 'Issue labels (optional)',
            default: [],
          },
          components: {
            type: 'array',
            items: { type: 'string' },
            description: 'Component names (optional)',
            default: [],
          },
          customFields: {
            type: 'object',
            additionalProperties: true,
            description:
              'Additional Jira fields, e.g. { "customfield_10071": value }. Use this to set required custom fields.',
          },
          returnIssue: {
            type: 'boolean',
            description: 'If false, returns only the issue key without fetching full details',
            default: true,
          },
          format: {
            type: 'string',
            enum: ['markdown', 'adf', 'plain'],
            description:
              'Description format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
            default: 'markdown',
          },
        },
        required: ['projectKey', 'summary', 'issueType'],
      },
    };
  • src/index.ts:166-172 (registration)
    MCP server registration of the jira_create_issue tool, linking name, description, Zod schema, and handler function.
    {
      name: TOOL_NAMES.CREATE_ISSUE,
      description: tools.createIssueTool.description!,
      inputSchema: CreateIssueInputSchema,
      handler: tools.handleCreateIssue,
      annotations: { readOnlyHint: false },
    },
  • Zod schema for validating create-issue input: projectKey, summary, description, issueType, priority, assignee, labels, components, customFields, returnIssue, format.
    export const CreateIssueInputSchema = z.object({
      projectKey: z
        .string()
        .describe('Project key where the issue will be created')
        .refine((v) => isValidProjectKey(v), 'Invalid project key format'),
      summary: z.string().min(1).describe('Issue summary/title'),
      description: z
        .union([z.string(), z.any()])
        .optional()
        .describe('Issue description. Accepts plain text or ADF object.'),
      issueType: z.string().describe('Issue type (e.g., Bug, Story, Task)'),
      priority: z.string().optional().describe('Issue priority'),
      assignee: z.string().optional().describe('Assignee account ID'),
      labels: z.array(z.string()).optional().describe('Issue labels'),
      components: z.array(z.string()).optional().describe('Component names'),
      customFields: z
        .record(z.any())
        .optional()
        .describe(
          'Additional Jira field mappings, e.g. { "customfield_12345": value }. Use for required custom fields.'
        ),
      returnIssue: z
        .boolean()
        .optional()
        .describe('When false, skip fetching full issue after creation'),
      format: z
        .enum(['markdown', 'adf', 'plain'])
        .optional()
        .default('markdown')
        .describe(
          'Description format: "markdown" (converts Markdown to ADF), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting). Default: "markdown"'
        ),
    });
    
    export type CreateIssueInput = z.infer<typeof CreateIssueInputSchema>;
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only set readOnlyHint=false, so the description carries the burden. It adds valuable behavior details: it returns the created issue, controls description format via the 'format' parameter, and handles custom fields. However, it does not disclose permissions, rate limits, or side effects beyond creation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise at 4 sentences, front-loaded with the main purpose. Every sentence adds unique information (purpose, supported fields, format control, custom fields). No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (11 parameters, 3 required, nested objects), the description covers all essential aspects: creation, field types, format handling, custom fields, and return behavior. No gaps remain despite the absence of an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, baseline 3. The description adds meaningful examples: 'format' default is markdown, customFields can use syntax like {'customfield_12345': {id:'...'}}, and returnIssue behavior. These details clarify usage beyond the schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states 'Creates a new Jira issue in the specified project,' clearly identifying the verb (create) and resource (Jira issue). It distinguishes from sibling tools like jira_update_issue and jira_search_issues by focusing on creation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not provide explicit guidance on when to use this tool versus alternatives. It only describes what it does, leaving the agent to infer usage context. There is no mention of when not to use or which sibling tool applies for similar tasks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freema/mcp-jira-stdio'

If you have feedback or need assistance with the MCP directory API, please join our Discord server