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 };
      }
    }

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