backlog_list
List and filter backlog tasks by status, type, or search query to manage work items and track progress with customizable limits.
Instructions
List tasks from backlog. Returns most recently updated items first. Default: shows only active work (open/in_progress/blocked), limited to 20 items. Use counts=true to check if more items exist beyond the limit.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| status | No | Filter by status. Options: open, in_progress, blocked, done, cancelled. Default: [open, in_progress, blocked]. Pass ["done"] to see completed work. | |
| type | No | Filter by type. Options: task, epic, folder, artifact, milestone. Default: returns all. | |
| epic_id | No | Filter tasks belonging to a specific epic. Example: epic_id="EPIC-0001" | |
| parent_id | No | Filter items by parent. Example: parent_id="FLDR-0001" | |
| query | No | Search across all task fields (title, description, evidence, references, etc.). Case-insensitive substring matching. | |
| counts | No | Include global counts { total_tasks, total_epics, by_status, by_type } alongside results. Use this to detect if more items exist beyond the limit. Default: false | |
| limit | No | Max items to return. Default: 20. Increase if you need to see more items (e.g., limit=100 to list all epics). |
Implementation Reference
- Main handler function that executes the backlog_list tool logic. It filters tasks by status, type, epic_id, parent_id, and query parameters, then formats the results with optional counts.
async ({ status, type, epic_id, parent_id, query, counts, limit }) => { // parent_id takes precedence; epic_id is alias for backward compat const resolvedParent = parent_id ?? epic_id; const tasks = await storage.list({ status, type, parent_id: resolvedParent, query, limit }); const list = tasks.map((t) => ({ id: t.id, title: t.title, status: t.status, type: t.type ?? 'task', parent_id: t.parent_id ?? t.epic_id, })); const result: any = { tasks: list }; if (counts) result.counts = storage.counts(); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } - Zod input schema defining all filter parameters for backlog_list: status array, type enum, epic_id, parent_id, query string, counts boolean, and limit number.
inputSchema: z.object({ status: z.array(z.enum(STATUSES)).optional().describe('Filter by status. Options: open, in_progress, blocked, done, cancelled. Default: [open, in_progress, blocked]. Pass ["done"] to see completed work.'), type: z.enum(ENTITY_TYPES).optional().describe('Filter by type. Options: task, epic, folder, artifact, milestone. Default: returns all.'), epic_id: z.string().optional().describe('Filter tasks belonging to a specific epic. Example: epic_id="EPIC-0001"'), parent_id: z.string().optional().describe('Filter items by parent. Example: parent_id="FLDR-0001"'), query: z.string().optional().describe('Search across all task fields (title, description, evidence, references, etc.). Case-insensitive substring matching.'), counts: z.boolean().optional().describe('Include global counts { total_tasks, total_epics, by_status, by_type } alongside results. Use this to detect if more items exist beyond the limit. Default: false'), limit: z.number().optional().describe('Max items to return. Default: 20. Increase if you need to see more items (e.g., limit=100 to list all epics).'), }), - packages/server/src/tools/backlog-list.ts:6-20 (registration)Tool registration function that registers 'backlog_list' with the MCP server, including the tool description and input schema.
export function registerBacklogListTool(server: McpServer) { server.registerTool( 'backlog_list', { description: 'List tasks from backlog. Returns most recently updated items first. Default: shows only active work (open/in_progress/blocked), limited to 20 items. Use counts=true to check if more items exist beyond the limit.', inputSchema: z.object({ status: z.array(z.enum(STATUSES)).optional().describe('Filter by status. Options: open, in_progress, blocked, done, cancelled. Default: [open, in_progress, blocked]. Pass ["done"] to see completed work.'), type: z.enum(ENTITY_TYPES).optional().describe('Filter by type. Options: task, epic, folder, artifact, milestone. Default: returns all.'), epic_id: z.string().optional().describe('Filter tasks belonging to a specific epic. Example: epic_id="EPIC-0001"'), parent_id: z.string().optional().describe('Filter items by parent. Example: parent_id="FLDR-0001"'), query: z.string().optional().describe('Search across all task fields (title, description, evidence, references, etc.). Case-insensitive substring matching.'), counts: z.boolean().optional().describe('Include global counts { total_tasks, total_epics, by_status, by_type } alongside results. Use this to detect if more items exist beyond the limit. Default: false'), limit: z.number().optional().describe('Max items to return. Default: 20. Increase if you need to see more items (e.g., limit=100 to list all epics).'), }), }, - Storage service list method that handles the actual data retrieval, including both search-based and filter-based listing of entities.
async list(filter?: { status?: Status[]; type?: EntityType; epic_id?: string; parent_id?: string; query?: string; limit?: number }): Promise<Entity[]> { const { query, ...storageFilter } = filter ?? {}; if (query) { await this.ensureSearchReady(); const results = await this.search.search(query, { filters: { status: storageFilter.status, type: storageFilter.type, epic_id: storageFilter.epic_id, parent_id: storageFilter.parent_id }, limit: storageFilter.limit, }); return results.map(r => ({ ...r.task, score: r.score })); } return this.taskStorage.list(storageFilter); } - Schema constants defining EntityType enum, ENTITY_TYPES array, and STATUSES array used as validation enums in backlog_list input schema.
export enum EntityType { Task = 'task', Epic = 'epic', Folder = 'folder', Artifact = 'artifact', Milestone = 'milestone', } export const ENTITY_TYPES = Object.values(EntityType); export const TYPE_PREFIXES: Record<EntityType, string> = { [EntityType.Task]: 'TASK', [EntityType.Epic]: 'EPIC', [EntityType.Folder]: 'FLDR', [EntityType.Artifact]: 'ARTF', [EntityType.Milestone]: 'MLST', }; const PREFIX_TO_TYPE: Record<string, EntityType> = Object.fromEntries( Object.entries(TYPE_PREFIXES).map(([type, prefix]) => [prefix, type as EntityType]), ) as Record<string, EntityType>; // ============================================================================ // Status // ============================================================================ export const STATUSES = ['open', 'in_progress', 'blocked', 'done', 'cancelled'] as const; export type Status = (typeof STATUSES)[number];