List Issues
list_issuesRetrieve and filter MantisBT bug tracker issues with pagination, field selection, and date-based queries to manage project workflows efficiently.
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", "status", and date filters are applied client-side (the MantisBT REST API does not 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.
Tip for date queries: fetching with select="id,updated_at,created_at" plus a date filter is very compact and efficient.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | No | Filter by project ID | |
| page | No | Page number (default: 1) | |
| page_size | No | Issues per page (default: 50, max: 50) | |
| assigned_to | No | Filter by handler/assignee user ID | |
| reporter_id | No | Filter by reporter user ID | |
| filter_id | No | Use a saved MantisBT filter ID | |
| sort | No | Sort field (e.g. "last_updated", "id") | |
| direction | No | Sort direction | |
| select | No | 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 | No | 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. | |
| updated_after | No | ISO-8601 timestamp — only return issues updated after this date (exclusive). Example: "2026-03-25T00:00:00Z" | |
| updated_before | No | ISO-8601 timestamp — only return issues updated before this date (exclusive). Example: "2026-03-28T00:00:00Z" | |
| created_after | No | ISO-8601 timestamp — only return issues created after this date (exclusive). Example: "2026-03-01T00:00:00Z" | |
| created_before | No | ISO-8601 timestamp — only return issues created before this date (exclusive). Example: "2026-03-15T00:00:00Z" |
Implementation Reference
- src/tools/issues.ts:183-273 (handler)The handler function for 'list_issues' that performs MantisBT issue fetching and client-side filtering/pagination.
async ({ project_id, page, page_size, assigned_to, reporter_id, filter_id, sort, direction, select, status, updated_after, updated_before, created_after, created_before }) => { try { const baseParams: Record<string, string | number | boolean | undefined> = { project_id, assigned_to, reporter_id, filter_id, sort, direction, select, }; const dateFilter: DateFilter = { updated_after, updated_before, created_after, created_before }; const needsClientFilter = status !== undefined || assigned_to !== undefined || reporter_id !== undefined || hasDateFilter(dateFilter); 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(); const statusId = status ? resolveEnumId('status', status) : undefined; // Pre-parse date thresholds once — avoids repeated new Date() inside the scan loop const updatedAfterMs = updated_after ? new Date(updated_after).getTime() : undefined; 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; let stopAfterBatch = false; 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 (statusId !== undefined) { if (issue.status.id !== statusId) 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; if (!matchesDateFilter(issue, dateFilter)) { // MantisBT returns results newest-first. Once updated_at drops below // updated_after, all subsequent pages are guaranteed to be older too. // Finish the current batch first (items within it may still be newer), // then stop fetching further pages. if (updatedAfterMs && issue.updated_at && new Date(issue.updated_at).getTime() <= updatedAfterMs) { stopAfterBatch = true; } continue; } matching.push(issue); } if (stopAfterBatch) break; 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 }; } } - src/tools/issues.ts:159-182 (registration)Tool registration for 'list_issues' along with its input schema and description.
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", "status", and date filters are applied client-side (the MantisBT REST API does not 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.\n\nTip for date queries: fetching with select="id,updated_at,created_at" plus a date filter is very compact and efficient.', 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.'), ...dateFilterSchema, }), annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, }, },