Skip to main content
Glama

list_issues

Retrieve and filter MantisBT bug tracker issues with pagination, field selection, and client-side filtering for assignee, reporter, and status.

Instructions

List MantisBT issues with optional filtering. Returns a paginated list of issues. Use the "select" parameter to limit returned fields and reduce response size significantly.

Note: "assigned_to", "reporter_id", and "status" filters are applied client-side (the MantisBT REST API does not reliably support these as server-side filters). When any of these filters are active the tool automatically fetches multiple pages internally until enough matching results are found (up to 500 issues scanned). The "page" and "page_size" parameters refer to the resulting filtered list.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_idNoFilter by project ID
pageNoPage number (default: 1)
page_sizeNoIssues per page (default: 50, max: 50)
assigned_toNoFilter by handler/assignee user ID
reporter_idNoFilter by reporter user ID
filter_idNoUse a saved MantisBT filter ID
sortNoSort field (e.g. "last_updated", "id")
directionNoSort direction
selectNoComma-separated list of fields to include in the response (server-side projection). Significantly reduces response size. Example: "id,summary,status,priority,handler,updated_at"
statusNoFilter issues by status name (e.g. "new", "feedback", "acknowledged", "confirmed", "assigned", "resolved", "closed") or use "open" as shorthand for all statuses with id < 80 (i.e. not yet resolved or closed). Applied client-side after fetching — when combined with pagination, a page may contain fewer results than page_size.

Implementation Reference

  • The async handler function for 'list_issues' which handles both direct API calls and client-side filtering (when assigned_to, reporter_id, or status filters are used).
    async ({ project_id, page, page_size, assigned_to, reporter_id, filter_id, sort, direction, select, status }) => {
      try {
        const baseParams: Record<string, string | number | boolean | undefined> = {
          project_id,
          assigned_to,
          reporter_id,
          filter_id,
          sort,
          direction,
          select,
        };
    
        const needsClientFilter = status !== undefined || assigned_to !== undefined || reporter_id !== undefined;
    
        if (!needsClientFilter) {
          // No client-side filtering — single API call, pass pagination as-is
          const result = await client.get<MantisPaginatedIssues>('issues', { ...baseParams, page, page_size });
          return {
            content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
          };
        }
    
        // Client-side filtering active: scan multiple API pages until we have
        // enough matching results for the requested logical page.
        const API_PAGE_SIZE = 50; // always fetch max to minimise round-trips
        const MAX_API_PAGES = 10; // hard cap: scan at most 500 issues
        const neededTotal = page * page_size; // need this many matches to serve page N
    
        const matching: MantisIssue[] = [];
        let serverPage = 1;
        let hasMore = true;
    
        const statusLower = status?.toLowerCase();
    
        while (matching.length < neededTotal && serverPage <= MAX_API_PAGES && hasMore) {
          const batch = await client.get<MantisPaginatedIssues>('issues', {
            ...baseParams,
            page: serverPage,
            page_size: API_PAGE_SIZE,
          });
    
          const issues = batch.issues ?? [];
          hasMore = issues.length === API_PAGE_SIZE;
    
          for (const issue of issues) {
            if (statusLower) {
              if (!issue.status) continue;
              if (statusLower === 'open') {
                if ((issue.status.id ?? 0) >= MANTIS_RESOLVED_STATUS_ID) continue;
              } else if (issue.status.name?.toLowerCase() !== statusLower) {
                continue;
              }
            }
            if (assigned_to !== undefined && issue.handler?.id !== assigned_to) continue;
            if (reporter_id !== undefined && issue.reporter?.id !== reporter_id) continue;
            matching.push(issue);
          }
    
          serverPage++;
        }
    
        const start = (page - 1) * page_size;
        return {
          content: [{
            type: 'text',
            text: JSON.stringify({ issues: matching.slice(start, start + page_size) }, null, 2),
          }],
        };
      } catch (error) {
        const msg = error instanceof Error ? error.message : String(error);
        return { content: [{ type: 'text', text: errorText(msg) }], isError: true };
      }
    }
  • The Zod schema defining the input parameters for 'list_issues', including pagination and filtering options.
    inputSchema: z.object({
      project_id: z.coerce.number().int().positive().optional().describe('Filter by project ID'),
      page: z.coerce.number().int().positive().default(1).describe('Page number (default: 1)'),
      page_size: z.coerce.number().int().min(1).max(50).default(50).describe('Issues per page (default: 50, max: 50)'),
      assigned_to: z.coerce.number().int().positive().optional().describe('Filter by handler/assignee user ID'),
      reporter_id: z.coerce.number().int().positive().optional().describe('Filter by reporter user ID'),
      filter_id: z.coerce.number().int().positive().optional().describe('Use a saved MantisBT filter ID'),
      sort: z.string().optional().describe('Sort field (e.g. "last_updated", "id")'),
      direction: z.enum(['ASC', 'DESC']).optional().describe('Sort direction'),
      select: z.string().optional().describe('Comma-separated list of fields to include in the response (server-side projection). Significantly reduces response size. Example: "id,summary,status,priority,handler,updated_at"'),
      status: z.string().optional().describe('Filter issues by status name (e.g. "new", "feedback", "acknowledged", "confirmed", "assigned", "resolved", "closed") or use "open" as shorthand for all statuses with id < 80 (i.e. not yet resolved or closed). Applied client-side after fetching — when combined with pagination, a page may contain fewer results than page_size.'),
    }),
  • Tool registration block for 'list_issues' in 'src/tools/issues.ts'.
    server.registerTool(
      'list_issues',
      {
        title: 'List Issues',
        description: 'List MantisBT issues with optional filtering. Returns a paginated list of issues. Use the "select" parameter to limit returned fields and reduce response size significantly.\n\nNote: "assigned_to", "reporter_id", and "status" filters are applied client-side (the MantisBT REST API does not reliably support these as server-side filters). When any of these filters are active the tool automatically fetches multiple pages internally until enough matching results are found (up to 500 issues scanned). The "page" and "page_size" parameters refer to the resulting filtered list.',
        inputSchema: z.object({
          project_id: z.coerce.number().int().positive().optional().describe('Filter by project ID'),
          page: z.coerce.number().int().positive().default(1).describe('Page number (default: 1)'),
          page_size: z.coerce.number().int().min(1).max(50).default(50).describe('Issues per page (default: 50, max: 50)'),
          assigned_to: z.coerce.number().int().positive().optional().describe('Filter by handler/assignee user ID'),
          reporter_id: z.coerce.number().int().positive().optional().describe('Filter by reporter user ID'),
          filter_id: z.coerce.number().int().positive().optional().describe('Use a saved MantisBT filter ID'),
          sort: z.string().optional().describe('Sort field (e.g. "last_updated", "id")'),
          direction: z.enum(['ASC', 'DESC']).optional().describe('Sort direction'),
          select: z.string().optional().describe('Comma-separated list of fields to include in the response (server-side projection). Significantly reduces response size. Example: "id,summary,status,priority,handler,updated_at"'),
          status: z.string().optional().describe('Filter issues by status name (e.g. "new", "feedback", "acknowledged", "confirmed", "assigned", "resolved", "closed") or use "open" as shorthand for all statuses with id < 80 (i.e. not yet resolved or closed). Applied client-side after fetching — when combined with pagination, a page may contain fewer results than page_size.'),
        }),
        annotations: {
          readOnlyHint: true,
          destructiveHint: false,
          idempotentHint: true,
        },
      },

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/dpesch/mantisbt-mcp-server'

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