recent_run_issues
Retrieve code quality issues from the latest analysis on a specific branch to identify and address problems in your project.
Instructions
Get issues from the most recent analysis run on a specific branch
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectKey | Yes | DeepSource project key to fetch issues for | |
| branchName | Yes | Branch name to fetch the most recent run from | |
| first | No | Number of items to retrieve (forward pagination) | |
| after | No | Cursor to start retrieving items after (forward pagination) | |
| last | No | Number of items to retrieve (backward pagination) | |
| before | No | Cursor to start retrieving items before (backward pagination) | |
| page_size | No | Number of items per page (alias for first, for convenience) | |
| max_pages | No | Maximum number of pages to fetch (enables automatic multi-page fetching) |
Implementation Reference
- Top-level exported handler function for the 'recent_run_issues' tool. Sets up domain repository and client dependencies, creates the handler, executes it, and handles error responses.export async function handleDeepsourceRecentRunIssues( params: DeepsourceRecentRunIssuesParams ): Promise<ApiResponse> { const baseDeps = createDefaultHandlerDeps({ logger }); const apiKey = baseDeps.getApiKey(); const repositoryFactory = new RepositoryFactory({ apiKey }); const analysisRunRepository = repositoryFactory.createAnalysisRunRepository(); const client = new DeepSourceClient(apiKey); const deps: RecentRunIssuesHandlerDeps = { analysisRunRepository, client, logger, }; const handler = createRecentRunIssuesHandlerWithRepo(deps); const result = await handler(params); // If the domain handler returned an error response, throw an error for backward compatibility if (result.isError) { const firstContent = result.content[0]; if (firstContent) { const errorData = JSON.parse(firstContent.text); throw new Error(errorData.error); } else { throw new Error('Unknown recent run issues error'); } } return result; }
- src/handlers/recent-run-issues.ts:49-195 (handler)Domain-aware handler factory and execution logic. Finds the most recent run using the analysis run repository, fetches issues via DeepSource client, formats response with run details and issues.export function createRecentRunIssuesHandlerWithRepo(deps: RecentRunIssuesHandlerDeps) { return async function handleRecentRunIssues(params: DeepsourceRecentRunIssuesParams) { try { const { projectKey, branchName } = params; const projectKeyBranded = asProjectKey(projectKey); const branchNameBranded = asBranchName(branchName); deps.logger.info('Fetching recent run from repository and issues from client', { projectKey, branchName, }); // Get the most recent run using domain repository const recentRun = await deps.analysisRunRepository.findMostRecent( projectKeyBranded, branchNameBranded ); if (!recentRun) { deps.logger.error('No recent run found for branch', { projectKey, branchName }); throw new Error( `No recent analysis run found for branch "${branchName}" in project "${projectKey}"` ); } deps.logger.info('Found recent run, fetching issues via client', { runId: recentRun.runId, commitOid: recentRun.commitInfo.oid, branchName: recentRun.commitInfo.branch, }); // Get issues for this run using the client (since we don't have an issue domain aggregate yet) const result = await deps.client.getRecentRunIssues(projectKey, branchName as BranchName); // Verify we got the same run (sanity check) if (!result.run || result.run.runUid !== recentRun.runId) { deps.logger.warn('Mismatch between domain run and client run', { domainRunId: recentRun.runId, clientRunUid: result.run?.runUid || 'null', }); } deps.logger.info('Successfully fetched recent run issues', { runId: recentRun.runId, commitOid: recentRun.commitInfo.oid, issueCount: result.items.length, totalCount: result.totalCount, hasNextPage: result.pageInfo?.hasNextPage, hasPreviousPage: result.pageInfo?.hasPreviousPage, }); const recentRunData = { run: { id: recentRun.runId, runUid: recentRun.runId, // Domain aggregate uses runId as unique identifier commitOid: recentRun.commitInfo.oid, branchName: recentRun.commitInfo.branch, baseOid: recentRun.commitInfo.baseOid, status: recentRun.status, createdAt: recentRun.timestamps.createdAt, updatedAt: recentRun.timestamps.startedAt || recentRun.timestamps.createdAt, finishedAt: recentRun.timestamps.finishedAt, summary: { occurrencesIntroduced: recentRun.summary.totalIntroduced.count, occurrencesResolved: recentRun.summary.totalResolved.count, occurrencesSuppressed: recentRun.summary.totalSuppressed.count, occurrenceDistributionByAnalyzer: recentRun.summary.byAnalyzer.map((dist) => ({ analyzerShortcode: dist.analyzerShortcode, introduced: dist.introduced.count, })), occurrenceDistributionByCategory: recentRun.summary.byCategory.map((dist) => ({ category: dist.category, introduced: dist.introduced.count, })), }, repository: { name: 'Repository', // Domain aggregate doesn't store repository name directly id: recentRun.repositoryId, }, }, issues: result.items.map((issue: DeepSourceIssue) => ({ id: issue.id, title: issue.title, shortcode: issue.shortcode, category: issue.category, severity: issue.severity, status: issue.status, issue_text: issue.issue_text, file_path: issue.file_path, line_number: issue.line_number, tags: issue.tags, })), pageInfo: { hasNextPage: result.pageInfo?.hasNextPage || false, hasPreviousPage: result.pageInfo?.hasPreviousPage || false, startCursor: result.pageInfo?.startCursor || null, endCursor: result.pageInfo?.endCursor || null, }, totalCount: result.totalCount, // Provide helpful information and guidance usage_examples: { pagination: { next_page: 'For forward pagination, use first and after parameters', previous_page: 'For backward pagination, use last and before parameters', }, related_tools: { run_details: 'Use the run tool to get detailed information about a specific run', all_issues: 'Use the project_issues tool to get all issues in the project', other_runs: 'Use the runs tool to list all runs for the project', }, }, }; return { content: [ { type: 'text' as const, text: JSON.stringify(recentRunData), }, ], }; } catch (error) { deps.logger.error('Error in handleRecentRunIssues', { errorType: typeof error, errorName: error instanceof Error ? error.name : 'Unknown', errorMessage: error instanceof Error ? error.message : String(error), errorStack: error instanceof Error ? error.stack : 'No stack available', }); const errorMessage = error instanceof Error ? error.message : 'Unknown error'; deps.logger.debug('Returning error response', { errorMessage }); return { isError: true, content: [ { type: 'text' as const, text: JSON.stringify({ error: errorMessage, details: 'Failed to retrieve recent run issues', }), }, ], }; } }; }
- Input and output schema definition using Zod for the 'recent_run_issues' MCP tool.export const recentRunIssuesToolSchema = { name: 'recent_run_issues', description: 'Get issues from the most recent analysis run on a specific branch', inputSchema: { projectKey: z.string().describe('DeepSource project key to fetch issues for'), branchName: z.string().describe('Branch name to fetch the most recent run from'), first: z.number().optional().describe('Number of items to retrieve (forward pagination)'), after: z .string() .optional() .describe('Cursor to start retrieving items after (forward pagination)'), last: z.number().optional().describe('Number of items to retrieve (backward pagination)'), before: z .string() .optional() .describe('Cursor to start retrieving items before (backward pagination)'), page_size: z .number() .optional() .describe('Number of items per page (alias for first, for convenience)'), max_pages: z .number() .optional() .describe('Maximum number of pages to fetch (enables automatic multi-page fetching)'), }, outputSchema: { run: z.object({ id: z.string(), runUid: z.string(), commitOid: z.string(), branchName: z.string(), baseOid: z.string(), status: z.string(), createdAt: z.string(), updatedAt: z.string(), finishedAt: z.string().optional(), summary: z.object({ occurrencesIntroduced: z.number(), occurrencesResolved: z.number(), occurrencesSuppressed: z.number(), occurrenceDistributionByAnalyzer: z .array( z.object({ analyzerShortcode: z.string(), introduced: z.number(), }) ) .optional(), occurrenceDistributionByCategory: z .array( z.object({ category: z.string(), introduced: z.number(), }) ) .optional(), }), repository: z.object({ name: z.string(), id: z.string(), }), }), issues: z.array( z.object({ id: z.string(), title: z.string(), shortcode: z.string(), category: z.string(), severity: z.string(), status: z.string(), issue_text: z.string(), file_path: z.string(), line_number: z.number(), tags: z.array(z.string()), }) ), pageInfo: z.object({ hasNextPage: z.boolean(), hasPreviousPage: z.boolean(), startCursor: z.string().nullable(), endCursor: z.string().nullable(), }), totalCount: z.number(), }, };
- src/server/tool-registration.ts:190-211 (registration)Active handler adapter and invocation in TOOL_HANDLERS map used for registering the tool.recent_run_issues: async (params: unknown) => { const typedParams = params as Record<string, unknown>; const recentRunParams: DeepsourceRecentRunIssuesParams = { projectKey: typedParams.projectKey as string, branchName: typedParams.branchName as string, }; if (typeof typedParams.first === 'number') { recentRunParams.first = typedParams.first; } if (typeof typedParams.last === 'number') { recentRunParams.last = typedParams.last; } if (typeof typedParams.after === 'string') { recentRunParams.after = typedParams.after; } if (typeof typedParams.before === 'string') { recentRunParams.before = typedParams.before; } return handleDeepsourceRecentRunIssues(recentRunParams); },
- src/index-registry.ts:174-179 (registration)Deprecated registration of the 'recent_run_issues' tool in legacy index-registry....recentRunIssuesToolSchema, handler: async (params) => { const adaptedParams = adaptRecentRunIssuesParams(params); return handleDeepsourceRecentRunIssues(adaptedParams); }, });