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

Tool Definition Quality

Score is being calculated. Check back soon.

Install Server

Other Tools

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

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