deepsource-mcp-server
Version:
Model Context Protocol server for DeepSource
193 lines • 6.53 kB
JavaScript
/**
* @fileoverview MCP Server module for DeepSource integration
*
* This module provides a configurable MCP server that can be used
* to integrate DeepSource functionality with Model Context Protocol.
* It separates the server setup logic from the main entry point,
* allowing for better testability and reusability.
*
* @packageDocumentation
*/
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { createLogger } from '../utils/logging/logger.js';
import { ToolRegistry } from './tool-registry.js';
import { createDefaultHandlerDeps } from '../handlers/base/handler.factory.js';
import { registerDeepSourceTools } from './tool-registration.js';
import { VERSION } from '../version.js';
const logger = createLogger('MCPServer');
/**
* Default configuration values
*/
const DEFAULT_CONFIG = {
name: 'deepsource-mcp-server',
version: VERSION,
autoRegisterTools: true,
autoStart: false,
};
/**
* DeepSource MCP Server class
*
* This class encapsulates the MCP server setup and configuration,
* providing a clean API for creating and managing the server.
*/
export class DeepSourceMCPServer {
mcpServer;
toolRegistry;
transport;
config;
isConnected = false;
constructor(config = {}) {
this.config = { ...DEFAULT_CONFIG, ...config };
logger.info('Initializing DeepSource MCP Server', {
name: this.config.name,
version: this.config.version,
});
// Initialize MCP server
this.mcpServer = new McpServer({
name: this.config.name,
version: this.config.version,
});
// Set transport FIRST (default to stdio if not provided)
// This must be set before registering tools
this.transport = this.config.transport || new StdioServerTransport();
// Initialize tool registry
const handlerDeps = this.config.handlerDeps || createDefaultHandlerDeps();
this.toolRegistry = new ToolRegistry(this.mcpServer, handlerDeps);
// Auto-register tools if configured (AFTER transport is set)
if (this.config.autoRegisterTools) {
this.registerDefaultTools();
}
}
/**
* Registers the default DeepSource tools
*/
registerDefaultTools() {
try {
logger.info('Starting registration of default DeepSource tools', {
mcpServerType: typeof this.mcpServer,
mcpServerExists: Boolean(this.mcpServer),
toolRegistryExists: Boolean(this.toolRegistry),
});
registerDeepSourceTools(this.toolRegistry);
const registeredTools = this.toolRegistry.getToolNames();
logger.info('Successfully registered DeepSource tools', {
registeredTools,
toolCount: registeredTools.length,
});
// Verify tools are actually registered with the MCP server
// The MCP server doesn't expose a direct way to query tools,
// but we can log what we've registered
logger.info('Tool registration verification', {
toolRegistryCount: registeredTools.length,
mcpServerConnected: this.isConnected,
transportSet: Boolean(this.transport),
});
}
catch (error) {
logger.error('Failed to register DeepSource tools', {
error,
message: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
throw error;
}
}
/**
* Gets the MCP server instance
*/
getMcpServer() {
return this.mcpServer;
}
/**
* Gets the tool registry
*/
getToolRegistry() {
return this.toolRegistry;
}
/**
* Connects the server to the transport
*
* @param transport - Optional transport to use (overrides constructor transport)
*/
async connect(transport) {
if (this.isConnected) {
logger.warn('Server is already connected');
return;
}
const transportToUse = transport || this.transport || new StdioServerTransport();
logger.info('Connecting MCP server to transport');
await this.mcpServer.connect(transportToUse);
this.isConnected = true;
logger.info('MCP server connected successfully');
}
/**
* Starts the server (convenience method that creates transport and connects)
*/
async start() {
if (!this.transport) {
this.transport = new StdioServerTransport();
}
await this.connect();
}
/**
* Checks if the server is connected
*/
isServerConnected() {
return this.isConnected;
}
/**
* Updates handler dependencies
*
* @param deps - New handler dependencies
*/
updateHandlerDeps(deps) {
this.toolRegistry.updateDefaultDeps(deps);
logger.info('Handler dependencies updated');
}
/**
* Gets registered tool names
*/
getRegisteredTools() {
return this.toolRegistry.getToolNames();
}
/**
* Discovers and loads tools from filesystem (requires FEATURE_TOOL_DISCOVERY)
*
* @param options - Discovery options
* @returns Array of discovered tool names
*/
async discoverTools(options) {
logger.info('Starting tool discovery from DeepSourceMCPServer');
return this.toolRegistry.discoverTools(options);
}
/**
* Gets enhanced tool information including metadata
*/
getToolsInfo() {
return this.toolRegistry.getToolsInfo();
}
/**
* Creates and optionally starts a DeepSource MCP server
*
* @param config - Server configuration
* @returns The created server instance
*/
static async create(config = {}) {
const server = new DeepSourceMCPServer(config);
if (config.autoStart) {
await server.start();
}
return server;
}
}
/**
* Convenience function to create a server with default configuration
*
* @param autoStart - Whether to start the server immediately
* @returns The created server instance
*/
export async function createDeepSourceMCPServer(autoStart = false) {
return DeepSourceMCPServer.create({ autoStart });
}
//# sourceMappingURL=mcp-server.js.map