Skip to main content
Glama

create_jira_issue

Create a new Jira issue with specified project, summary, description, and issue type. Automatically handles common issue types like 'Bug', 'Task', 'Story', and 'Epic'. Supports additional fields for customization.

Instructions

Create a new Jira issue. Common issue types include 'Bug', 'Task', 'Story', 'Epic' (capitalization handled automatically)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
descriptionYesIssue description
fieldsNoAdditional fields for the issue (optional)
issue_typeYesIssue type (e.g., 'Bug', 'Task', 'Story', 'Epic', 'New Feature', 'Improvement'). IMPORTANT: Types are case-sensitive and vary by Jira instance.
projectYesProject key (e.g., 'MYPROJ')
summaryYesIssue summary/title

Implementation Reference

  • Main handler function that processes input parameters, formats the issue payload, handles issue type normalization, calls the v3 API to create the issue, and returns a JiraIssueResult.
    async def create_jira_issue(
        self,
        project: str,
        summary: str,
        description: str,
        issue_type: str,
        fields: Optional[Dict[str, Any]] = None,
    ) -> JiraIssueResult:
        """Create a new Jira issue using v3 REST API
    
        Args:
            project: Project key (e.g., 'PROJ')
            summary: Issue summary/title
            description: Issue description
            issue_type: Issue type - common values include 'Bug', 'Task', 'Story', 'Epic', 'New Feature', 'Improvement'
                       Note: Available issue types vary by Jira instance and project
            fields: Optional additional fields dictionary
    
        Returns:
            JiraIssueResult object with the created issue details
    
        Example:
            # Create a bug
            await create_jira_issue(
                project='PROJ',
                summary='Login button not working',
                description='The login button on the homepage is not responding to clicks',
                issue_type='Bug'
            )
    
            # Create a task with custom fields
            await create_jira_issue(
                project='PROJ',
                summary='Update documentation',
                description='Update API documentation with new endpoints',
                issue_type='Task',
                fields={
                    'assignee': 'jsmith',
                    'labels': ['documentation', 'api'],
                    'priority': {'name': 'High'}
                }
            )
        """
        logger.info("Starting create_jira_issue...")
    
        try:
            # Create a properly formatted issue dictionary
            issue_dict = {}
    
            # Process required fields first
            # Project field - required
            if isinstance(project, str):
                issue_dict["project"] = {"key": project}
            else:
                issue_dict["project"] = project
    
            # Summary - required
            issue_dict["summary"] = summary
    
            # Description
            if description:
                issue_dict["description"] = description
    
            # Issue type - required, with validation for common issue types
            logger.info(
                f"Processing issue_type: '{issue_type}' (type: {type(issue_type)})"
            )
            common_types = [
                "bug",
                "task",
                "story",
                "epic",
                "improvement",
                "newfeature",
                "new feature",
            ]
    
            if isinstance(issue_type, str):
                # Check for common issue type variants and fix case-sensitivity issues
                issue_type_lower = issue_type.lower()
    
                if issue_type_lower in common_types:
                    # Convert first letter to uppercase for standard Jira types
                    issue_type_proper = issue_type_lower.capitalize()
                    if (
                        issue_type_lower == "new feature"
                        or issue_type_lower == "newfeature"
                    ):
                        issue_type_proper = "New Feature"
    
                    logger.info(
                        f"Note: Converting issue type from '{issue_type}' to '{issue_type_proper}'"
                    )
                    issue_dict["issuetype"] = {"name": issue_type_proper}
                else:
                    # Use the type as provided - some Jira instances have custom types
                    issue_dict["issuetype"] = {"name": issue_type}
            else:
                issue_dict["issuetype"] = issue_type
    
            # Add any additional fields with proper type handling
            if fields:
                for key, value in fields.items():
                    # Skip fields we've already processed
                    if key in [
                        "project",
                        "summary",
                        "description",
                        "issuetype",
                        "issue_type",
                    ]:
                        continue
    
                    # Handle special fields that require specific formats
                    if key == "assignees" or key == "assignee":
                        # Convert string to array for assignees or proper format for assignee
                        if isinstance(value, str):
                            if key == "assignees":
                                issue_dict[key] = [value] if value else []
                            else:  # assignee
                                issue_dict[key] = {"name": value} if value else None
                        elif isinstance(value, list) and key == "assignee" and value:
                            # If assignee is a list but should be a dict with name
                            issue_dict[key] = {"name": value[0]}
                        else:
                            issue_dict[key] = value
                    elif key == "labels":
                        # Convert string to array for labels
                        if isinstance(value, str):
                            issue_dict[key] = [value] if value else []
                        else:
                            issue_dict[key] = value
                    elif key == "milestone":
                        # Convert string to number for milestone
                        if isinstance(value, str) and value.isdigit():
                            issue_dict[key] = int(value)
                        else:
                            issue_dict[key] = value
                    else:
                        issue_dict[key] = value
    
            # Use v3 API client
            v3_client = self._get_v3_api_client()
            response_data = await v3_client.create_issue(fields=issue_dict)
    
            # Extract issue details from v3 API response
            issue_key = response_data.get("key")
            issue_id = response_data.get("id")
    
            logger.info(f"Successfully created issue {issue_key} (ID: {issue_id})")
    
            # Return JiraIssueResult with the created issue details
            # For v3 API, we return what we have from the create response
            return JiraIssueResult(
                key=issue_key,
                summary=summary,  # Use the summary we provided
                description=description,  # Use the description we provided
                status="Open",  # Default status for new issues
            )
    
        except Exception as e:
            error_msg = f"Failed to create issue: {type(e).__name__}: {str(e)}"
            logger.error(error_msg, exc_info=True)
    
            # Enhanced error handling for issue type errors
            if "issuetype" in str(e).lower() or "issue type" in str(e).lower():
                logger.info(
                    "Issue type error detected, trying to provide helpful suggestions..."
                )
                try:
                    project_key = (
                        project if isinstance(project, str) else project.get("key")
                    )
                    if project_key:
                        issue_types = await self.get_jira_project_issue_types(
                            project_key
                        )
                        type_names = [t.get("name") for t in issue_types]
                        logger.info(
                            f"Available issue types for project {project_key}: {', '.join(type_names)}"
                        )
    
                        # Try to find the closest match
                        attempted_type = issue_type
                        closest = None
                        attempted_lower = attempted_type.lower()
                        for t in type_names:
                            if (
                                attempted_lower in t.lower()
                                or t.lower() in attempted_lower
                            ):
                                closest = t
                                break
    
                        if closest:
                            logger.info(
                                f"The closest match to '{attempted_type}' is '{closest}'"
                            )
                            error_msg += f" Available types: {', '.join(type_names)}. Closest match: '{closest}'"
                        else:
                            error_msg += f" Available types: {', '.join(type_names)}"
                except Exception as fetch_error:
                    logger.error(f"Could not fetch issue types: {str(fetch_error)}")
    
            raise ValueError(error_msg)
  • Tool call dispatching in call_tool() that handles invocation of create_jira_issue by extracting arguments and calling the handler method.
    case JiraTools.CREATE_ISSUE.value:
        logger.info("About to AWAIT jira_server.create_jira_issue...")
        required_args = ["project", "summary", "description", "issue_type"]
        if not all(arg in arguments for arg in required_args):
            missing = [arg for arg in required_args if arg not in arguments]
            raise ValueError(
                f"Missing required arguments: {', '.join(missing)}"
            )
        result = await jira_server.create_jira_issue(
            arguments["project"],
            arguments["summary"],
            arguments["description"],
            arguments["issue_type"],
            arguments.get("fields", {}),
        )
        logger.info("COMPLETED await jira_server.create_jira_issue.")
  • Registers the create_jira_issue tool in list_tools() with name, description, and detailed input schema definition.
    Tool(
        name=JiraTools.CREATE_ISSUE.value,
        description="Create a new Jira issue. Common issue types include 'Bug', 'Task', 'Story', 'Epic' (capitalization handled automatically)",
        inputSchema={
            "type": "object",
            "properties": {
                "project": {
                    "type": "string",
                    "description": "Project key (e.g., 'MYPROJ')",
                },
                "summary": {
                    "type": "string",
                    "description": "Issue summary/title",
                },
                "description": {
                    "type": "string",
                    "description": "Issue description",
                },
                "issue_type": {
                    "type": "string",
                    "description": "Issue type (e.g., 'Bug', 'Task', 'Story', 'Epic', 'New Feature', 'Improvement'). IMPORTANT: Types are case-sensitive and vary by Jira instance.",
                },
                "fields": {
                    "type": "object",
                    "description": "Additional fields for the issue (optional)",
                },
            },
            "required": ["project", "summary", "description", "issue_type"],
        },
    ),
  • Pydantic model defining the output structure returned by the create_jira_issue handler.
    class JiraIssueResult(BaseModel):
        key: str
        summary: str
        description: Optional[str] = None
        status: Optional[str] = None
        assignee: Optional[str] = None
        reporter: Optional[str] = None
        created: Optional[str] = None
        updated: Optional[str] = None
        fields: Optional[Dict[str, Any]] = None
        comments: Optional[List[Dict[str, Any]]] = None
        watchers: Optional[Dict[str, Any]] = None
        attachments: Optional[List[Dict[str, Any]]] = None
        subtasks: Optional[List[Dict[str, Any]]] = None
        project: Optional[Dict[str, Any]] = None
        issue_links: Optional[List[Dict[str, Any]]] = None
        worklog: Optional[List[Dict[str, Any]]] = None
        timetracking: Optional[Dict[str, Any]] = None
  • Low-level helper in JiraV3APIClient that performs the actual HTTP POST to create a single Jira issue via v3 REST API.
    async def create_issue(
        self,
        fields: Dict[str, Any],
        update: Optional[Dict[str, Any]] = None,
        history_metadata: Optional[Dict[str, Any]] = None,
        properties: Optional[list] = None,
        transition: Optional[Dict[str, Any]] = None,
    ) -> Dict[str, Any]:
        """
        Create an issue using the v3 REST API.
    
        Creates an issue or, where the option to create subtasks is enabled in Jira, a subtask.
        A transition may be applied, to move the issue or subtask to a workflow step other than
        the default start step, and issue properties set.
    
        Args:
            fields: Dict containing field names and values (required).
                   Must include project, summary, description, and issuetype.
            update: Dict containing update operations for fields
            history_metadata: Optional history metadata for the issue creation
            properties: Optional list of properties to set
            transition: Optional transition to apply after creation
    
        Returns:
            Dictionary containing the created issue details:
            - id: Issue ID
            - key: Issue key
            - self: URL to the created issue
            - transition: Transition result if applied
    
        Raises:
            ValueError: If required parameters are missing or creation fails
        """
        if not fields:
            raise ValueError("fields is required")
    
        # Build the request payload
        payload = {"fields": fields}
    
        # Add optional parameters
        if update:
            payload["update"] = update
    
        if history_metadata:
            payload["historyMetadata"] = history_metadata
    
        if properties:
            payload["properties"] = properties
    
        if transition:
            payload["transition"] = transition
    
        endpoint = "/issue"
        logger.debug(f"Creating issue with v3 API endpoint: {endpoint}")
        logger.debug(f"Create issue payload: {json.dumps(payload, indent=2)}")
    
        response_data = await self._make_v3_api_request("POST", endpoint, data=payload)
        logger.debug(f"Create issue response: {response_data}")
        return response_data

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

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