Skip to main content
Glama
sapientpants

DeepSource MCP Server

by sapientpants

run

Retrieve specific code analysis results from DeepSource using a project key and run identifier or commit hash to access detailed quality metrics and issues.

Instructions

Get a specific analysis run by its runUid or commitOid

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectKeyYesDeepSource project key to identify the project
runIdentifierYesThe run identifier (runUid or commitOid)
isCommitOidNoFlag to indicate whether the runIdentifier is a commitOid (default: false)

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
runYes
analysisYes

Implementation Reference

  • Core handler function that executes the 'run' tool logic: fetches AnalysisRun from repository by runId or commitOid, formats response with run details, summary, analysis info, and returns MCP content.
      return async function handleRun(params: DeepsourceRunParams) {
        try {
          const { projectKey, runIdentifier, isCommitOid = false } = params;
          const projectKeyBranded = asProjectKey(projectKey);
    
          deps.logger.info('Fetching run from repository', {
            projectKey,
            runIdentifier,
            identifierType: isCommitOid ? 'commitOid' : 'runUid',
          });
    
          let domainRun: AnalysisRun | null;
    
          if (isCommitOid) {
            // Search by commit OID
            const commitOidBranded = asCommitOid(runIdentifier);
            domainRun = await deps.analysisRunRepository.findByCommit(
              projectKeyBranded,
              commitOidBranded
            );
          } else {
            // Search by run ID (assuming runIdentifier is the runId)
            const runIdBranded = asRunId(runIdentifier);
            domainRun = await deps.analysisRunRepository.findByRunId(runIdBranded);
          }
    
          if (!domainRun) {
            deps.logger.error('Run not found', {
              projectKey,
              runIdentifier,
              identifierType: isCommitOid ? 'commitOid' : 'runUid',
            });
            throw new Error(
              `Run with ${isCommitOid ? 'commitOid' : 'runUid'} "${runIdentifier}" not found`
            );
          }
    
          deps.logger.info('Successfully fetched run', {
            runId: domainRun.runId,
            commitOid: domainRun.commitInfo.oid,
            branchName: domainRun.commitInfo.branch,
            status: domainRun.status,
          });
    
          const runData = {
            run: {
              id: domainRun.runId,
              runUid: domainRun.runId, // Domain aggregate uses runId as the unique identifier
              commitOid: domainRun.commitInfo.oid,
              branchName: domainRun.commitInfo.branch,
              baseOid: domainRun.commitInfo.baseOid,
              status: domainRun.status,
              createdAt: domainRun.timestamps.createdAt,
              updatedAt: domainRun.timestamps.startedAt || domainRun.timestamps.createdAt,
              finishedAt: domainRun.timestamps.finishedAt,
              summary: {
                occurrencesIntroduced: domainRun.summary.totalIntroduced.count,
                occurrencesResolved: domainRun.summary.totalResolved.count,
                occurrencesSuppressed: domainRun.summary.totalSuppressed.count,
                occurrenceDistributionByAnalyzer: domainRun.summary.byAnalyzer.map((dist) => ({
                  analyzerShortcode: dist.analyzerShortcode,
                  introduced: dist.introduced.count,
                })),
                occurrenceDistributionByCategory: domainRun.summary.byCategory.map((dist) => ({
                  category: dist.category,
                  introduced: dist.introduced.count,
                })),
              },
              repository: {
                name: 'Repository', // Domain aggregate doesn't store repository name directly
                id: domainRun.repositoryId,
              },
            },
            // Provide helpful guidance and related information
            analysis: {
              status_info: getStatusInfo(domainRun.status),
              issue_summary: `This run introduced ${domainRun.summary.totalIntroduced.count} issues, resolved ${domainRun.summary.totalResolved.count} issues, and suppressed ${domainRun.summary.totalSuppressed.count} issues.`,
              analyzers_used: domainRun.summary.byAnalyzer?.map((a) => a.analyzerShortcode) || [],
              issue_categories: domainRun.summary.byCategory?.map((c) => c.category) || [],
            },
            related_tools: {
              issues: 'Use the project_issues tool to get all issues in the project',
              runs: 'Use the runs tool to list all runs for the project',
              recent_issues:
                'Use the recent_run_issues tool to get issues from the most recent run on a branch',
            },
          };
    
          return {
            content: [
              {
                type: 'text' as const,
                text: JSON.stringify(runData),
              },
            ],
          };
        } catch (error) {
          deps.logger.error('Error in handleRun', {
            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 run',
                }),
              },
            ],
          };
        }
      };
    }
  • Zod input and output schema definition for the 'run' MCP tool, specifying parameters and response structure.
    export const runToolSchema = {
      name: 'run',
      description: 'Get a specific analysis run by its runUid or commitOid',
      inputSchema: {
        projectKey: z.string().describe('DeepSource project key to identify the project'),
        runIdentifier: z.string().describe('The run identifier (runUid or commitOid)'),
        isCommitOid: z
          .boolean()
          .optional()
          .describe('Flag to indicate whether the runIdentifier is a commitOid (default: false)'),
      },
      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(),
          }),
        }),
        analysis: z.object({
          status_info: z.string(),
          issue_summary: z.string(),
          analyzers_used: z.array(z.string()),
          issue_categories: z.array(z.string()),
        }),
      },
    };
  • TOOL_HANDLERS mapping for 'run' tool: wraps raw params, types them as DeepsourceRunParams, and delegates to handleDeepsourceRun.
    run: async (params: unknown) => {
      const typedParams = params as Record<string, unknown>;
      const runParams: DeepsourceRunParams = {
        projectKey: typedParams.projectKey as string,
        runIdentifier: typedParams.runIdentifier as string,
      };
    
      if (typeof typedParams.isCommitOid === 'boolean') {
        runParams.isCommitOid = typedParams.isCommitOid;
      }
    
      return handleDeepsourceRun(runParams);
    },
  • Handler entry point that initializes repository dependencies and invokes the core run handler function.
    export async function handleDeepsourceRun(params: DeepsourceRunParams): Promise<ApiResponse> {
      const baseDeps = createDefaultHandlerDeps({ logger });
      const apiKey = baseDeps.getApiKey();
      const repositoryFactory = new RepositoryFactory({ apiKey });
      const analysisRunRepository = repositoryFactory.createAnalysisRunRepository();
    
      const deps: RunHandlerDeps = {
        analysisRunRepository,
        logger,
      };
    
      const handler = createRunHandlerWithRepo(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 run error');
        }
      }
    
      return result;
    }
  • Main registration function that iterates over toolSchemas (including 'run'), pairs with TOOL_HANDLERS['run'], creates ToolDefinition, and registers with MCP ToolRegistry which calls server.registerTool.
    export function registerDeepSourceTools(registry: ToolRegistry): void {
      logger.info('=== REGISTER DEEPSOURCE TOOLS START ===');
      logger.info('Registering DeepSource tools', {
        toolSchemasType: typeof toolSchemas,
        toolSchemasIsArray: Array.isArray(toolSchemas),
        toolSchemasLength: Array.isArray(toolSchemas) ? toolSchemas.length : 'not an array',
        toolSchemaNames: Array.isArray(toolSchemas) ? toolSchemas.map((s) => s.name) : 'not an array',
      });
    
      const toolDefinitions: ToolDefinition[] = [];
    
      // Create tool definitions from schemas and handlers
      for (const schema of toolSchemas) {
        logger.debug(`Processing schema: ${schema.name}`);
        const handler = TOOL_HANDLERS[schema.name];
        if (!handler) {
          logger.warn(`No handler found for tool: ${schema.name}`);
          continue;
        }
    
        logger.debug(`Creating tool definition for: ${schema.name}`);
        const toolDef = createToolDefinition(schema, handler);
        toolDefinitions.push(toolDef);
        logger.debug(`Successfully created tool definition for: ${schema.name}`);
      }
    
      logger.info(`Prepared ${toolDefinitions.length} tool definitions for registration`);
    
      // Register all tools
      registry.registerTools(toolDefinitions);
    
      logger.info('=== REGISTER DEEPSOURCE TOOLS COMPLETE ===', {
        registeredCount: toolDefinitions.length,
        registeredTools: toolDefinitions.map((t) => t.name),
      });
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden but only states the basic action. It doesn't disclose behavioral traits like whether this is a read-only operation, if it requires authentication, potential rate limits, error handling, or what the output contains. For a tool with no annotations, this is a significant gap in transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the core purpose without unnecessary words. Every part earns its place by specifying the action, resource, and identifiers concisely, making it easy to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema (which handles return values) and high schema coverage, the description is minimally adequate. However, with no annotations and a mutation-focused sibling tool ('update_metric_setting'), it should clarify this is a read operation to avoid confusion. The description is complete enough for basic use but lacks context on safety and alternatives.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds no additional meaning beyond implying the runIdentifier can be either runUid or commitOid, which is already covered in the schema. Baseline 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Get') and resource ('a specific analysis run') with specific identifiers mentioned ('runUid or commitOid'). It distinguishes itself from sibling tools like 'runs' (likely listing multiple runs) by focusing on retrieving a single run, though it doesn't explicitly name alternatives. The purpose is specific but could be more differentiated from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'runs' or 'recent_run_issues'. It mentions the identifiers but doesn't explain scenarios where one might prefer this tool over others, such as for detailed analysis of a particular run versus overviews. No exclusions or prerequisites are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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