deepsource_project_runs
Retrieve and filter analysis runs for a DeepSource project using cursor-based pagination. Navigate pages with first, after, last, and before parameters, and filter by specific analyzers for targeted code quality insights.
Instructions
List analysis runs for a DeepSource project with support for Relay-style cursor-based pagination and filtering.
For forward pagination, use first (defaults to 10) with optional after cursor.
For backward pagination, use last (defaults to 10) with optional before cursor.
The response includes pageInfo with hasNextPage, hasPreviousPage, startCursor, and endCursor
to help navigate through pages.
Filtering options:
analyzerIn: Filter runs by specific analyzers
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | Cursor to fetch records after this position | |
| analyzerIn | No | Filter runs by specific analyzers (e.g. ["python", "javascript"]) | |
| before | No | Cursor to fetch records before this position | |
| first | No | Number of items to return after the "after" cursor (default: 10) | |
| last | No | Number of items to return before the "before" cursor (default: 10) | |
| offset | No | Legacy pagination: Number of items to skip | |
| projectKey | Yes | The unique identifier for the DeepSource project |
Implementation Reference
- src/handlers/project-runs.ts:265-293 (handler)The primary exported handler function for the deepsource_project_runs tool. It sets up domain repository dependencies and delegates to the core project runs handler logic.export async function handleDeepsourceProjectRuns( params: DeepsourceProjectRunsParams ): Promise<ApiResponse> { const baseDeps = createDefaultHandlerDeps({ logger }); const apiKey = baseDeps.getApiKey(); const repositoryFactory = new RepositoryFactory({ apiKey }); const analysisRunRepository = repositoryFactory.createAnalysisRunRepository(); const deps: ProjectRunsHandlerDeps = { analysisRunRepository, logger, }; const handler = createProjectRunsHandlerWithRepo(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 project runs error'); } } return result; }
- src/handlers/project-runs.ts:46-160 (handler)Core handler logic for fetching and formatting project runs using the domain analysis run repository. This is the main execution function.export function createProjectRunsHandlerWithRepo(deps: ProjectRunsHandlerDeps) { return async function handleProjectRuns(params: DeepsourceProjectRunsParams) { try { const { projectKey, analyzerIn, first } = params; // Note: after, last, before pagination parameters not yet implemented const projectKeyBranded = asProjectKey(projectKey); deps.logger.info('Fetching project runs from repository', { projectKey, hasAnalyzerFilter: Boolean(analyzerIn), }); // Get the analysis runs from repository // Note: Basic pagination using page/pageSize for now // Note: Advanced pagination and analyzer filtering can be implemented in future versions const pageSize = first || 20; // Default page size const page = 1; // For now, always fetch first page const result = await deps.analysisRunRepository.findByProject(projectKeyBranded, { page, pageSize, }); deps.logger.info('Successfully fetched project runs', { count: result.items.length, totalCount: result.totalCount, hasNextPage: result.hasNextPage, hasPreviousPage: result.hasPreviousPage, }); const runsData = { runs: result.items.map((run: AnalysisRun) => ({ id: run.runId, runUid: run.runId, // Domain aggregate uses runId as the unique identifier commitOid: run.commitInfo.oid, branchName: run.commitInfo.branch, baseOid: run.commitInfo.baseOid, status: run.status, createdAt: run.timestamps.createdAt, updatedAt: run.timestamps.startedAt || run.timestamps.createdAt, // Use startedAt or fallback to createdAt finishedAt: run.timestamps.finishedAt, summary: { occurrencesIntroduced: run.summary.totalIntroduced.count, occurrencesResolved: run.summary.totalResolved.count, occurrencesSuppressed: run.summary.totalSuppressed.count, occurrenceDistributionByAnalyzer: run.summary.byAnalyzer.map((dist) => ({ analyzerShortcode: dist.analyzerShortcode, introduced: dist.introduced.count, })), occurrenceDistributionByCategory: run.summary.byCategory.map((dist) => ({ category: dist.category, introduced: dist.introduced.count, })), }, repository: { name: 'Repository', // Domain aggregate doesn't store repository name directly id: run.repositoryId, }, })), pageInfo: { hasNextPage: result.hasNextPage || false, hasPreviousPage: result.hasPreviousPage || false, startCursor: null, // Cursor-based pagination not yet implemented in domain layer endCursor: null, // Cursor-based pagination not yet implemented in domain layer }, totalCount: result.totalCount, // Provide helpful guidance on filtering and pagination usage_examples: { filtering: { by_analyzer: 'Use the analyzerIn parameter to filter by specific analyzers', }, 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', run_issues: 'Use the recent_run_issues tool to get issues from the most recent run', }, }, }; return { content: [ { type: 'text' as const, text: JSON.stringify(runsData), }, ], }; } catch (error) { deps.logger.error('Error in handleProjectRuns', { 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 project runs', }), }, ], }; } }; }
- src/handlers/project-runs.ts:28-31 (schema)TypeScript interface defining the input parameters for the project runs handler, serving as the schema for tool inputs.export interface DeepsourceProjectRunsParams extends RunFilterParams { /** DeepSource project key to fetch runs for */ projectKey: string; }
- src/server/tool-registration.ts:148-176 (registration)Registration of the 'runs' tool handler in TOOL_HANDLERS, which adapts parameters and calls handleDeepsourceProjectRuns. This connects the tool to the MCP server.runs: async (params: unknown) => { const typedParams = params as Record<string, unknown>; const runsParams: { projectKey: string; analyzerIn: AnalyzerShortcode[]; first?: number; last?: number; after?: string; before?: string; } = { projectKey: typedParams.projectKey as string, analyzerIn: typedParams.analyzerIn as AnalyzerShortcode[], }; if (typeof typedParams.first === 'number') { runsParams.first = typedParams.first; } if (typeof typedParams.last === 'number') { runsParams.last = typedParams.last; } if (typeof typedParams.after === 'string') { runsParams.after = typedParams.after; } if (typeof typedParams.before === 'string') { runsParams.before = typedParams.before; } return handleDeepsourceProjectRuns(runsParams); },
- Parameter adapter function that converts raw MCP tool parameters to the typed DeepsourceProjectRunsParams expected by the handler. Used in deprecated registration path.export function adaptProjectRunsParams(params: unknown): DeepsourceProjectRunsParams { const typedParams = params as Record<string, unknown>; const result: DeepsourceProjectRunsParams = { projectKey: typedParams.projectKey as string, // Handler still expects string }; const analyzerIn = typedParams.analyzerIn as AnalyzerShortcode[] | undefined; if (analyzerIn !== undefined) result.analyzerIn = analyzerIn; const first = typedParams.first as number | undefined; if (first !== undefined) result.first = first; const last = typedParams.last as number | undefined; if (last !== undefined) result.last = last; const after = typedParams.after as string | undefined; if (after !== undefined) result.after = after; const before = typedParams.before as string | undefined; if (before !== undefined) result.before = before; return result;