list_project_issues
Retrieve and filter issues for a Sentry project to monitor errors, track unresolved problems, and manage debugging tasks with customizable search queries and time periods.
Instructions
List issues for a specific project, with optional filtering.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| organization_slug | No | The slug of the organization the project belongs to. | |
| project_slug | Yes | The slug of the project to list issues for. | |
| query | No | Sentry search query to filter issues (e.g., "is:unresolved", "assignee:me"). Optional. | |
| statsPeriod | No | Time period for statistics (e.g., "24h", "14d", "auto"). Optional. | |
| cursor | No | Pagination cursor for fetching next/previous page. Optional. |
Implementation Reference
- src/index.ts:232-285 (handler)Handler for the 'list_project_issues' tool. Extracts parameters, validates project_slug, makes API call to Sentry for project issues with optional filters and pagination, parses Link header for pagination info, returns JSON or error.case 'list_project_issues': { let { organization_slug, project_slug, query, statsPeriod, cursor } = request.params.arguments ?? {}; // If user doesn't provide slug, use default value read from environment variable organization_slug = typeof organization_slug === 'string' ? organization_slug : this.defaultOrgSlug; // Removed project_slug default assignment // project_slug required check if (typeof project_slug !== 'string' || project_slug.length === 0) { throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid argument: project_slug must be a non-empty string.'); } // Configure parameters for API request const apiParams: Record<string, string> = {}; if (typeof query === 'string' && query.length > 0) apiParams.query = query; if (typeof statsPeriod === 'string' && statsPeriod.length > 0) apiParams.statsPeriod = statsPeriod; if (typeof cursor === 'string' && cursor.length > 0) apiParams.cursor = cursor; try { const response = await this.axiosInstance.get( `projects/${organization_slug}/${project_slug}/issues/`, { params: apiParams } ); // Return result including pagination info (Link header parsing needed) const linkHeader = response.headers['link']; // Axios might return header keys in lowercase const paginationInfo = parseLinkHeader(linkHeader); // Link header parsing function needed return { content: [ { type: 'text', text: JSON.stringify({ issues: response.data, pagination: paginationInfo, // Add parsed pagination info }, null, 2), }, ], }; } catch (error) { let errorMessage = 'Failed to list Sentry project issues.'; if (axios.isAxiosError(error)) { errorMessage = `Sentry API error: ${error.response?.status} ${error.response?.statusText}. ${JSON.stringify(error.response?.data)}`; console.error("Sentry API Error Details:", error.response?.data); } else if (error instanceof Error) { errorMessage = error.message; } console.error("Error listing Sentry project issues:", error); return { content: [ { type: 'text', text: errorMessage } ], isError: true, }; } break; // End case
- src/index.ts:139-168 (registration)Registration of the 'list_project_issues' tool in the MCP ListTools response, including name, description, and detailed input schema.{ name: 'list_project_issues', description: 'List issues for a specific project, with optional filtering.', inputSchema: { type: 'object', properties: { organization_slug: { type: 'string', description: 'The slug of the organization the project belongs to.', }, project_slug: { type: 'string', description: 'The slug of the project to list issues for.', }, query: { type: 'string', description: 'Sentry search query to filter issues (e.g., "is:unresolved", "assignee:me"). Optional.', }, statsPeriod: { type: 'string', description: 'Time period for statistics (e.g., "24h", "14d", "auto"). Optional.', }, cursor: { type: 'string', description: 'Pagination cursor for fetching next/previous page. Optional.', } }, required: ['project_slug'], // Changed project_slug to required }, },
- src/index.ts:403-430 (helper)Helper function parseLinkHeader used in the handler to parse Sentry API's Link header for pagination information (next/prev cursors).function parseLinkHeader(header: string | undefined): Record<string, string> { if (!header) return {}; const links: Record<string, string> = {}; const parts = header.split(','); parts.forEach(part => { const section = part.split(';'); if (section.length < 2) return; const urlMatch = section[0].match(/<(.*)>/); if (!urlMatch) return; const url = urlMatch[1]; const params: Record<string, string> = {}; section.slice(1).forEach(paramPart => { const param = paramPart.trim().split('='); if (param.length === 2) { params[param[0]] = param[1].replace(/"/g, ''); } }); if (params.rel && params.results === 'true' && params.cursor) { links[params.rel] = params.cursor; // Use rel value (next or prev) as key } }); return links; }