@cyanheads/toolkit-mcp-server
Version:
MCP server providing system, network, geolocation, generator, datetime, and security tools
172 lines (171 loc) • 6.63 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { systemTools } from './tools/system.js';
import { networkTools } from './tools/network.js';
import { geoTools } from './tools/geo.js';
import { generatorTools } from './tools/generator.js';
import { dateTimeTools } from './tools/datetime.js';
import { securityTools } from './tools/security.js';
import { McpToolError, handleToolError } from './utils/errors.js';
import { systemRateLimiter, networkRateLimiter, geoRateLimiter } from './utils/rate-limiter.js';
import { withProgress } from './utils/progress.js';
const allTools = {
...systemTools,
...networkTools,
...geoTools,
...generatorTools,
...dateTimeTools,
...securityTools
};
class ToolkitServer {
server;
isShuttingDown = false;
constructor() {
this.server = new Server({
name: 'toolkit-mcp-server',
version: '1.0.0',
}, {
capabilities: {
tools: {},
progress: {}
}
});
this.setupHandlers();
this.setupErrorHandling();
this.setupCleanup();
}
setupErrorHandling() {
this.server.onerror = (error) => {
console.error('[MCP Error]', error);
if (!this.isShuttingDown) {
// Attempt to notify clients of the error
this.server.notification({
method: 'notifications/server/error',
params: {
error: error instanceof Error ? error.message : 'Unknown error occurred'
}
}).catch(console.error);
}
};
}
setupCleanup() {
const cleanup = async () => {
this.isShuttingDown = true;
console.log('Shutting down toolkit-mcp-server...');
try {
// Notify clients of shutdown
await this.server.notification({
method: 'notifications/server/shutdown',
params: {
reason: 'Server is shutting down'
}
});
// Close server connection
await this.server.close();
console.log('Server shutdown complete');
process.exit(0);
}
catch (error) {
console.error('Error during shutdown:', error);
process.exit(1);
}
};
// Handle termination signals
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
process.on('uncaughtException', (error) => {
console.error('Uncaught exception:', error);
cleanup().catch(console.error);
});
}
setupHandlers() {
// Handle tool listing
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
try {
return {
tools: Object.entries(allTools).map(([name, tool]) => ({
name,
description: tool.description,
inputSchema: tool.inputSchema
}))
};
}
catch (error) {
throw new McpToolError(ErrorCode.InternalError, 'Failed to list tools', error instanceof Error ? error.message : undefined);
}
});
// Handle tool execution
this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
try {
const tool = allTools[request.params.name];
if (!tool) {
throw new McpToolError(ErrorCode.MethodNotFound, `Tool not found: ${request.params.name}`);
}
// Get appropriate rate limiter based on tool category
let rateLimiter;
if (request.params.name.startsWith('get_system')) {
rateLimiter = systemRateLimiter;
}
else if (request.params.name.startsWith('get_network') ||
request.params.name === 'ping_host' ||
request.params.name === 'traceroute') {
rateLimiter = networkRateLimiter;
}
else if (request.params.name === 'geolocate') {
rateLimiter = geoRateLimiter;
}
else {
rateLimiter = systemRateLimiter; // default to system rate limiter
}
// Execute tool with rate limiting and progress reporting
const result = await rateLimiter.withRateLimit(request.params.name, async () => {
return await withProgress(this.server, {
title: `Executing ${request.params.name}`,
unit: 'operations'
}, async (progress) => {
const toolResult = await tool.handler(request.params.arguments, progress);
await progress.complete();
return toolResult;
});
});
// Convert ToolResponse to ServerResult format
return {
content: result.content,
_meta: result.isError ? { isError: true } : undefined
};
}
catch (error) {
if (error instanceof McpToolError) {
throw error;
}
const errorResult = handleToolError(error);
return {
content: errorResult.content,
_meta: { isError: true }
};
}
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Toolkit MCP server running on stdio');
// Handle process termination
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
process.on('SIGTERM', async () => {
await this.server.close();
process.exit(0);
});
}
}
// Start the server
const server = new ToolkitServer();
server.run().catch((error) => {
console.error('Failed to start server:', error);
process.exit(1);
});