deepsource-mcp-server
Version:
Model Context Protocol server for DeepSource
147 lines • 6.7 kB
JavaScript
/**
* @fileoverview Run handler for the DeepSource MCP server
* This module provides MCP tool handlers for fetching a specific DeepSource analysis run.
*/
import { DeepSourceClient, } from '../deepsource.js';
import { createLogger } from '../utils/logging/logger.js';
// Logger for the run handler
const logger = createLogger('RunHandler');
/**
* Fetches and returns information about a specific analysis run
* @param params - Parameters for fetching the run, including project key and run identifier
* @returns A response containing the run data
* @throws Error if the DEEPSOURCE_API_KEY environment variable is not set
* @public
*/
export async function handleDeepsourceRun({ projectKey, runIdentifier, isCommitOid = false, }) {
const apiKey = process.env.DEEPSOURCE_API_KEY;
logger.debug('Checking API key', {
exists: Boolean(apiKey),
length: apiKey ? apiKey.length : 0,
prefix: apiKey ? `${apiKey.substring(0, 5)}...` : 'N/A',
});
if (!apiKey) {
logger.error('DEEPSOURCE_API_KEY environment variable is not set');
throw new Error('DEEPSOURCE_API_KEY environment variable is not set');
}
try {
logger.debug('Creating DeepSource client');
const client = new DeepSourceClient(apiKey);
logger.info('Fetching run', {
projectKey,
runIdentifier,
identifierType: isCommitOid ? 'commitOid' : 'runUid',
});
const run = await client.getRun(runIdentifier);
if (!run) {
logger.error('Run not found', {
projectKey,
runIdentifier,
identifierType: isCommitOid ? 'commitOid' : 'runUid',
});
throw new Error(`Run with ${isCommitOid ? 'commitOid' : 'runUid'} "${runIdentifier}" not found in project "${projectKey}"`);
}
logger.info('Successfully fetched run', {
runUid: run.runUid,
commitOid: run.commitOid,
branchName: run.branchName,
status: run.status,
});
return {
content: [
{
type: 'text',
text: JSON.stringify({
run: {
id: run.id,
runUid: run.runUid,
commitOid: run.commitOid,
branchName: run.branchName,
baseOid: run.baseOid,
status: run.status,
createdAt: run.createdAt,
updatedAt: run.updatedAt,
finishedAt: run.finishedAt,
summary: {
occurrencesIntroduced: run.summary.occurrencesIntroduced,
occurrencesResolved: run.summary.occurrencesResolved,
occurrencesSuppressed: run.summary.occurrencesSuppressed,
occurrenceDistributionByAnalyzer: run.summary.occurrenceDistributionByAnalyzer,
occurrenceDistributionByCategory: run.summary.occurrenceDistributionByCategory,
},
repository: {
name: run.repository.name,
id: run.repository.id,
},
},
// Provide helpful guidance and related information
analysis: {
status_info: getStatusInfo(run.status),
issue_summary: `This run introduced ${run.summary.occurrencesIntroduced} issues, resolved ${run.summary.occurrencesResolved} issues, and suppressed ${run.summary.occurrencesSuppressed} issues.`,
analyzers_used: run.summary.occurrenceDistributionByAnalyzer?.map((a) => a.analyzerShortcode) || [],
issue_categories: run.summary.occurrenceDistributionByCategory?.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',
},
}, null, 2),
},
],
};
}
catch (error) {
logger.error('Error in handleDeepsourceRun', {
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',
});
// Return an error object with details
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
logger.debug('Returning error response', { errorMessage });
return {
isError: true,
content: [
{
type: 'text',
text: JSON.stringify({
error: errorMessage,
details: 'Failed to retrieve run',
project_key: projectKey,
run_identifier: runIdentifier,
identifier_type: isCommitOid ? 'commitOid' : 'runUid',
}),
},
],
};
}
}
/**
* Helper function to get human-readable status information
* @param status The run status
* @returns Information about the status
* @private
*/
function getStatusInfo(status) {
switch (status) {
case 'PENDING':
return 'The run is currently queued and waiting to be processed.';
case 'SUCCESS':
return 'The run completed successfully with all analyzers.';
case 'FAILURE':
return 'The run failed due to an error during analysis.';
case 'TIMEOUT':
return 'The run exceeded the maximum allowed time and was terminated.';
case 'CANCEL':
return 'The run was manually cancelled.';
case 'READY':
return 'The run is ready to be processed but not yet started.';
case 'SKIPPED':
return 'The run was skipped, possibly due to no code changes detected.';
default:
return `Unknown status: ${status}`;
}
}
//# sourceMappingURL=run.js.map