Skip to main content
Glama
Dsazz

JIRA MCP Server

jira_create_issue

Create new JIRA issues with project details, summaries, issue types, priorities, assignees, and custom fields to track tasks and bugs in development workflows.

Instructions

Creates a new JIRA issue with specified parameters

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectKeyYes
summaryYes
issueTypeYes
descriptionNo
priorityNo
assigneeNo
labelsNo
componentsNo
fixVersionsNo
parentIssueKeyNo
timeEstimateNo
environmentNo
storyPointsNo
customFieldsNo

Implementation Reference

  • The CreateIssueHandler class provides the MCP tool handler logic for 'jira_create_issue'. It validates input parameters using Zod, delegates business logic to CreateIssueUseCase, formats responses, and provides enhanced error messages.
    export class CreateIssueHandler extends BaseToolHandler<
      CreateIssueParams,
      string
    > {
      private readonly formatter: IssueCreationFormatter;
    
      /**
       * Create a new CreateIssueHandler with necessary dependencies
       *
       * @param createIssueUseCase - Use case for creating issues with validation
       * @param projectValidator - Validator for project-related validation
       * @param permissionChecker - Checker for permission-related validation
       */
      constructor(private readonly createIssueUseCase: CreateIssueUseCase) {
        super("JIRA", "Create Issue");
        this.formatter = new IssueCreationFormatter();
      }
    
      /**
       * Execute the handler logic
       * Creates a new JIRA issue with comprehensive validation and formatting
       * Delegates business logic to the use case
       *
       * @param params - Parameters for issue creation
       */
      protected async execute(params: CreateIssueParams): Promise<string> {
        try {
          // Step 1: Validate parameters
          const validatedParams = this.validateParameters(params);
          this.logger.info(
            `Creating JIRA issue in project: ${validatedParams.projectKey}`,
          );
    
          // Step 2: Map parameters to use case request
          const useCaseRequest: CreateIssueUseCaseRequest = {
            projectKey: validatedParams.projectKey,
            summary: validatedParams.summary,
            issueType: validatedParams.issueType,
            description: validatedParams.description,
            customFields: validatedParams.customFields,
          };
    
          // Step 3: Execute the use case
          this.logger.debug("Delegating to CreateIssueUseCase", {
            projectKey: validatedParams.projectKey,
            issueType: validatedParams.issueType,
            summary: validatedParams.summary,
          });
    
          const createdIssue =
            await this.createIssueUseCase.execute(useCaseRequest);
    
          // Step 4: Format and return success response
          this.logger.info(`Successfully created issue: ${createdIssue.key}`);
          return this.formatter.format(createdIssue);
        } catch (error) {
          this.logger.error(`Failed to create JIRA issue: ${error}`);
          throw this.enhanceError(error, params.projectKey, params.issueType);
        }
      }
    
      /**
       * Validate parameters using Zod schema
       */
      private validateParameters(params: CreateIssueParams): CreateIssueParams {
        const result = createIssueParamsSchema.safeParse(params);
    
        if (!result.success) {
          const errorMessage = `Invalid issue creation parameters: ${formatZodError(
            result.error,
          )}`;
          throw new IssueCreateParamsValidationError(errorMessage);
        }
    
        return result.data;
      }
    
      /**
       * Enhance error messages for better user guidance
       */
      private enhanceError(
        error: unknown,
        projectKey?: string,
        issueType?: string,
      ): Error {
        if (error instanceof JiraNotFoundError) {
          return new Error(
            `❌ **Project Not Found**\n\nProject '${projectKey}' not found or you don't have permission to create issues.\n\n**Solutions:**\n- Verify the project key is correct\n- Check your JIRA permissions\n- Use \`jira_get_projects\` to see available projects\n\n**Example:** \`jira_create_issue projectKey=MYPROJ summary="Fix bug" issueType=Bug\``,
          );
        }
    
        if (error instanceof JiraPermissionError) {
          return new Error(
            `❌ **Permission Denied**\n\nYou don't have permission to create issues in project '${projectKey}'.\n\n**Solutions:**\n- Check your JIRA permissions for this project\n- Contact your JIRA administrator\n- Verify you have CREATE_ISSUES permission\n\n**Required Permissions:** Create Issues`,
          );
        }
    
        if (error instanceof IssueCreateParamsValidationError) {
          return new Error(
            `❌ **Validation Error**\n\n${error.message}\n\n**Solutions:**\n- Check the format of all parameters\n- Ensure required fields are provided\n- Verify field values match expected formats\n\n**Example:** \`jira_create_issue projectKey=PROJ summary="My issue" issueType=Task\``,
          );
        }
    
        if (error instanceof JiraApiError) {
          return new Error(
            `❌ **JIRA API Error**\n\n${error.message}\n\n**Solutions:**\n- Check all required fields are provided\n- Verify field values match JIRA requirements\n- Ensure issue type '${issueType}' exists in project '${projectKey}'\n\n**Example:** \`jira_create_issue projectKey=PROJ summary="My issue" issueType=Task\``,
          );
        }
    
        if (error instanceof Error) {
          return new Error(
            `❌ **Creation Failed**\n\n${error.message}\n\n**Solutions:**\n- Check your parameters are valid\n- Verify the project and issue type exist\n- Try with minimal required fields first\n\n**Example:** \`jira_create_issue projectKey=PROJ summary="Test issue" issueType=Task\``,
          );
        }
    
        return new Error(
          "❌ **Unknown Error**\n\nAn unknown error occurred during issue creation.\n\nPlease check your parameters and try again.",
        );
      }
    }
  • Zod schema defining the input parameters and validation rules for the jira_create_issue tool.
    export const createIssueParamsSchema = z.object({
      // Required fields
      projectKey: z
        .string()
        .min(1, "Project key is required")
        .max(50, "Project key too long")
        .regex(
          /^[A-Z0-9_]+$/,
          "Project key must contain only uppercase letters, numbers, and underscores",
        ),
    
      summary: z
        .string()
        .min(1, "Summary is required")
        .max(255, "Summary must be 255 characters or less"),
    
      issueType: z
        .string()
        .min(1, "Issue type is required")
        .max(50, "Issue type name too long"),
    
      // Optional core fields
      description: z
        .string()
        .max(32767, "Description too long (max 32,767 characters)")
        .optional(),
    
      priority: z.enum(["Highest", "High", "Medium", "Low", "Lowest"]).optional(),
    
      assignee: z
        .string()
        .min(1, "Assignee cannot be empty")
        .max(255, "Assignee identifier too long")
        .optional(),
    
      // Array fields with limits
      labels: z
        .array(z.string().min(1).max(255))
        .max(10, "Maximum 10 labels allowed")
        .optional(),
    
      components: z
        .array(z.string().min(1).max(255))
        .max(5, "Maximum 5 components allowed")
        .optional(),
    
      fixVersions: z
        .array(z.string().min(1).max(255))
        .max(3, "Maximum 3 fix versions allowed")
        .optional(),
    
      // Parent issue for subtasks
      parentIssueKey: issueKeySchema.optional(),
    
      // Time tracking
      timeEstimate: z
        .string()
        .regex(
          /^\d+[wdhm]$/,
          "Time estimate must be in format like '2w', '3d', '4h', '30m'",
        )
        .optional(),
    
      // Environment field
      environment: z
        .string()
        .max(32767, "Environment description too long")
        .optional(),
    
      // Story points for agile
      storyPoints: z
        .number()
        .int()
        .min(0)
        .max(100, "Story points must be between 0 and 100")
        .optional(),
    
      // Custom fields (flexible object)
      customFields: z.record(z.string(), z.unknown()).optional(),
    });
  • Tool configuration registration for jira_create_issue, specifying name, description, input schema, and handler binding within the issue tools config factory.
    {
      name: "jira_create_issue",
      description: "Creates a new JIRA issue with specified parameters",
      params: createIssueParamsSchema.shape,
      handler: tools.jira_create_issue.handle.bind(tools.jira_create_issue),
    },
  • Factory function creating the jira_create_issue ToolHandler object by instantiating CreateIssueHandler and wrapping its handle method.
    jira_create_issue: {
      handle: async (args: unknown) => createIssueHandler.handle(args),
    },
  • CreateIssueUseCaseImpl provides the business logic helper for issue creation, including validations and repository interaction, used by the handler.
    export class CreateIssueUseCaseImpl implements CreateIssueUseCase {
      private readonly logger = logger;
    
      constructor(
        private readonly issueRepository: IssueRepository,
        private readonly projectValidator: ProjectValidator,
        private readonly permissionChecker: ProjectPermissionRepository,
      ) {}
    
      /**
       * Execute issue creation with comprehensive validation
       */
      async execute(request: CreateIssueUseCaseRequest): Promise<Issue> {
        this.logger.debug("Starting issue creation process", {
          prefix: "JIRA:CreateIssueUseCase",
          projectKey: request.projectKey,
          summary: request.summary,
        });
    
        // Step 1: Validate project exists
        await this.validateProject(request.projectKey);
    
        // Step 2: Check user permissions
        await this.validatePermissions(request.projectKey);
    
        // Step 3: Validate issue type if provided
        if (request.issueType) {
          await this.validateIssueType(request.projectKey, request.issueType);
        }
    
        // Step 4: Create the issue
        const issueData = this.buildCreateIssueRequest(request);
        const createdIssue = await this.issueRepository.createIssue(issueData);
    
        this.logger.debug("Issue creation completed successfully", {
          prefix: "JIRA:CreateIssueUseCase",
          issueKey: createdIssue.key,
          projectKey: request.projectKey,
        });
    
        return createdIssue;
      }
    
      /**
       * Validate that the project exists and is accessible
       */
      private async validateProject(projectKey: string): Promise<void> {
        this.logger.debug("Validating project existence", {
          prefix: "JIRA:CreateIssueUseCase",
          projectKey,
        });
    
        try {
          await this.projectValidator.validateProject(projectKey);
        } catch (error) {
          this.logger.error("Project validation failed", {
            prefix: "JIRA:CreateIssueUseCase",
            projectKey,
            error,
          });
          throw error;
        }
      }
    
      /**
       * Validate that the user has permission to create issues
       */
      private async validatePermissions(projectKey: string): Promise<void> {
        this.logger.debug("Validating create issue permissions", {
          prefix: "JIRA:CreateIssueUseCase",
          projectKey,
        });
    
        const hasPermission =
          await this.permissionChecker.hasCreateIssuePermission(projectKey);
    
        if (!hasPermission) {
          const error = new Error(
            `User does not have CREATE_ISSUES permission for project '${projectKey}'`,
          );
          this.logger.error("Permission validation failed", {
            prefix: "JIRA:CreateIssueUseCase",
            projectKey,
            error: error.message,
          });
          throw error;
        }
      }
    
      /**
       * Validate that the issue type exists in the project
       */
      private async validateIssueType(
        projectKey: string,
        issueType: string,
      ): Promise<void> {
        this.logger.debug("Validating issue type", {
          prefix: "JIRA:CreateIssueUseCase",
          projectKey,
          issueType,
        });
    
        try {
          await this.projectValidator.validateIssueType(projectKey, issueType);
        } catch (error) {
          this.logger.error("Issue type validation failed", {
            prefix: "JIRA:CreateIssueUseCase",
            projectKey,
            issueType,
            error,
          });
          throw error;
        }
      }
    
      /**
       * Build the create issue request from the use case request
       */
      private buildCreateIssueRequest(
        request: CreateIssueUseCaseRequest,
      ): CreateIssueRequest {
        const fields: CreateIssueRequest["fields"] = {
          project: {
            key: request.projectKey,
          },
          summary: request.summary,
          issuetype: {
            name: request.issueType || "Task",
          },
        };
    
        // Convert description to ADF format if provided
        if (request.description) {
          const adfDescription = ensureADFFormat(request.description);
          if (adfDescription) {
            fields.description = adfDescription;
          }
        }
    
        // Add custom fields if provided
        if (request.customFields) {
          Object.assign(fields, request.customFields);
        }
    
        return { fields };
      }
    }
Behavior1/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It states 'creates' which implies a write operation, but provides no information about authentication requirements, rate limits, side effects, error conditions, or what happens upon successful creation. This is inadequate for a mutation tool with 14 parameters.

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 extremely concise at just 7 words. It's front-loaded with the core action and contains no unnecessary words. While it may be too brief for adequate functionality description, it earns full marks for conciseness.

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

Completeness1/5

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

Given the complexity (14 parameters, no annotations, no output schema, 0% schema description coverage), the description is completely inadequate. It doesn't explain what the tool returns, how to handle errors, what permissions are needed, or provide any context about the parameters. For a creation tool in a complex system like JIRA, this leaves the agent with insufficient information.

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

Parameters1/5

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

The schema has 0% description coverage, meaning none of the 14 parameters have documentation in the schema. The description adds no semantic information about any parameters beyond the generic 'specified parameters' phrase. For a complex tool with many parameters including arrays, objects, and specific patterns, this is a critical gap.

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

Purpose4/5

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

The description clearly states the verb ('creates') and resource ('new JIRA issue'), making the purpose immediately understandable. It distinguishes from siblings like 'jira_update_issue' by specifying creation rather than modification. However, it doesn't explicitly differentiate from other potential creation tools that might exist in a broader context.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, when to choose this over other issue management tools, or any contextual constraints. The agent must infer usage from the tool name alone.

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/Dsazz/mcp-jira'

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