Skip to main content
Glama
cbunting99

MCP Code Analysis & Quality Server

by cbunting99
index.ts11.1 kB
// Copyright 2025 Chris Bunting // Brief: Main entry point for the dependency analysis MCP server // Scope: Initializes the server and registers all tools import { PackageManager, SeverityLevel } from '@mcp-code-analysis/shared-types'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import { zodToJsonSchema } from 'zod-to-json-schema'; import { DependencyAnalyzer } from './services/DependencyAnalyzer.js'; import { DependencyGraphBuilder } from './services/DependencyGraphBuilder.js'; import { PackageManagerDetector } from './services/PackageManagerDetector.js'; import { SecurityAuditor } from './services/SecurityAuditor.js'; import { VersionResolver } from './services/VersionResolver.js'; import { Logger } from './utils/Logger.js'; // Create logger const logger = new Logger('DependencyAnalysisServer' as any); // Create service instances const packageManagerDetector = new PackageManagerDetector(logger); const dependencyGraphBuilder = new DependencyGraphBuilder(logger); const versionResolver = new VersionResolver(logger); const securityAuditor = new SecurityAuditor(logger); const dependencyAnalyzer = new DependencyAnalyzer( packageManagerDetector, dependencyGraphBuilder, versionResolver, securityAuditor, logger ); // Create server instance const server = new Server( { name: 'dependency-analysis-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Tool schemas const AnalyzeDependenciesSchema = z.object({ projectPath: z.string().describe('Path to the project directory'), includeDev: z.boolean().optional().default(true).describe('Include development dependencies'), includePeer: z.boolean().optional().default(true).describe('Include peer dependencies'), includeOptional: z.boolean().optional().default(true).describe('Include optional dependencies'), }); const CheckUpdatesSchema = z.object({ projectPath: z.string().describe('Path to the project directory'), packageName: z.string().optional().describe('Specific package name to check updates for'), }); const FindConflictsSchema = z.object({ projectPath: z.string().describe('Path to the project directory'), }); const SuggestAlternativesSchema = z.object({ packageName: z.string().describe('Name of the package to find alternatives for'), packageManager: z.nativeEnum(PackageManager).optional().describe('Package manager to use'), }); const SecurityAuditSchema = z.object({ projectPath: z.string().describe('Path to the project directory'), severity: z.nativeEnum(SeverityLevel).optional().default(SeverityLevel.WARNING).describe('Minimum severity level to report'), }); // Register tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'analyze_dependencies', description: 'Analyze project dependencies and generate comprehensive report', inputSchema: zodToJsonSchema(AnalyzeDependenciesSchema), }, { name: 'check_updates', description: 'Check for available updates for project dependencies', inputSchema: zodToJsonSchema(CheckUpdatesSchema), }, { name: 'find_conflicts', description: 'Find version conflicts in project dependencies', inputSchema: zodToJsonSchema(FindConflictsSchema), }, { name: 'suggest_alternatives', description: 'Suggest alternative packages for a given package', inputSchema: zodToJsonSchema(SuggestAlternativesSchema), }, { name: 'security_audit', description: 'Perform security audit of project dependencies', inputSchema: zodToJsonSchema(SecurityAuditSchema), }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'analyze_dependencies': { const { projectPath, includeDev, includePeer, includeOptional } = AnalyzeDependenciesSchema.parse(args); logger.info(`Analyzing dependencies for project: ${projectPath}`); const result = await dependencyAnalyzer.analyzeProject(projectPath, { includeDev, includePeer, includeOptional, }); // Format the result for output const formattedResult = { summary: { projectPath: result.projectPath, packageManager: result.packageManager, totalDependencies: result.metrics.totalDependencies, directDependencies: result.metrics.directDependencies, transitiveDependencies: result.metrics.transitiveDependencies, maxDepth: result.metrics.maxDepth, analysisTime: `${result.analysisTime}ms`, }, metrics: result.metrics, security: { vulnerablePackages: result.securityAudits.filter(a => a.vulnerabilities.length > 0).length, totalVulnerabilities: result.securityAudits.reduce((sum, audit) => sum + audit.vulnerabilities.length, 0), averageSecurityScore: result.securityAudits.reduce((sum, audit) => sum + audit.score, 0) / result.securityAudits.length || 100, }, updates: { outdatedPackages: result.outdatedPackages.length, majorUpdates: result.outdatedPackages.filter(p => p.semverDiff === 'major').length, minorUpdates: result.outdatedPackages.filter(p => p.semverDiff === 'minor').length, }, issues: { conflicts: result.conflicts.length, circularDependencies: result.circularDependencies.length, }, recommendations: result.recommendations, vulnerablePackages: result.securityAudits .filter(audit => audit.vulnerabilities.length > 0) .map(audit => ({ package: audit.package, version: audit.version, vulnerabilities: audit.vulnerabilities, score: audit.score, })), outdatedPackages: result.outdatedPackages, conflicts: result.conflicts, circularDependencies: result.circularDependencies, }; return { content: [ { type: 'text', text: JSON.stringify(formattedResult, null, 2), }, ], }; } case 'check_updates': { const { projectPath, packageName } = CheckUpdatesSchema.parse(args); logger.info(`Checking updates for project: ${projectPath}${packageName ? ` (package: ${packageName})` : ''}`); const updates = await dependencyAnalyzer.checkUpdates(projectPath, packageName); const formattedUpdates = { projectPath, packageName: packageName || 'all', updatesFound: updates.length, updates: updates.map(update => ({ package: update.package, currentVersion: update.current, latestVersion: update.latest, semverDiff: update.semverDiff, isBreaking: update.semverDiff === 'major', releaseDate: undefined, // Not available in UpdateInfo })), }; return { content: [ { type: 'text', text: JSON.stringify(formattedUpdates, null, 2), }, ], }; } case 'find_conflicts': { const { projectPath } = FindConflictsSchema.parse(args); logger.info(`Finding conflicts for project: ${projectPath}`); const conflicts = await dependencyAnalyzer.findConflicts(projectPath); const formattedConflicts = { projectPath, conflictsFound: conflicts.length, conflicts: conflicts.map(conflict => ({ package: conflict.package, versions: conflict.versions, constraints: conflict.constraints, resolution: conflict.resolution, })), }; return { content: [ { type: 'text', text: JSON.stringify(formattedConflicts, null, 2), }, ], }; } case 'suggest_alternatives': { const { packageName, packageManager } = SuggestAlternativesSchema.parse(args); logger.info(`Suggesting alternatives for package: ${packageName}`); const alternatives = await dependencyAnalyzer.suggestAlternatives(packageName, packageManager); const formattedAlternatives = { packageName, packageManager: packageManager || 'auto-detected', alternativesFound: alternatives.length, alternatives: alternatives.map(alt => ({ name: alt.name, description: alt.description, packageManager: alt.packageManager, downloads: alt.downloads, stars: alt.stars, lastUpdated: alt.lastUpdated, score: alt.score, features: alt.features, })), }; return { content: [ { type: 'text', text: JSON.stringify(formattedAlternatives, null, 2), }, ], }; } case 'security_audit': { const { projectPath, severity } = SecurityAuditSchema.parse(args); logger.info(`Performing security audit for project: ${projectPath} (severity: ${severity})`); const auditResult = await dependencyAnalyzer.securityAudit(projectPath, severity); const formattedAudit = { projectPath, severity, audits: auditResult.audits.map((audit: any) => ({ package: audit.package, version: audit.version, score: audit.score, vulnerabilities: audit.vulnerabilities, })), report: auditResult.report, }; return { content: [ { type: 'text', text: JSON.stringify(formattedAudit, null, 2), }, ], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { logger.error(`Error executing tool ${name}:`, error); return { content: [ { type: 'text', text: JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error', tool: name, }), }, ], isError: true, }; } }); // Start the server async function main() { logger.info('Starting Dependency Analysis MCP Server...'); const transport = new StdioServerTransport(); await server.connect(transport); logger.info('Dependency Analysis MCP Server started successfully'); } main().catch((error) => { logger.error('Failed to start server:', error); process.exit(1); });

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/cbunting99/mcp-code-analysis-server'

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