UNPKG

jaegis-npm-mcp-server

Version:

NPM Package Management MCP Server for JAEGIS-web-os project with 8 specialized tools

613 lines (604 loc) • 25 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js"); const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js"); const types_js_1 = require("@modelcontextprotocol/sdk/types.js"); const dotenv = __importStar(require("dotenv")); // Using built-in fetch (Node.js 18+) for better compatibility // Load environment variables dotenv.config(); // Command line argument parsing const args = process.argv.slice(2); const hasListTools = args.includes('--list-tools'); const hasToolsJson = args.includes('--tools-json'); const hasHelp = args.includes('--help') || args.includes('-h'); const formatTable = args.includes('--format=table'); // Security: Credential sanitization function sanitizeCredential(value) { if (!value || value.length < 8) return '****'; return `${value.substring(0, 4)}****...****${value.substring(value.length - 4)}`; } function sanitizeEnvVars(env) { const sensitiveKeys = ['TOKEN', 'KEY', 'SECRET', 'PASSWORD', 'API_']; const sanitized = { ...env }; Object.keys(sanitized).forEach(key => { if (sensitiveKeys.some(sensitive => key.toUpperCase().includes(sensitive))) { sanitized[key] = sanitizeCredential(sanitized[key]); } }); return sanitized; } function showHelp() { console.log(` NPM JAEGIS MCP Server v1.0.0 - NPM package management with 8 specialized tools USAGE: npm-mcp-server [OPTIONS] OPTIONS: --list-tools List all available tools with descriptions --tools-json Output complete MCP tools schema as JSON --format=table Use table format for tool listings (default: JSON) --help, -h Show this help message ENVIRONMENT VARIABLES: NPM_TOKEN NPM access token (required) Format: npm_* Generate at: https://www.npmjs.com/settings/tokens NPM_USERNAME NPM username (required) NPM_EMAIL NPM email (required) NPM_REGISTRY NPM registry URL (optional, default: https://registry.npmjs.org/) DEFAULT_PACKAGE Default package name (optional, default: JAEGIS-web-os) EXAMPLES: # List all tools in table format npm-mcp-server --list-tools --format=table # Get tools schema for MCP client integration npm-mcp-server --tools-json # Start the MCP server (default) npm-mcp-server QUICK SETUP: 1. Generate NPM token: https://www.npmjs.com/settings/tokens 2. Set environment variables: export NPM_TOKEN=npm_your_token_here export NPM_USERNAME=your_username export NPM_EMAIL=your_email@example.com 3. Run: npm-mcp-server For detailed documentation, see: README.md `); } function getToolsInfo() { return [ { name: 'npm_package_info', category: 'Package Information', description: 'Get detailed information about an NPM package including metadata and dependencies', requiredParams: ['package_name'], optionalParams: ['version'], inputSchema: { type: 'object', properties: { package_name: { type: 'string' } } } }, { name: 'npm_search_packages', category: 'Package Discovery', description: 'Search for NPM packages using keywords and filters', requiredParams: ['query'], optionalParams: ['limit'], inputSchema: { type: 'object', properties: { query: { type: 'string' } } } }, { name: 'npm_publish_package', category: 'Package Publishing', description: 'Publish a package to NPM registry with specified configuration', requiredParams: ['package_path'], optionalParams: ['tag', 'access'], inputSchema: { type: 'object', properties: { package_path: { type: 'string' } } } }, { name: 'npm_unpublish_package', category: 'Package Management', description: 'Unpublish a package version from NPM registry (irreversible)', requiredParams: ['package_name'], optionalParams: ['version'], inputSchema: { type: 'object', properties: { package_name: { type: 'string' } } } }, { name: 'npm_deprecate_package', category: 'Package Management', description: 'Deprecate a package version with a custom message', requiredParams: ['package_name', 'version', 'message'], optionalParams: [], inputSchema: { type: 'object', properties: { package_name: { type: 'string' }, version: { type: 'string' }, message: { type: 'string' } } } }, { name: 'npm_list_versions', category: 'Package Information', description: 'List all available versions of a package with release information', requiredParams: ['package_name'], optionalParams: [], inputSchema: { type: 'object', properties: { package_name: { type: 'string' } } } }, { name: 'npm_download_stats', category: 'Package Analytics', description: 'Get download statistics and analytics for a package', requiredParams: ['package_name'], optionalParams: ['period'], inputSchema: { type: 'object', properties: { package_name: { type: 'string' } } } }, { name: 'npm_validate_package', category: 'Package Validation', description: 'Validate package.json and check for publishing readiness', requiredParams: ['package_path'], optionalParams: [], inputSchema: { type: 'object', properties: { package_path: { type: 'string' } } } } ]; } function displayToolsTable(tools) { console.log('\nšŸ“¦ NPM JAEGIS MCP Server - Tool Inventory\n'); console.log('ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”'); console.log('│ Tool Name │ Category │ Required │ Optional │'); console.log('ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤'); tools.forEach(tool => { const name = tool.name.padEnd(35); const category = tool.category.padEnd(32); const required = tool.requiredParams.length.toString().padEnd(8); const optional = tool.optionalParams.length.toString().padEnd(8); console.log(`│ ${name} │ ${category} │ ${required} │ ${optional} │`); }); console.log('ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜'); // Summary by category const categories = tools.reduce((acc, tool) => { acc[tool.category] = (acc[tool.category] || 0) + 1; return acc; }, {}); console.log('\nšŸ“‹ Tool Summary by Category:'); Object.entries(categories).forEach(([category, count]) => { console.log(` • ${category}: ${count} tools`); }); console.log(`\nšŸŽÆ Total: ${tools.length} tools available\n`); } function displayToolsJson(tools, includeSchema = false) { const output = { server: 'npm-jaegis-mcp-server', version: '1.0.0', totalTools: tools.length, categories: tools.reduce((acc, tool) => { acc[tool.category] = (acc[tool.category] || 0) + 1; return acc; }, {}), tools: tools.map(tool => ({ name: tool.name, category: tool.category, description: tool.description, parameters: { required: tool.requiredParams, optional: tool.optionalParams, total: tool.requiredParams.length + tool.optionalParams.length }, ...(includeSchema && { inputSchema: tool.inputSchema }) })) }; console.log(JSON.stringify(output, null, 2)); } // Handle command line arguments before server initialization if (hasHelp) { showHelp(); process.exit(0); } if (hasListTools || hasToolsJson) { const tools = getToolsInfo(); if (hasToolsJson) { displayToolsJson(tools, true); } else if (formatTable) { displayToolsTable(tools); } else { displayToolsJson(tools, false); } process.exit(0); } class NPMJAEGISMCPServer { server; config; constructor() { this.config = this.loadConfig(); this.validateConfiguration(); this.server = new index_js_1.Server({ name: 'npm-jaegis-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, }); this.setupToolHandlers(); this.setupErrorHandling(); } loadConfig() { const token = process.env.NPM_TOKEN; const username = process.env.NPM_USERNAME; const email = process.env.NPM_EMAIL; if (!token) { throw new Error(`NPM token is required. Please set NPM_TOKEN environment variable. Generate a token at: https://www.npmjs.com/settings/tokens`); } if (!username) { throw new Error('NPM username is required. Please set NPM_USERNAME environment variable.'); } if (!email) { throw new Error('NPM email is required. Please set NPM_EMAIL environment variable.'); } return { token, username, email, registry: process.env.NPM_REGISTRY || 'https://registry.npmjs.org/', scope: process.env.NPM_SCOPE, defaultPackage: process.env.DEFAULT_PACKAGE || 'JAEGIS-web-os' }; } validateConfiguration() { if (!this.config.token.startsWith('npm_')) { console.warn('Warning: NPM token format may be invalid. Expected format: npm_*'); } console.log(`NPM MCP Server configured for user: ${this.config.username}`); console.log(`Registry: ${this.config.registry}`); console.log(`Default package: ${this.config.defaultPackage}`); } setupToolHandlers() { this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => { return { tools: [ { name: 'npm_package_info', description: 'Get detailed information about an NPM package', inputSchema: { type: 'object', properties: { package_name: { type: 'string', description: 'Name of the NPM package' }, version: { type: 'string', description: 'Specific version (optional, defaults to latest)' } }, required: ['package_name'] } }, { name: 'npm_search_packages', description: 'Search for NPM packages', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query' }, limit: { type: 'number', description: 'Maximum number of results (default: 20)' } }, required: ['query'] } }, { name: 'npm_publish_package', description: 'Publish a package to NPM registry', inputSchema: { type: 'object', properties: { package_path: { type: 'string', description: 'Path to package directory containing package.json' }, tag: { type: 'string', description: 'Distribution tag (default: latest)' }, access: { type: 'string', enum: ['public', 'restricted'], description: 'Package access level (default: public)' } }, required: ['package_path'] } }, { name: 'npm_unpublish_package', description: 'Unpublish a package version from NPM', inputSchema: { type: 'object', properties: { package_name: { type: 'string', description: 'Name of the package to unpublish' }, version: { type: 'string', description: 'Specific version to unpublish (optional, unpublishes entire package if not specified)' } }, required: ['package_name'] } }, { name: 'npm_deprecate_package', description: 'Deprecate a package version', inputSchema: { type: 'object', properties: { package_name: { type: 'string', description: 'Name of the package' }, version: { type: 'string', description: 'Version range to deprecate' }, message: { type: 'string', description: 'Deprecation message' } }, required: ['package_name', 'version', 'message'] } }, { name: 'npm_list_versions', description: 'List all versions of a package', inputSchema: { type: 'object', properties: { package_name: { type: 'string', description: 'Name of the package' } }, required: ['package_name'] } }, { name: 'npm_download_stats', description: 'Get download statistics for a package', inputSchema: { type: 'object', properties: { package_name: { type: 'string', description: 'Name of the package' }, period: { type: 'string', enum: ['last-day', 'last-week', 'last-month', 'last-year'], description: 'Time period for stats (default: last-month)' } }, required: ['package_name'] } }, { name: 'npm_validate_package', description: 'Validate package.json and check for publishing readiness', inputSchema: { type: 'object', properties: { package_path: { type: 'string', description: 'Path to package directory' } }, required: ['package_path'] } } ] }; }); this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'npm_package_info': return await this.getPackageInfo(args); case 'npm_search_packages': return await this.searchPackages(args); case 'npm_publish_package': return await this.publishPackage(args); case 'npm_unpublish_package': return await this.unpublishPackage(args); case 'npm_deprecate_package': return await this.deprecatePackage(args); case 'npm_list_versions': return await this.listVersions(args); case 'npm_download_stats': return await this.getDownloadStats(args); case 'npm_validate_package': return await this.validatePackage(args); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ error: error instanceof Error ? error.message : String(error), success: false }, null, 2) } ] }; } }); } setupErrorHandling() { this.server.onerror = (error) => { console.error('[NPM MCP Server Error]', error); }; process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } // Tool implementations will be added in the next part async getPackageInfo(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'Package info functionality will be implemented' } ] }; } async searchPackages(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'Search packages functionality will be implemented' } ] }; } async publishPackage(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'Publish package functionality will be implemented' } ] }; } async unpublishPackage(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'Unpublish package functionality will be implemented' } ] }; } async deprecatePackage(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'Deprecate package functionality will be implemented' } ] }; } async listVersions(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'List versions functionality will be implemented' } ] }; } async getDownloadStats(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'Download stats functionality will be implemented' } ] }; } async validatePackage(args) { // Implementation placeholder return { content: [ { type: 'text', text: 'Validate package functionality will be implemented' } ] }; } async run() { const transport = new stdio_js_1.StdioServerTransport(); await this.server.connect(transport); // Display startup summary const tools = getToolsInfo(); const categories = tools.reduce((acc, tool) => { acc[tool.category] = (acc[tool.category] || 0) + 1; return acc; }, {}); console.error('šŸ“¦ NPM JAEGIS MCP Server (v1.0.0) running on stdio'); console.error(`šŸ“Š Total Tools: ${tools.length} | Categories: ${Object.keys(categories).length}`); console.error(`šŸ”§ Configured for user: ${sanitizeCredential(this.config.username)}`); console.error(`🌐 Registry: ${this.config.registry}`); console.error('āœ… Server ready with NPM package management tools'); console.error('šŸ’” Use --list-tools to see all available tools'); } } // Run the server if (require.main === module) { try { const server = new NPMJAEGISMCPServer(); server.run().catch((error) => { console.error('Failed to start NPM JAEGIS MCP Server:', error.message); process.exit(1); }); } catch (error) { console.error('Failed to initialize NPM JAEGIS MCP Server:'); console.error(error instanceof Error ? error.message : String(error)); process.exit(1); } } //# sourceMappingURL=index.js.map