Skip to main content
Glama
scoutos

Linear MCP Server

by scoutos

create_issue

Add tasks, bugs, or feature requests to your Linear workspace with clarity and organization by specifying title, team, description, priority, assignee, and project details.

Instructions

Create a new issue in Linear. This tool is useful for adding new tasks, bugs, or feature requests to your Linear workspace.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
assigneeIdNoThe ID of the user to assign the issue to
debugNoDebug mode to show extra diagnostics
descriptionNoThe detailed description of the issue
priorityNoThe priority of the issue (0-4)
projectIdNoThe ID of the project to associate with the issue
stateIdNoThe ID of the state to set for the issue
teamIdYesThe ID of the Linear team where the issue will be created
titleYesThe title of the issue to create

Implementation Reference

  • Main handler function for the 'create_issue' tool. Handles input, creates Linear client, calls the createIssue helper, formats success response with issue details, and provides detailed error messages with optional debug info.
    const handler = async (
      ctx,
      {
        title,
        teamId,
        description,
        priority,
        assigneeId,
        stateId,
        projectId,
        debug,
      }
    ) => {
      const logger = ctx.effects.logger;
    
      try {
        // Log details about config and parameters
        logger.debug('Create issue called with parameters:', {
          title,
          teamId,
          description: description
            ? `${description.substring(0, 20)}...`
            : undefined,
          priority,
          assigneeId,
          stateId,
          projectId,
          debug,
        });
    
        // Debug log for API key (masked)
        const apiKey = ctx.config.linearApiKey || '';
        const maskedKey = apiKey
          ? apiKey.substring(0, 4) + '...' + apiKey.substring(apiKey.length - 4)
          : '<not set>';
        logger.debug(`Using Linear API key: ${maskedKey}`);
    
        if (!ctx.config.linearApiKey) {
          throw new Error('LINEAR_API_KEY is not configured');
        }
    
        // Create a Linear client using our effect
        logger.debug('Creating Linear client');
        const linearClient = ctx.effects.linear.createClient(
          ctx.config.linearApiKey
        );
    
        // Create the issue using the Linear SDK client
        logger.debug('Executing Linear API to create issue');
        const options = {
          description,
          priority,
          assigneeId,
          stateId,
          projectId,
        };
    
        const result = await createIssue(
          linearClient,
          title,
          teamId,
          options,
          logger
        );
    
        // Log that we created the issue
        logger.info(`Created issue with ID: ${result.id}`);
    
        // Format the output
        const formatDate = timestamp => {
          if (!timestamp) return 'Just now';
          const date = new Date(timestamp);
          return date.toLocaleString();
        };
    
        let responseText = '';
        responseText += `✅ Issue created successfully\n\n`;
    
        // Add issue details
        responseText += `**Issue ID:** ${result.id}\n`;
        responseText += `**Title:** ${result.title}\n`;
    
        if (result.status) {
          responseText += `**Status:** ${result.status}\n`;
        }
    
        if (result.priority !== undefined) {
          const priorityLabels = ['No priority', 'Urgent', 'High', 'Medium', 'Low'];
          responseText += `**Priority:** ${priorityLabels[result.priority]}\n`;
        }
    
        if (result.assignee) {
          responseText += `**Assigned to:** ${result.assignee.name}\n`;
        }
    
        if (result.project) {
          responseText += `**Project:** ${result.project.name}\n`;
        }
    
        responseText += `**Created at:** ${formatDate(result.createdAt)}\n\n`;
    
        if (result.description) {
          responseText += `**Description:**\n${result.description}\n`;
        }
    
        logger.debug('Returning formatted issue result');
        return {
          content: [{ type: 'text', text: responseText }],
        };
      } catch (error) {
        logger.error(`Error creating issue: ${error.message}`);
        logger.error(error.stack);
    
        // Create a user-friendly error message with troubleshooting guidance
        let errorMessage = `Error creating issue: ${error.message}`;
    
        // Add detailed diagnostic information if in debug mode
        if (debug) {
          errorMessage += '\n\n=== DETAILED DEBUG INFORMATION ===';
    
          // Add parameters that were used
          errorMessage += `\nParameters:
    - title: ${title}
    - teamId: ${teamId}
    - description: ${description ? 'provided' : 'not provided'}
    - priority: ${priority !== undefined ? priority : 'not provided'}
    - assigneeId: ${assigneeId || 'not provided'}
    - stateId: ${stateId || 'not provided'}
    - projectId: ${projectId || 'not provided'}`;
    
          // Check if API key is configured
          const apiKey = ctx.config.linearApiKey || '';
          const keyStatus = apiKey
            ? `API key is configured (${apiKey.substring(
                0,
                4
              )}...${apiKey.substring(apiKey.length - 4)})`
            : 'API key is NOT configured - set LINEAR_API_KEY';
    
          errorMessage += `\n\nLinear API Status: ${keyStatus}`;
    
          // Add error details
          if (error.name) {
            errorMessage += `\nError type: ${error.name}`;
          }
    
          if (error.code) {
            errorMessage += `\nError code: ${error.code}`;
          }
    
          if (error.stack) {
            errorMessage += `\n\nStack trace: ${error.stack
              .split('\n')
              .slice(0, 3)
              .join('\n')}`;
          }
    
          // Add Linear API info for manual testing
          errorMessage += `\n\nLinear API: Using official Linear SDK (@linear/sdk)
    For manual testing, try using the SDK directly or the Linear API Explorer in the Linear UI.`;
        }
    
        // Add a note that debug mode can be enabled for more details
        if (!debug) {
          errorMessage += `\n\nFor more detailed diagnostics, retry with debug:true in the input.`;
        }
    
        return {
          content: [
            {
              type: 'text',
              text: errorMessage,
            },
          ],
          isError: true,
        };
      }
    };
  • Zod input schema defining parameters for the create_issue tool, including title, teamId (required), and optional fields like description, priority, assignee, etc.
    const CreateIssueInputSchema = z.object({
      title: z.string().describe('The title of the issue to create'),
      teamId: z
        .string()
        .min(1, { message: 'Team ID is required' })
        .describe('The ID of the Linear team where the issue will be created'),
      description: z
        .string()
        .optional()
        .describe('The detailed description of the issue'),
      priority: z
        .number()
        .min(0)
        .max(4)
        .optional()
        .describe('The priority of the issue (0-4)'),
      assigneeId: z
        .string()
        .optional()
        .describe('The ID of the user to assign the issue to'),
      stateId: z
        .string()
        .optional()
        .describe('The ID of the state to set for the issue'),
      projectId: z
        .string()
        .optional()
        .describe('The ID of the project to associate with the issue'),
      debug: z
        .boolean()
        .default(false)
        .describe('Debug mode to show extra diagnostics'),
    });
  • Tool factory using create_tool() that registers the 'create_issue' tool with its name, description, input schema, and handler function.
    export const CreateIssue = create_tool({
      name: 'create_issue',
      description:
        'Create a new issue in Linear. This tool is useful for adding new tasks, bugs, or feature requests to your Linear workspace.',
      inputSchema: CreateIssueInputSchema,
      handler,
    });
  • Helper function that performs the actual Linear SDK issue creation, input preparation, response processing with schema validation, and async data loading.
    async function createIssue(client, title, teamId, options = {}, logger) {
      try {
        logger?.debug(`Creating new Linear issue with title: ${title}`);
    
        // Prepare the issue creation input for the Linear SDK
        const issueInput = {
          title,
          teamId,
          description: options.description,
          priority: options.priority,
          assigneeId: options.assigneeId,
          stateId: options.stateId,
          projectId: options.projectId,
        };
    
        // Filter out undefined values
        Object.keys(issueInput).forEach(key => {
          if (issueInput[key] === undefined) {
            delete issueInput[key];
          }
        });
    
        logger?.debug('Issue creation payload:', issueInput);
    
        // Create the issue using the Linear SDK
        const issueResult = await client.createIssue(issueInput);
    
        if (!issueResult) {
          throw new Error('Failed to create issue, received null response');
        }
    
        // Linear API returns a promise for the created issue
        const issueData = await issueResult.issue;
    
        if (!issueData) {
          throw new Error('Failed to retrieve issue data from response');
        }
    
        logger?.debug(`Successfully created issue: ${issueData.id}`);
    
        // Load related data asynchronously
        let assigneeData = null;
        let projectData = null;
        let stateData = null;
    
        if (issueData.assignee) {
          assigneeData = await issueData.assignee;
        }
    
        if (issueData.project) {
          projectData = await issueData.project;
        }
    
        if (issueData.state) {
          stateData = await issueData.state;
        }
    
        // Process and validate the issue data using our schema
        const processedIssue = IssueSchema.parse({
          id: issueData.id,
          title: issueData.title,
          description: issueData.description || undefined, // Convert null to undefined
          status: stateData?.name,
          priority: issueData.priority,
          assignee: assigneeData
            ? {
                id: assigneeData.id,
                name: assigneeData.name,
                email: assigneeData.email,
              }
            : undefined,
          project: projectData
            ? {
                id: projectData.id,
                name: projectData.name,
              }
            : undefined,
          createdAt:
            issueData.createdAt instanceof Date
              ? issueData.createdAt.toISOString()
              : issueData.createdAt,
          updatedAt:
            issueData.updatedAt instanceof Date
              ? issueData.updatedAt.toISOString()
              : issueData.updatedAt,
        });
    
        return processedIssue;
      } catch (error) {
        // Enhanced error logging
        logger?.error(`Error creating Linear issue: ${error.message}`, {
          title,
          teamId,
          options,
          stack: error.stack,
        });
    
        // Check if it's a Zod validation error (formatted differently)
        if (error.name === 'ZodError') {
          logger?.error(
            'Zod validation error details:',
            JSON.stringify(error.errors, null, 2)
          );
        }
    
        // Rethrow the error for the tool to handle
        throw error;
      }
    }
  • src/index.js:109-118 (registration)
    Instantiation of the CreateIssue tool class with toolContext and addition to the all_tools array for MCP server registration.
    const all_tools = [
      new tools.ListIssues(toolContext),
      new tools.GetIssue(toolContext),
      new tools.ListMembers(toolContext),
      new tools.ListProjects(toolContext),
      new tools.GetProject(toolContext),
      new tools.ListTeams(toolContext),
      new tools.AddComment(toolContext),
      new tools.CreateIssue(toolContext),
    ];
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/scoutos/mcp-linear'

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