Skip to main content
Glama

runs

List and filter analysis runs for a DeepSource project to track code quality assessments and review results.

Instructions

List analysis runs for a DeepSource project with filtering

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectKeyYesDeepSource project key to fetch runs for
analyzerInNoFilter runs by analyzer shortcodes
firstNoNumber of items to retrieve (forward pagination)
afterNoCursor to start retrieving items after (forward pagination)
lastNoNumber of items to retrieve (backward pagination)
beforeNoCursor to start retrieving items before (backward pagination)
page_sizeNoNumber of items per page (alias for first, for convenience)
max_pagesNoMaximum number of pages to fetch (enables automatic multi-page fetching)

Implementation Reference

  • Registers the 'runs' MCP tool with runsToolSchema and a handler that adapts input parameters and delegates to handleDeepsourceProjectRuns
    toolRegistry.registerTool({ ...runsToolSchema, handler: async (params) => { const adaptedParams = adaptProjectRunsParams(params); return handleDeepsourceProjectRuns(adaptedParams); }, });
  • Defines the inputSchema and outputSchema for the 'runs' tool using Zod validation, including parameters like projectKey, analyzerIn, pagination options, and detailed run response structure
    export const runsToolSchema = { name: 'runs', description: 'List analysis runs for a DeepSource project with filtering', inputSchema: { projectKey: z.string().describe('DeepSource project key to fetch runs for'), analyzerIn: z.array(z.string()).optional().describe('Filter runs by analyzer shortcodes'), 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: { runs: z.array( 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(), }), }) ), pageInfo: z.object({ hasNextPage: z.boolean(), hasPreviousPage: z.boolean(), startCursor: z.string().nullable(), endCursor: z.string().nullable(), }), totalCount: z.number(), }, };
  • Main handler function for the 'runs' tool. Sets up domain repository (analysisRunRepository), creates a handler with repo deps, executes the query via findByProject, maps results to MCP response format, handles errors and pagination info
    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; }
  • Core execution logic for fetching project runs using domain AnalysisRunRepository.findByProject, mapping aggregate data to the expected output format including summaries, pagination, and usage guidance
    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', }), }, ], }; } }; }
  • Adapts raw MCP tool parameters to DeepsourceProjectRunsParams interface expected by the handler, extracting and typing projectKey, analyzerIn, and pagination parameters
    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; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sapientpants/deepsource-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server