sonatype-mcp
Version:
Model Context Protocol server for Sonatype Nexus Repository Manager
134 lines (133 loc) • 4.94 kB
JavaScript
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 { createConfig } from './config/environment.js';
import { NexusClient } from './services/nexus-client.js';
import { createTools, getToolByName } from './tools/index.js';
import { formatMCPError } from './utils/errors.js';
/**
* Main MCP server for Nexus Repository Manager
*/
class NexusMCPServer {
server;
nexusClient = null;
tools = [];
config = null;
constructor() {
// Initialize server with default values, config will be loaded later
this.server = new Server({
name: 'mcp-sonatype',
version: '1.0.3',
}, {
capabilities: {
tools: {},
},
});
}
initializeWithConfig() {
// Load configuration
this.config = createConfig();
// Initialize Nexus client
this.nexusClient = new NexusClient(this.config);
this.tools = createTools(this.nexusClient, this.config);
this.setupHandlers();
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: this.tools.map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
})),
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const tool = getToolByName(this.tools, name);
if (!tool) {
throw new Error(`Tool not found: ${name}`);
}
try {
console.error(`Executing tool: ${name}`);
const result = await tool.handler(args || {});
console.error(`Tool execution completed: ${name}`);
return result;
}
catch (error) {
console.error(`Tool execution failed: ${name}`, error);
const mcpError = formatMCPError(error);
return {
content: [
{
type: 'text',
text: `Error executing ${name}: ${mcpError.message}`
}
],
isError: true
};
}
});
}
async start() {
try {
console.error('Starting Nexus MCP Server...');
// Initialize configuration and components
this.initializeWithConfig();
if (!this.config || !this.nexusClient) {
throw new Error('Failed to initialize server configuration');
}
console.error(`Server: ${this.config.server.name} v${this.config.server.version}`);
console.error(`Nexus URL: ${this.config.nexus.baseUrl}`);
console.error(`Read-only mode: ${this.config.server.readOnly}`);
console.error(`Available tools: ${this.tools.length}`);
// Test connection to Nexus
console.error('Testing connection to Nexus...');
const isConnected = await this.nexusClient.testConnection();
if (!isConnected) {
console.warn('Warning: Could not connect to Nexus server');
}
else {
console.error('Successfully connected to Nexus');
}
// Start the server
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Nexus MCP Server started successfully');
}
catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
async stop() {
try {
console.error('Stopping Nexus MCP Server...');
await this.server.close();
console.error('Server stopped');
}
catch (error) {
console.error('Error stopping server:', error);
}
}
}
// Handle process signals
process.on('SIGINT', async () => {
console.error('\nReceived SIGINT, shutting down gracefully...');
process.exit(0);
});
process.on('SIGTERM', async () => {
console.error('\nReceived SIGTERM, shutting down gracefully...');
process.exit(0);
});
// Start the server if this file is run directly
if (import.meta.url === `file://${process.argv[1]}`) {
const server = new NexusMCPServer();
server.start().catch((error) => {
console.error('Failed to start server:', error);
process.exit(1);
});
}