Skip to main content
Glama

create_jira_issues

Bulk create Jira issues using field dictionaries for multiple entries. Specify issue types like 'Bug', 'Task', or 'Story' as per your Jira instance, and optionally reload created issues.

Instructions

Bulk create new Jira issues. IMPORTANT: For 'issue_type', use the exact case-sensitive types in your Jira instance (common: 'Bug', 'Task', 'Story', 'Epic')

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
field_listYesA list of field dictionaries, each representing an issue to create
prefetchNoWhether to reload created issues (default: true)

Implementation Reference

  • Main handler: validates and transforms input field_list to v3 API format, handles description ADF conversion, issue type normalization, calls bulk_create_issues on v3 client, processes issues and errors in response.
    async def create_jira_issues(
        self, field_list: List[Dict[str, Any]], prefetch: bool = True
    ) -> List[Dict[str, Any]]:
        """Bulk create new Jira issues using v3 REST API.
    
        Parameters:
            field_list (List[Dict[str, Any]]): a list of dicts each containing field names and the values to use.
                                             Each dict is an individual issue to create.
            prefetch (bool): True reloads the created issue Resource so all of its data is present in the value returned (Default: True)
    
        Returns:
            List[Dict[str, Any]]: List of created issues with their details
    
        Issue Types:
            Common issue types include: 'Bug', 'Task', 'Story', 'Epic', 'New Feature', 'Improvement'
            Note: Available issue types vary by Jira instance and project
    
        Example:
            # Create multiple issues in bulk
            await create_jira_issues([
                {
                    'project': 'PROJ',
                    'summary': 'Implement user authentication',
                    'description': 'Add login and registration functionality',
                    'issue_type': 'Story'  # Note: case-sensitive, match to your Jira instance types
                },
                {
                    'project': 'PROJ',
                    'summary': 'Fix navigation bar display on mobile',
                    'description': 'Navigation bar is not displaying correctly on mobile devices',
                    'issue_type': 'Bug',
                    'priority': {'name': 'High'},
                    'labels': ['mobile', 'ui']
                }
            ])
        """
        logger.info("Starting create_jira_issues...")
    
        try:
            # Process each field dict to ensure proper formatting for v3 API
            processed_field_list = []
            for fields in field_list:
                # Create a properly formatted issue dictionary
                issue_dict = {}
    
                # Process required fields first to ensure they exist
                # Project field - required
                if "project" not in fields:
                    raise ValueError("Each issue must have a 'project' field")
                project_value = fields["project"]
                if isinstance(project_value, str):
                    issue_dict["project"] = {"key": project_value}
                else:
                    issue_dict["project"] = project_value
    
                # Summary field - required
                if "summary" not in fields:
                    raise ValueError("Each issue must have a 'summary' field")
                issue_dict["summary"] = fields["summary"]
    
                # Description field - convert to ADF format for v3 API if it's a simple string
                if "description" in fields:
                    description = fields["description"]
                    if isinstance(description, str):
                        # Convert simple string to Atlassian Document Format
                        issue_dict["description"] = {
                            "type": "doc",
                            "version": 1,
                            "content": [
                                {
                                    "type": "paragraph",
                                    "content": [
                                        {
                                            "type": "text",
                                            "text": description
                                        }
                                    ]
                                }
                            ]
                        }
                    else:
                        # Assume it's already in ADF format
                        issue_dict["description"] = description
    
                # Issue type field - required, handle both 'issuetype' and 'issue_type'
                issue_type = None
                if "issuetype" in fields:
                    issue_type = fields["issuetype"]
                elif "issue_type" in fields:
                    issue_type = fields["issue_type"]
                else:
                    raise ValueError(
                        "Each issue must have an 'issuetype' or 'issue_type' field"
                    )
    
                # Check for common issue type variants and fix case-sensitivity issues
                logger.debug(
                    f"Processing bulk issue_type: '{issue_type}' (type: {type(issue_type)})"
                )
                common_types = [
                    "bug",
                    "task",
                    "story",
                    "epic",
                    "improvement",
                    "newfeature",
                    "new feature",
                ]
    
                if isinstance(issue_type, str):
                    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.debug(
                            f"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
    
                # Process other fields
                for key, value in fields.items():
                    if key in [
                        "project",
                        "summary",
                        "description",
                        "issuetype",
                        "issue_type",
                    ]:
                        # Skip fields we've already processed
                        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
    
                # Add to the field list in v3 API format
                processed_field_list.append({"fields": issue_dict})
    
            logger.debug(f"Processed field list: {json.dumps(processed_field_list, indent=2)}")
    
            # Use v3 API client
            v3_client = self._get_v3_api_client()
            
            # Call the bulk create API
            response_data = await v3_client.bulk_create_issues(processed_field_list)
            
            # Process the results to maintain compatibility with existing interface
            processed_results = []
            
            # Handle successful issues
            if "issues" in response_data:
                for issue in response_data["issues"]:
                    processed_results.append({
                        "key": issue.get("key"),
                        "id": issue.get("id"),
                        "self": issue.get("self"),
                        "success": True,
                    })
            
            # Handle errors
            if "errors" in response_data:
                for error in response_data["errors"]:
                    processed_results.append({
                        "error": error,
                        "success": False,
                    })
    
            logger.info(f"Successfully processed {len(processed_results)} issue creations")
            return processed_results
    
        except Exception as e:
            error_msg = f"Failed to create issues in bulk: {type(e).__name__}: {str(e)}"
            logger.error(error_msg, exc_info=True)
            print(error_msg)
            raise ValueError(error_msg)
  • Tool registration in list_tools(): defines name 'create_jira_issues', description, and inputSchema for field_list array.
        name=JiraTools.CREATE_ISSUES.value,
        description="Bulk create new Jira issues. IMPORTANT: For 'issue_type', use the exact case-sensitive types in your Jira instance (common: 'Bug', 'Task', 'Story', 'Epic')",
        inputSchema={
            "type": "object",
            "properties": {
                "field_list": {
                    "type": "array",
                    "description": "A list of field dictionaries, each representing an issue to create",
                    "items": {
                        "type": "object",
                        "description": "Field dictionary for a single issue",
                    },
                },
                "prefetch": {
                    "type": "boolean",
                    "description": "Whether to reload created issues (default: true)",
                },
            },
            "required": ["field_list"],
        },
    ),
  • Tool dispatch in call_tool(): extracts arguments, calls jira_server.create_jira_issues(field_list, prefetch).
    case JiraTools.CREATE_ISSUES.value:
        logger.info("Calling async tool create_jira_issues...")
        field_list = arguments.get("field_list")
        if not field_list:
            raise ValueError("Missing required argument: field_list")
        prefetch = arguments.get("prefetch", True)
        result = await jira_server.create_jira_issues(field_list, prefetch)
        logger.info("Async tool create_jira_issues completed.")
  • Low-level helper: makes HTTP POST to /rest/api/3/issue/bulk with issueUpdates payload, handles response with issues and errors.
    async def bulk_create_issues(
        self, 
        issue_updates: list
    ) -> Dict[str, Any]:
        """
        Bulk create issues using the v3 REST API.
    
        Creates up to 50 issues and, where the option to create subtasks is enabled in Jira,
        subtasks. Transitions may be applied, to move the issues or subtasks to a workflow
        step other than the default start step, and issue properties set.
    
        Args:
            issue_updates: List of issue creation specifications. Each item should contain
                          'fields' dict with issue fields, and optionally 'update' dict
                          for additional operations during creation.
    
        Returns:
            Dict containing:
            - issues: List of successfully created issues with their details
            - errors: List of errors for failed issue creations
    
        Raises:
            ValueError: If required parameters are missing or bulk creation fails
        """
        if not issue_updates:
            raise ValueError("issue_updates list cannot be empty")
    
        if len(issue_updates) > 50:
            raise ValueError("Cannot create more than 50 issues in a single bulk operation")
    
        # Build the request payload for v3 API
        payload = {"issueUpdates": issue_updates}
    
        endpoint = "/issue/bulk"
        logger.debug(f"Bulk creating issues with v3 API endpoint: {endpoint}")
        logger.debug(f"Payload: {json.dumps(payload, indent=2)}")
    
        response_data = await self._make_v3_api_request("POST", endpoint, data=payload)
        logger.debug(f"Bulk create response: {json.dumps(response_data, indent=2)}")
    
        return response_data
  • Helper: lazily initializes the JiraV3APIClient used for all v3 API calls including bulk_create_issues.
    def _get_v3_api_client(self) -> JiraV3APIClient:
        """Get or create a v3 API client instance"""
        if not self._v3_api_client:
            self._v3_api_client = JiraV3APIClient(
                server_url=self.server_url,
                username=self.username,
                password=self.password,
                token=self.token,
            )
        return self._v3_api_client

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