Skip to main content
Glama

search_issues

Find Jira issues using JQL queries to filter by assignee, status, labels, parent/epic, or other criteria.

Instructions

Search for issues using JQL (Jira Query Language). Use this to find issues by parent/epic, assignee, status, labels, or any other criteria. Example JQL: "parent=TSSE-206", "assignee=currentuser() AND status="In Progress"", "labels=Dec15-19"

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
jqlYesJQL query string (e.g., "parent=EPIC-123", "project=TSSE AND status="To Do"")
maxResultsNoMaximum number of results to return (default: 50, max: 100)

Implementation Reference

  • MCP tool handler function for search_issues that validates JQL input, calls the underlying searchIssues helper, limits results, formats output with assignee display names, and handles errors.
    async ({ jql, maxResults }) => {
      try {
        if (!jql || !jql.trim()) {
          throw new Error('jql is required');
        }
    
        const issues = await searchIssues(jql, ['summary', 'status', 'priority', 'assignee', 'updated']);
        
        // Apply maxResults limit (default 50, max 100)
        const limit = Math.min(maxResults || 50, 100);
        const limitedIssues = issues.slice(0, limit);
        
        // Map to include assignee display name
        const mappedIssues = limitedIssues.map(issue => ({
          key: issue.key,
          summary: issue.summary,
          status: issue.status,
          priority: issue.priority,
          assignee: issue.assignee,
          updated: issue.updated,
        }));
    
        const output = { issues: mappedIssues, total: issues.length };
        return {
          content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
          structuredContent: output,
        };
      } catch (error) {
        const errOutput = formatError(error);
        return {
          content: [{ type: 'text', text: JSON.stringify(errOutput, null, 2) }],
          structuredContent: errOutput,
          isError: true,
        };
      }
    }
  • Input and output schemas using Zod for the search_issues tool, defining JQL query input and structured issues output.
    {
      title: 'Search Issues',
      description: 'Search for issues using JQL (Jira Query Language). Use this to find issues by parent/epic, assignee, status, labels, or any other criteria. Example JQL: "parent=TSSE-206", "assignee=currentuser() AND status=\"In Progress\"", "labels=Dec15-19"',
      inputSchema: {
        jql: z.string().describe('JQL query string (e.g., "parent=EPIC-123", "project=TSSE AND status=\"To Do\"")'),
        maxResults: z.number().optional().describe('Maximum number of results to return (default: 50, max: 100)'),
      },
      outputSchema: {
        issues: z.array(z.object({
          key: z.string(),
          summary: z.string(),
          status: z.string(),
          priority: z.string(),
          assignee: z.string().optional(),
          updated: z.string(),
        })).optional(),
        total: z.number().optional(),
        error: z.object({
          message: z.string(),
          statusCode: z.number().optional(),
          details: z.unknown().optional(),
        }).optional(),
      },
    },
  • src/index.ts:281-342 (registration)
    Full registration of the search_issues tool with MCP server, including name, schema, title, description, and handler function.
    server.registerTool(
      'search_issues',
      {
        title: 'Search Issues',
        description: 'Search for issues using JQL (Jira Query Language). Use this to find issues by parent/epic, assignee, status, labels, or any other criteria. Example JQL: "parent=TSSE-206", "assignee=currentuser() AND status=\"In Progress\"", "labels=Dec15-19"',
        inputSchema: {
          jql: z.string().describe('JQL query string (e.g., "parent=EPIC-123", "project=TSSE AND status=\"To Do\"")'),
          maxResults: z.number().optional().describe('Maximum number of results to return (default: 50, max: 100)'),
        },
        outputSchema: {
          issues: z.array(z.object({
            key: z.string(),
            summary: z.string(),
            status: z.string(),
            priority: z.string(),
            assignee: z.string().optional(),
            updated: z.string(),
          })).optional(),
          total: z.number().optional(),
          error: z.object({
            message: z.string(),
            statusCode: z.number().optional(),
            details: z.unknown().optional(),
          }).optional(),
        },
      },
      async ({ jql, maxResults }) => {
        try {
          if (!jql || !jql.trim()) {
            throw new Error('jql is required');
          }
    
          const issues = await searchIssues(jql, ['summary', 'status', 'priority', 'assignee', 'updated']);
          
          // Apply maxResults limit (default 50, max 100)
          const limit = Math.min(maxResults || 50, 100);
          const limitedIssues = issues.slice(0, limit);
          
          // Map to include assignee display name
          const mappedIssues = limitedIssues.map(issue => ({
            key: issue.key,
            summary: issue.summary,
            status: issue.status,
            priority: issue.priority,
            assignee: issue.assignee,
            updated: issue.updated,
          }));
    
          const output = { issues: mappedIssues, total: issues.length };
          return {
            content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
            structuredContent: output,
          };
        } catch (error) {
          const errOutput = formatError(error);
          return {
            content: [{ type: 'text', text: JSON.stringify(errOutput, null, 2) }],
            structuredContent: errOutput,
            isError: true,
          };
        }
      }
  • Core helper function implementing the Jira JQL search via the /search/jql API endpoint, handling fields parameter, response parsing, and mapping to simplified JiraIssue format. Called by the tool handler.
    export async function searchIssues(jql: string, fields: string[] = ['summary', 'status', 'priority', 'updated']): Promise<JiraIssue[]> {
      const params = new URLSearchParams({
        jql,
        maxResults: '100',
      });
      // Add fields as separate params (the new API accepts array-style)
      fields.forEach(f => params.append('fields', f));
    
      const response = await jiraFetch<{
        issues: Array<{
          key: string;
          id: string;
          fields: {
            summary: string;
            status: { name: string };
            priority: { name: string };
            updated: string;
            description?: unknown;
            assignee?: { displayName: string; accountId: string };
            reporter?: { displayName: string; accountId: string };
            created?: string;
            comment?: { comments: Array<{ id: string; author: { displayName: string }; body: unknown; created: string; updated: string }> };
          };
        }>;
        isLast?: boolean;
        nextPageToken?: string;
      }>(`/search/jql?${params.toString()}`);
    
      return response.issues.map((issue) => ({
        key: issue.key,
        summary: issue.fields.summary,
        status: issue.fields.status.name,
        priority: issue.fields.priority?.name || 'None',
        updated: issue.fields.updated,
        assignee: issue.fields.assignee?.displayName,
      }));
    }

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/eh24905-wiz/jira-mcp'

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