Skip to main content
Glama
tool-registration.ts14 kB
/** * @fileoverview Tool registration module for DeepSource MCP tools * * This module handles the registration of all DeepSource tools with the * MCP server. It centralizes tool registration logic and provides a * clean interface for registering tools. * * @packageDocumentation */ import { ToolRegistry, ToolDefinition } from './tool-registry.js'; import { toolSchemas } from './tool-definitions.js'; import { handleProjects, handleDeepsourceQualityMetrics, handleDeepsourceUpdateMetricThreshold, handleDeepsourceUpdateMetricSetting, handleDeepsourceComplianceReport, handleDeepsourceProjectIssues, handleDeepsourceProjectRuns, handleDeepsourceRun, handleDeepsourceRecentRunIssues, handleDeepsourceDependencyVulnerabilities, } from '../handlers/index.js'; import { DeepsourceRunParams } from '../handlers/run.js'; import { DeepsourceRecentRunIssuesParams } from '../handlers/recent-run-issues.js'; import { DeepsourceDependencyVulnerabilitiesParams } from '../handlers/dependency-vulnerabilities.js'; import { MetricKey } from '../types/metrics.js'; import { AnalyzerShortcode } from '../types/branded.js'; import { MetricShortcode } from '../models/metrics.js'; import { ReportType } from '../types/report-types.js'; import { createLogger } from '../utils/logging/logger.js'; const logger = createLogger('ToolRegistration'); /** * Handler mapping for tool schemas */ const TOOL_HANDLERS: Record<string, (params: unknown) => Promise<unknown>> = { projects: async (params: unknown) => { logger.info('=== PROJECTS HANDLER START ==='); logger.info('Projects handler called with params:', { params, type: typeof params }); try { // Params currently unused but may be used for future filtering const result = await handleProjects(); logger.info('=== PROJECTS HANDLER SUCCESS ===', { result }); return result; } catch (error) { logger.error('=== PROJECTS HANDLER ERROR ===', { error, message: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, }); throw error; } }, quality_metrics: async (params: unknown) => { const typedParams = params as Record<string, unknown>; const metricsParams: { projectKey: string; shortcodeIn?: MetricShortcode[] } = { projectKey: typedParams.projectKey as string, }; const shortcodeIn = typedParams.shortcodeIn as MetricShortcode[] | undefined; if (shortcodeIn) { metricsParams.shortcodeIn = shortcodeIn; } return handleDeepsourceQualityMetrics(metricsParams); }, update_metric_threshold: async (params: unknown) => { const typedParams = params as Record<string, unknown>; const thresholdParams: { projectKey: string; repositoryId: string; metricShortcode: MetricShortcode; metricKey: MetricKey; thresholdValue?: number | null; } = { projectKey: typedParams.projectKey as string, repositoryId: typedParams.repositoryId as string, metricShortcode: typedParams.metricShortcode as MetricShortcode, metricKey: typedParams.metricKey as MetricKey, }; const thresholdValue = typedParams.thresholdValue as number | null | undefined; if (thresholdValue !== undefined) { thresholdParams.thresholdValue = thresholdValue; } return handleDeepsourceUpdateMetricThreshold(thresholdParams); }, update_metric_setting: async (params: unknown) => { const typedParams = params as Record<string, unknown>; return handleDeepsourceUpdateMetricSetting({ projectKey: typedParams.projectKey as string, repositoryId: typedParams.repositoryId as string, metricShortcode: typedParams.metricShortcode as MetricShortcode, isReported: typedParams.isReported as boolean, isThresholdEnforced: typedParams.isThresholdEnforced as boolean, }); }, compliance_report: async (params: unknown) => { const typedParams = params as Record<string, unknown>; return handleDeepsourceComplianceReport({ projectKey: typedParams.projectKey as string, reportType: typedParams.reportType as ReportType, }); }, project_issues: async (params: unknown) => { const typedParams = params as Record<string, unknown>; const issuesParams: { projectKey: string; path?: string; analyzerIn?: string[]; tags?: string[]; first?: number; last?: number; after?: string; before?: string; } = { projectKey: typedParams.projectKey as string, }; if (typeof typedParams.path === 'string') { issuesParams.path = typedParams.path; } if (Array.isArray(typedParams.analyzerIn)) { issuesParams.analyzerIn = typedParams.analyzerIn as string[]; } if (Array.isArray(typedParams.tags)) { issuesParams.tags = typedParams.tags as string[]; } if (typeof typedParams.first === 'number') { issuesParams.first = typedParams.first; } if (typeof typedParams.last === 'number') { issuesParams.last = typedParams.last; } if (typeof typedParams.after === 'string') { issuesParams.after = typedParams.after; } if (typeof typedParams.before === 'string') { issuesParams.before = typedParams.before; } return handleDeepsourceProjectIssues(issuesParams); }, 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); }, 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); }, recent_run_issues: async (params: unknown) => { const typedParams = params as Record<string, unknown>; const recentRunParams: DeepsourceRecentRunIssuesParams = { projectKey: typedParams.projectKey as string, branchName: typedParams.branchName as string, }; if (typeof typedParams.first === 'number') { recentRunParams.first = typedParams.first; } if (typeof typedParams.last === 'number') { recentRunParams.last = typedParams.last; } if (typeof typedParams.after === 'string') { recentRunParams.after = typedParams.after; } if (typeof typedParams.before === 'string') { recentRunParams.before = typedParams.before; } return handleDeepsourceRecentRunIssues(recentRunParams); }, dependency_vulnerabilities: async (params: unknown) => { const typedParams = params as Record<string, unknown>; const vulnParams: DeepsourceDependencyVulnerabilitiesParams = { projectKey: typedParams.projectKey as string, }; if (typeof typedParams.first === 'number') { vulnParams.first = typedParams.first; } if (typeof typedParams.last === 'number') { vulnParams.last = typedParams.last; } if (typeof typedParams.after === 'string') { vulnParams.after = typedParams.after; } if (typeof typedParams.before === 'string') { vulnParams.before = typedParams.before; } return handleDeepsourceDependencyVulnerabilities(vulnParams); }, }; /** * Creates a tool definition from a schema and handler * * @param schema - The tool schema * @param handler - The tool handler function * @returns The tool definition */ function createToolDefinition( schema: { name: string; description: string; inputSchema?: unknown; outputSchema?: unknown; }, handler: (_params: unknown) => Promise<unknown> ): ToolDefinition { logger.debug(`Creating tool definition for ${schema.name}`, { hasInputSchema: Boolean(schema.inputSchema), inputSchemaType: typeof schema.inputSchema, inputSchema: schema.inputSchema, }); return { name: schema.name, description: schema.description, inputSchema: schema.inputSchema, outputSchema: schema.outputSchema, handler, } as ToolDefinition; } /** * Registers all DeepSource tools with the tool registry * * @param registry - The tool registry to register tools with */ 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), }); } /** * Tool categories for organization */ export enum ToolCategory { PROJECT_MANAGEMENT = 'project_management', CODE_QUALITY = 'code_quality', SECURITY = 'security', ANALYSIS = 'analysis', DEPENDENCIES = 'dependencies', } /** * Tool metadata for categorization and filtering */ export interface ToolMetadata { category: ToolCategory; tags: string[]; requiresAuth: boolean; supportsFiltering: boolean; supportsPagination: boolean; } /** * Metadata for all DeepSource tools */ export const TOOL_METADATA: Record<string, ToolMetadata> = { projects: { category: ToolCategory.PROJECT_MANAGEMENT, tags: ['projects', 'list', 'discovery'], requiresAuth: true, supportsFiltering: false, supportsPagination: false, }, quality_metrics: { category: ToolCategory.CODE_QUALITY, tags: ['metrics', 'quality', 'code', 'statistics'], requiresAuth: true, supportsFiltering: true, supportsPagination: false, }, update_metric_threshold: { category: ToolCategory.CODE_QUALITY, tags: ['metrics', 'quality', 'threshold', 'update', 'mutation'], requiresAuth: true, supportsFiltering: false, supportsPagination: false, }, update_metric_setting: { category: ToolCategory.CODE_QUALITY, tags: ['metrics', 'quality', 'settings', 'update', 'mutation'], requiresAuth: true, supportsFiltering: false, supportsPagination: false, }, compliance_report: { category: ToolCategory.SECURITY, tags: ['compliance', 'security', 'report', 'owasp', 'sans'], requiresAuth: true, supportsFiltering: false, supportsPagination: false, }, project_issues: { category: ToolCategory.CODE_QUALITY, tags: ['issues', 'problems', 'code', 'quality', 'list'], requiresAuth: true, supportsFiltering: true, supportsPagination: true, }, runs: { category: ToolCategory.ANALYSIS, tags: ['runs', 'analysis', 'history', 'list'], requiresAuth: true, supportsFiltering: true, supportsPagination: true, }, run: { category: ToolCategory.ANALYSIS, tags: ['run', 'analysis', 'details', 'single'], requiresAuth: true, supportsFiltering: false, supportsPagination: false, }, recent_run_issues: { category: ToolCategory.ANALYSIS, tags: ['issues', 'run', 'recent', 'branch', 'analysis'], requiresAuth: true, supportsFiltering: false, supportsPagination: true, }, dependency_vulnerabilities: { category: ToolCategory.DEPENDENCIES, tags: ['dependencies', 'vulnerabilities', 'security', 'cve', 'list'], requiresAuth: true, supportsFiltering: false, supportsPagination: true, }, }; /** * Gets tools by category * * @param category - The tool category * @returns Array of tool names in the category */ export function getToolsByCategory(category: ToolCategory): string[] { return Object.entries(TOOL_METADATA) .filter(([, metadata]) => metadata.category === category) .map(([name]) => name); } /** * Gets tools by tag * * @param tag - The tag to filter by * @returns Array of tool names with the tag */ export function getToolsByTag(tag: string): string[] { return Object.entries(TOOL_METADATA) .filter(([, metadata]) => metadata.tags.includes(tag)) .map(([name]) => name); } /** * Gets paginated tools * * @returns Array of tool names that support pagination */ export function getPaginatedTools(): string[] { return Object.entries(TOOL_METADATA) .filter(([, metadata]) => metadata.supportsPagination) .map(([name]) => name); }

Implementation Reference

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