UNPKG

@aurracloud/mcp-cli

Version:

A command-line tool to install, manage, and setup MCP (Model Context Protocol) servers with Docker support

1,013 lines • 54 kB
"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 }); exports.infoCommand = infoCommand; const smithery_1 = require("../smithery"); const npm_1 = require("../npm"); const git_1 = require("../git"); const logger_1 = require("../utils/logger"); const lib_1 = require("../lib"); const cloud_sse_1 = require("../utils/cloud-sse"); const path = __importStar(require("path")); /** * Format and display tool information */ function displayTools(tools) { if (!tools || tools.length === 0) { console.log('Tools: None available'); return; } // console.log('\nTools:'); // tools.forEach((tool, index) => { // console.log(` ${index + 1}. ${tool.name}`); // if (tool.description) { // console.log(` Description: ${tool.description}`); // } // Display parameter info if available // if (tool.inputSchema.properties) { // console.log(' Parameters:'); // Object.entries(tool.inputSchema.properties).forEach(([name, schema]) => { // console.log(` - ${name}: ${(schema as any).type || 'unknown'}`); // if ((schema as any).description) { // console.log(` ${(schema as any).description}`); // } // }); // } // }); } /** * Format and display connection information */ function displayConnections(connections) { if (connections.length === 0) { console.log('Connections: None available'); return; } console.log('\nConnections:'); connections.forEach((connection, index) => { console.log(` ${index + 1}. Type: ${connection.type}`); if (connection.type === 'http') { if (connection.deploymentUrl) { console.log(` Deployment URL: ${connection.deploymentUrl}`); } else if (connection.url) { console.log(` URL: ${connection.url}`); } } else if (connection.type === 'stdio') { console.log(` Published: ${connection.published ? 'Yes' : 'No'}`); if (connection.stdioFunction) { console.log(` StdIO Function: ${connection.stdioFunction}`); } if (connection.command) { console.log(` Command: ${connection.command}`); if (connection.args && connection.args.length > 0) { console.log(` Args: ${connection.args.join(' ')}`); } } } // Display config schema information if (connection.configSchema) { console.log(` Config Schema: ${JSON.stringify(connection.configSchema)}`); if (connection.configSchema.description) { console.log(` Description: ${connection.configSchema.description}`); } if (connection.configSchema.type) { console.log(` Type: ${connection.configSchema.type}`); } if (connection.configSchema.required && connection.configSchema.required.length > 0) { console.log(` Required: ${connection.configSchema.required.join(', ')}`); } if (connection.configSchema.properties && Object.keys(connection.configSchema.properties).length > 0) { console.log(` Properties:`); Object.entries(connection.configSchema.properties).forEach(([key, prop]) => { console.log(` ${key}: ${prop.type || 'unknown'}`); }); } } }); } /** * Display MCP server configuration information */ function displayMcpConfiguration(mcpInfo) { if (mcpInfo.source === 'cloud-sse' && mcpInfo.cloudTool) { console.log('\nšŸŒ©ļø === CLOUD SSE TOOL DETECTED ==='); console.log(`šŸ“¦ Name: ${mcpInfo.cloudTool.name}`); console.log(`šŸ”– Slug: ${mcpInfo.cloudTool.slug}`); console.log(`šŸ“ Description: ${mcpInfo.cloudTool.metadata.description}`); if (mcpInfo.cloudTool.metadata.tags && mcpInfo.cloudTool.metadata.tags.length > 0) { console.log(`šŸ·ļø Tags: ${mcpInfo.cloudTool.metadata.tags.join(', ')}`); } if (mcpInfo.cloudTool.metadata.examples && mcpInfo.cloudTool.metadata.examples.length > 0) { console.log('\nšŸ’” Examples:'); mcpInfo.cloudTool.metadata.examples.forEach((example, index) => { console.log(` ${index + 1}. "${example.content}"`); }); } console.log('\nšŸ”Œ === CONNECTION CONFIGURATION ==='); console.log('Type: SSE (Server-Sent Events)'); console.log('Authentication: Required (API Key)'); console.log('Installation: Use "mcp install" command with authentication'); return; } if (!mcpInfo.hasMcpConfig || !mcpInfo.config) { console.log('\n=== MCP Server Configuration ==='); console.log('āŒ No MCP server configuration found'); console.log('This package does not appear to be an MCP server or lacks proper configuration.'); return; } const config = mcpInfo.config; const summary = (0, lib_1.createConfigSummary)(config); console.log('\nšŸŽ‰ === MCP SERVER CONFIGURATION DETECTED ==='); console.log(`šŸ“¦ Name: ${config.name}`); console.log(`šŸ”– Version: ${config.version}`); console.log(`šŸ“ Description: ${config.description}`); if (config.author) { console.log(`šŸ‘¤ Author: ${config.author}`); } if (config.license) { console.log(`āš–ļø License: ${config.license}`); } if (config.repository) { console.log(`šŸ”— Repository: ${config.repository}`); } if (config.homepage) { console.log(`šŸ  Homepage: ${config.homepage}`); } // Connection Information console.log('\nšŸ”Œ === CONNECTION CONFIGURATION ==='); console.log(`Type: ${config.connection.type.toUpperCase()}`); if (config.connection.type === 'stdio') { if (config.connection.command) { console.log(`Command: ${config.connection.command}`); } if (config.connection.args && config.connection.args.length > 0) { console.log(`Arguments: ${config.connection.args.join(' ')}`); } } else if (config.connection.type === 'http' || config.connection.type === 'sse') { if (config.connection.url) { console.log(`URL: ${config.connection.url}`); } } if (config.connection.timeout) { console.log(`Timeout: ${config.connection.timeout}ms`); } // Capabilities console.log('\nšŸš€ === CAPABILITIES ==='); const capabilities = []; if (config.capabilities.tools) capabilities.push('šŸ”§ Tools'); if (config.capabilities.resources) capabilities.push('šŸ“ Resources'); if (config.capabilities.prompts) capabilities.push('šŸ’¬ Prompts'); if (capabilities.length > 0) { capabilities.forEach(cap => console.log(` āœ“ ${cap}`)); } else { console.log(' āŒ No capabilities specified'); } // Environment Variables const envVars = (0, lib_1.extractEnvironmentVariables)(config); if (envVars.required.length > 0 || envVars.optional.length > 0) { console.log('\nšŸŒ === ENVIRONMENT VARIABLES ==='); if (envVars.required.length > 0) { console.log('\nšŸ”“ Required:'); envVars.required.forEach(envName => { const envConfig = config.environment.required[envName]; const isSensitive = envVars.sensitive.includes(envName); console.log(` • ${envName}${isSensitive ? ' šŸ”’' : ''}`); console.log(` Description: ${envConfig.description}`); if (envConfig.type) console.log(` Type: ${envConfig.type}`); if (envConfig.pattern) console.log(` Pattern: ${envConfig.pattern}`); if (envConfig.format) console.log(` Format: ${envConfig.format}`); if (envConfig.enum) console.log(` Allowed values: ${envConfig.enum.join(', ')}`); }); } if (envVars.optional.length > 0) { console.log('\n🟔 Optional:'); envVars.optional.forEach(envName => { const envConfig = config.environment.optional[envName]; const isSensitive = envVars.sensitive.includes(envName); console.log(` • ${envName}${isSensitive ? ' šŸ”’' : ''}`); console.log(` Description: ${envConfig.description}`); if (envConfig.type) console.log(` Type: ${envConfig.type}`); if (envConfig.default !== undefined) console.log(` Default: ${envConfig.default}`); if (envConfig.pattern) console.log(` Pattern: ${envConfig.pattern}`); if (envConfig.format) console.log(` Format: ${envConfig.format}`); if (envConfig.enum) console.log(` Allowed values: ${envConfig.enum.join(', ')}`); }); } if (envVars.sensitive.length > 0) { console.log(`\nšŸ”’ Sensitive variables: ${envVars.sensitive.join(', ')}`); } } // Command Line Arguments const cmdArgs = (0, lib_1.extractCommandLineArguments)(config); if (cmdArgs.required.length > 0 || cmdArgs.optional.length > 0) { console.log('\nāš™ļø === COMMAND LINE ARGUMENTS ==='); if (cmdArgs.required.length > 0) { console.log('\nšŸ”“ Required:'); cmdArgs.required.forEach(arg => { console.log(` • ${arg.name}`); console.log(` Description: ${arg.description}`); if (arg.aliases.length > 0) { console.log(` Aliases: ${arg.aliases.join(', ')}`); } }); } if (cmdArgs.optional.length > 0) { console.log('\n🟔 Optional:'); cmdArgs.optional.forEach(arg => { console.log(` • ${arg.name}`); console.log(` Description: ${arg.description}`); if (arg.default !== undefined) { console.log(` Default: ${arg.default}`); } if (arg.aliases.length > 0) { console.log(` Aliases: ${arg.aliases.join(', ')}`); } }); } } // Configuration Files const configFiles = (0, lib_1.extractConfigurationFiles)(config); if (configFiles.required.length > 0 || configFiles.optional.length > 0) { console.log('\nšŸ“„ === CONFIGURATION FILES ==='); if (configFiles.required.length > 0) { console.log('\nšŸ”“ Required:'); configFiles.required.forEach(file => { console.log(` • ${file.name}${file.sensitive ? ' šŸ”’' : ''}`); console.log(` Path: ${file.path}`); console.log(` Description: ${file.description}`); if (file.format) console.log(` Format: ${file.format}`); }); } if (configFiles.optional.length > 0) { console.log('\n🟔 Optional:'); configFiles.optional.forEach(file => { console.log(` • ${file.name}${file.sensitive ? ' šŸ”’' : ''}`); console.log(` Path: ${file.path}`); console.log(` Description: ${file.description}`); if (file.format) console.log(` Format: ${file.format}`); if (file.default) console.log(` Default: ${file.default}`); }); } } // Metadata if (config.metadata.category || (config.metadata.keywords && config.metadata.keywords.length > 0)) { console.log('\nšŸ·ļø === METADATA ==='); if (config.metadata.category) { console.log(`Category: ${config.metadata.category}`); } if (config.metadata.keywords && config.metadata.keywords.length > 0) { console.log(`Keywords: ${config.metadata.keywords.join(', ')}`); } if (config.metadata.requires_extras && config.metadata.requires_extras.length > 0) { console.log(`Required extras: ${config.metadata.requires_extras.join(', ')}`); } } // Setup Requirements Summary console.log('\nšŸ“‹ === SETUP REQUIREMENTS ==='); if (summary.requiresSetup) { console.log('āš ļø This server requires additional configuration before use:'); if (envVars.required.length > 0) { console.log(` • ${envVars.required.length} required environment variable(s)`); } if (envVars.optional.length > 0) { console.log(` • ${envVars.optional.length} optional environment variable(s)`); } if (cmdArgs.required.length > 0) { console.log(` • ${cmdArgs.required.length} required command line argument(s)`); } if (configFiles.required.length > 0) { console.log(` • ${configFiles.required.length} required configuration file(s)`); } if (summary.hasSensitiveData) { console.log(' šŸ”’ Contains sensitive configuration data'); } } else { console.log('āœ… No additional configuration required - ready to use!'); } // Validation Issues if (mcpInfo.validation && !mcpInfo.validation.valid) { console.log('\nāš ļø === CONFIGURATION VALIDATION ISSUES ==='); console.log((0, lib_1.formatValidationResults)(mcpInfo.validation)); } else if (mcpInfo.validation && mcpInfo.validation.warnings.length > 0) { console.log('\nāš ļø === CONFIGURATION WARNINGS ==='); console.log((0, lib_1.formatValidationResults)(mcpInfo.validation)); } else { console.log('\nāœ… Configuration validation: PASSED'); } console.log('\n' + '='.repeat(50)); } /** * Checks if a package has MCP configuration */ async function checkMcpConfiguration(packageName, jsonMode = false) { // First, check if it's a cloud SSE tool slug try { logger_1.logger.info(`Checking if ${packageName} is a cloud SSE tool...`); const cloudTool = await (0, cloud_sse_1.isCloudToolSlug)(packageName); if (cloudTool) { logger_1.logger.info(`Found cloud SSE tool: ${cloudTool.name}`); return { hasMcpConfig: false, // Cloud SSE tools don't use traditional MCP config source: 'cloud-sse', cloudTool }; } } catch (error) { logger_1.logger.debug(`Cloud SSE tool check failed for ${packageName}: ${error}`); // Continue to other checks if cloud tool check fails } // Second, try to check if it's a Git repository if (packageName.includes('github.com')) { try { logger_1.logger.info(`Checking if ${packageName} is a Git repository with MCP configuration...`); const gitResult = jsonMode ? await (0, git_1.checkGitRepoExistenceQuiet)(packageName, jsonMode) : await (0, git_1.checkGitRepoExistence)(packageName); if (gitResult.exists && gitResult.clonePath) { // If a specific path was provided and a server was found there if (gitResult.selectedServer && gitResult.selectedServer.packageInfo?.mcpServer) { logger_1.logger.info(`Found MCP server configuration in specified path: ${gitResult.targetPath}`); const result = (0, lib_1.parseMcpServerConfig)(gitResult.selectedServer.packageInfo); return { hasMcpConfig: true, config: result.config || undefined, validation: result.validation, source: 'git', clonePath: gitResult.clonePath }; } // If multiple MCP servers were found, display them all and let user choose if (gitResult.mcpServers && gitResult.mcpServers.length > 0) { if (gitResult.mcpServers.length === 1) { // Only one server found, use it const server = gitResult.mcpServers[0]; logger_1.logger.info(`Found MCP server configuration: ${server.name} at ${server.path}`); const result = (0, lib_1.parseMcpServerConfig)(server.packageInfo); return { hasMcpConfig: true, config: result.config || undefined, validation: result.validation, source: 'git', clonePath: gitResult.clonePath }; } else { // Multiple servers found, display information about all of them if (!jsonMode) { console.log('\nšŸŽÆ Multiple MCP servers found in this repository:'); console.log('====================================='); gitResult.mcpServers.forEach((server, index) => { console.log(`${index + 1}. ${server.name}`); console.log(` Path: ${server.path}`); console.log(` Description: ${server.packageInfo?.description || server.pythonPackageInfo?.description || 'No description'}`); console.log(` Version: ${server.packageInfo?.version || server.pythonPackageInfo?.version || 'Unknown'}`); if (server.packageInfo?.mcpServer) { console.log(` āœ… Has MCP Configuration`); } console.log(''); }); // For info command, we'll show the first server's config as an example // but indicate that there are multiple servers const firstServer = gitResult.mcpServers[0]; logger_1.logger.info(`Showing configuration for first server: ${firstServer.name}`); } const firstServer = gitResult.mcpServers[0]; const result = (0, lib_1.parseMcpServerConfig)(firstServer.packageInfo); return { hasMcpConfig: true, config: result.config || undefined, validation: result.validation, source: 'git', clonePath: gitResult.clonePath }; } } // Check if the root package.json has MCP configuration (backward compatibility) if (gitResult.packageInfo && gitResult.packageInfo.mcpServer) { logger_1.logger.info('Found MCP server configuration in root package.json'); const result = (0, lib_1.parseMcpServerConfig)(gitResult.packageInfo); return { hasMcpConfig: true, config: result.config || undefined, validation: result.validation, source: 'git', clonePath: gitResult.clonePath }; } // Try to find smithery.yaml in the repository as a fallback if (gitResult.clonePath) { logger_1.logger.info('Checking for smithery.yaml configuration...'); // Check for smithery.yaml in selected server path if available if (gitResult.selectedServer && gitResult.selectedServer.path) { const serverPath = path.join(gitResult.clonePath, gitResult.selectedServer.path); const smitheryResult = await (0, smithery_1.findAndLoadSmitheryConfig)(serverPath); if (smitheryResult.found && smitheryResult.envResult.environmentVariables) { logger_1.logger.info(`Found smithery.yaml configuration for server ${gitResult.selectedServer.name}`); // Convert smithery config to MCP format const envVarNames = Object.keys(smitheryResult.envResult.environmentVariables); const mcpEnvConfig = (0, smithery_1.convertSmitheryToMcpConfig)(smitheryResult.envResult, envVarNames); // Create a synthetic MCP config from smithery.yaml const syntheticMcpConfig = { name: gitResult.selectedServer.name, version: gitResult.selectedServer.packageInfo?.version || gitResult.selectedServer.pythonPackageInfo?.version || '1.0.0', description: gitResult.selectedServer.packageInfo?.description || gitResult.selectedServer.pythonPackageInfo?.description || `MCP server: ${gitResult.selectedServer.name}`, connection: { type: 'stdio', command: smitheryResult.envResult.command || 'node', args: smitheryResult.envResult.args || ['dist/index.js'], timeout: 30000, headers: {} }, environment: mcpEnvConfig, arguments: { required: {}, optional: {} }, files: { required: {}, optional: {} }, capabilities: { tools: false, resources: false, prompts: false }, metadata: { keywords: [], requires_extras: [] } }; return { hasMcpConfig: true, config: syntheticMcpConfig, validation: { valid: true, errors: [], warnings: [] }, source: 'git', clonePath: gitResult.clonePath }; } } // Check for smithery.yaml in repository root const smitheryResult = await (0, smithery_1.findAndLoadSmitheryConfig)(gitResult.clonePath); if (smitheryResult.found && smitheryResult.envResult.environmentVariables) { logger_1.logger.info('Found smithery.yaml configuration in repository root'); // Convert smithery config to MCP format const envVarNames = Object.keys(smitheryResult.envResult.environmentVariables); const mcpEnvConfig = (0, smithery_1.convertSmitheryToMcpConfig)(smitheryResult.envResult, envVarNames); // Create a synthetic MCP config from smithery.yaml const syntheticMcpConfig = { name: gitResult.packageInfo?.name || packageName, version: gitResult.packageInfo?.version || '1.0.0', description: gitResult.packageInfo?.description || `MCP server: ${packageName}`, connection: { type: 'stdio', command: smitheryResult.envResult.command || 'node', args: smitheryResult.envResult.args || ['dist/index.js'], timeout: 30000, headers: {} }, environment: mcpEnvConfig, arguments: { required: {}, optional: {} }, files: { required: {}, optional: {} }, capabilities: { tools: false, resources: false, prompts: false }, metadata: { keywords: [], requires_extras: [] } }; return { hasMcpConfig: true, config: syntheticMcpConfig, validation: { valid: true, errors: [], warnings: [] }, source: 'git', clonePath: gitResult.clonePath }; } } return { hasMcpConfig: false, source: 'git', clonePath: gitResult.clonePath }; } } catch (error) { logger_1.logger.warn(`Failed to check Git repository: ${error}`); } } // If not a Git repo or Git check failed, try npm try { logger_1.logger.info(`Checking npm registry for ${packageName} MCP configuration...`); const npmResult = await (0, npm_1.checkPackageExistence)(packageName); if (npmResult.exists && npmResult.packageInfo) { const packageJson = npmResult.packageInfo; // Check for MCP configuration in npm package let mcpConfigResult = { hasMcpConfig: false, source: 'npm' }; if (packageJson.mcpServer) { logger_1.logger.info('Found MCP server configuration in npm package'); const result = (0, lib_1.parseMcpServerConfig)(packageJson); mcpConfigResult = { hasMcpConfig: true, config: result.config || undefined, validation: result.validation, source: 'npm' }; } // Check for GitHub repository in npm package.json for smithery.yaml detection const githubRepo = extractGitHubRepoFromPackageInfo(npmResult.packageInfo); if (githubRepo) { logger_1.logger.info('Found GitHub repository in npm package.json, checking for smithery.yaml...'); try { const gitResult = jsonMode ? await (0, git_1.checkGitRepoExistenceQuiet)(githubRepo, jsonMode) : await (0, git_1.checkGitRepoExistence)(githubRepo); if (gitResult.exists && gitResult.clonePath) { logger_1.logger.info('Successfully cloned GitHub repository from npm package.json'); // If no MCP config was found in npm package, check for smithery.yaml in the cloned repo if (!mcpConfigResult.hasMcpConfig) { logger_1.logger.info('No MCP config in npm package, checking for smithery.yaml in cloned repository...'); const smitheryResult = await (0, smithery_1.findAndLoadSmitheryConfig)(gitResult.clonePath); if (smitheryResult.found && smitheryResult.envResult.environmentVariables) { logger_1.logger.info('Found smithery.yaml configuration in npm package\'s GitHub repository'); // Convert smithery config to MCP format const envVarNames = Object.keys(smitheryResult.envResult.environmentVariables); const mcpEnvConfig = (0, smithery_1.convertSmitheryToMcpConfig)(smitheryResult.envResult, envVarNames); // Create a synthetic MCP config from smithery.yaml const syntheticMcpConfig = { name: packageJson.name, version: packageJson.version, description: packageJson.description || `MCP server: ${packageJson.name}`, connection: { type: 'stdio', command: smitheryResult.envResult.command || 'node', args: smitheryResult.envResult.args || ['dist/index.js'], timeout: 30000, headers: {} }, environment: mcpEnvConfig, arguments: { required: {}, optional: {} }, files: { required: {}, optional: {} }, capabilities: { tools: false, resources: false, prompts: false }, metadata: { keywords: packageJson.keywords || [], requires_extras: [] } }; logger_1.logger.info(`Generated MCP configuration from smithery.yaml for npm package ${packageJson.name}`); // Update the result to indicate we found MCP config from smithery.yaml mcpConfigResult = { hasMcpConfig: true, config: syntheticMcpConfig, validation: { valid: true, errors: [], warnings: [] }, source: 'npm', clonePath: gitResult.clonePath }; } else { // Store clonePath for cleanup even if no smithery.yaml found mcpConfigResult.clonePath = gitResult.clonePath; } } else { // Store clonePath for cleanup mcpConfigResult.clonePath = gitResult.clonePath; } } } catch (error) { logger_1.logger.warn(`Failed to clone GitHub repository from npm package.json: ${error}`); } } return mcpConfigResult; } } catch (error) { logger_1.logger.warn(`Failed to check npm package: ${error}`); } return { hasMcpConfig: false, source: 'none' }; } /** * Display package information from npm registry */ function displayPackageInfo(packageInfo) { console.log('\n=== NPM Package Information ==='); console.log(`Name: ${packageInfo.name}`); console.log(`Version: ${packageInfo.version}`); if (packageInfo.description) { console.log(`Description: ${packageInfo.description}`); } if (packageInfo.author) { console.log(`Author: ${JSON.stringify(packageInfo.author)}`); } if (packageInfo.license) { console.log(`License: ${packageInfo.license}`); } if (packageInfo.homepage) { console.log(`Homepage: ${packageInfo.homepage}`); } if (packageInfo.repository) { console.log(`Repository: ${JSON.stringify(packageInfo.repository)}`); } if (packageInfo.keywords && packageInfo.keywords.length > 0) { console.log(`Keywords: ${packageInfo.keywords.join(', ')}`); } } /** * Display GitHub repository information */ function displayGitRepoInfo(gitResult) { if (!gitResult.repoInfo) return; console.log('\n=== GitHub Repository Information ==='); console.log(`Name: ${gitResult.repoInfo.name}`); console.log(`Full Name: ${gitResult.repoInfo.fullName}`); console.log(`URL: ${gitResult.repoInfo.htmlUrl}`); if (gitResult.repoInfo.description) { console.log(`Description: ${gitResult.repoInfo.description}`); } if (gitResult.repoInfo.language) { console.log(`Primary Language: ${gitResult.repoInfo.language}`); } if (gitResult.repoInfo.license) { console.log(`License: ${gitResult.repoInfo.license.name}`); } if (gitResult.repoInfo.topics && gitResult.repoInfo.topics.length > 0) { console.log(`Topics: ${gitResult.repoInfo.topics.join(', ')}`); } // Display information about the selected server (if a specific path was provided) if (gitResult.selectedServer) { console.log(`\n--- Selected MCP Server ---`); console.log(`Server Name: ${gitResult.selectedServer.name}`); console.log(`Server Path: ${gitResult.selectedServer.path}`); console.log(`Server Version: ${gitResult.selectedServer.packageInfo?.version || gitResult.selectedServer.pythonPackageInfo?.version || 'Unknown'}`); const description = gitResult.selectedServer.packageInfo?.description || gitResult.selectedServer.pythonPackageInfo?.description; if (description) { console.log(`Server Description: ${description}`); } console.log(`Executable: ${gitResult.selectedServer.isExecutable ? 'Yes' : 'No'}`); if (gitResult.selectedServer.isExecutable && gitResult.selectedServer.executableName) { console.log(`Executable Name: ${gitResult.selectedServer.executableName}`); } } // Display information about multiple MCP servers (if found) if (gitResult.mcpServers && gitResult.mcpServers.length > 0) { console.log(`\n--- MCP Servers in Repository ---`); console.log(`Total MCP Servers Found: ${gitResult.mcpServers.length}`); gitResult.mcpServers.forEach((server, index) => { console.log(`\n${index + 1}. ${server.name}`); console.log(` Path: ${server.path}`); console.log(` Description: ${server.packageInfo?.description || server.pythonPackageInfo?.description || 'No description'}`); console.log(` Version: ${server.packageInfo?.version || server.pythonPackageInfo?.version || 'Unknown'}`); if (server.packageInfo?.mcpServer) { console.log(` āœ… Has MCP Configuration`); } console.log(''); }); } // Display root package.json information (if different from selected server) if (gitResult.packageInfo && (!gitResult.selectedServer || gitResult.selectedServer.packageInfo?.name !== gitResult.packageInfo.name)) { console.log(`\n--- Root Package.json Information ---`); console.log(`Package Name: ${gitResult.packageInfo.name}`); console.log(`Package Version: ${gitResult.packageInfo.version}`); if (gitResult.packageInfo.description) { console.log(`Package Description: ${gitResult.packageInfo.description}`); } } } /** * Display executability status for any source (npm or git) */ function displayExecutabilityStatus(isExecutable, executableName, executablePath, command, source = 'npm', serverPath, serverName) { console.log('\n========================================'); console.log('PACKAGE EXECUTABILITY STATUS'); console.log('========================================'); if (isExecutable) { logger_1.logger.success(`āœ“ EXECUTABLE: Package can be run with npx`); if (serverName && serverPath) { console.log(`\nServer: ${serverName} (at ${serverPath})`); } if (command) { console.log(`\nCommand to run: ${command}`); } if (executableName && executablePath) { console.log(`Executable: ${executableName} (${executablePath})`); } if (source === 'git') { console.log('\nNote: This package is available on GitHub but not published to npm.'); console.log('You can run it directly from the GitHub repository using the command above.'); if (serverPath && serverPath !== '.') { console.log(`This is a nested server located at: ${serverPath}`); } } } else { logger_1.logger.warn(`āœ— NOT EXECUTABLE: Package cannot be run with npx`); console.log('\nThis package cannot be installed as an MCP server using standard methods.'); console.log('It may not be designed to run as a command-line tool.'); if (serverPath && serverPath !== '.') { console.log(`Note: This refers to the server at path: ${serverPath}`); } } console.log('========================================'); } /** * Extract GitHub repository information from npm package.json */ function extractGitHubRepoFromPackageInfo(packageInfo) { if (!packageInfo.repository) { return null; } let repoUrl; // Handle repository object format if (typeof packageInfo.repository === 'object' && packageInfo.repository.url) { repoUrl = packageInfo.repository.url; } else if (typeof packageInfo.repository === 'string') { repoUrl = packageInfo.repository; } else { return null; } // Clean up common prefixes and suffixes repoUrl = repoUrl .replace(/^git\+/, '') .replace(/^git:\/\//, 'https://') .replace(/\.git$/, ''); // Check if it's a GitHub URL if (repoUrl.includes('github.com')) { return repoUrl; } return null; } /** * Extract repository name from GitHub URL for Smithery lookup */ function extractRepoNameForSmitery(packageName) { // If it doesn't contain github.com, return as-is if (!packageName.includes('github.com')) { return packageName; } // Extract owner/repo from various GitHub URL formats let repoPath = packageName; // Remove protocol and domain repoPath = repoPath.replace(/^https?:\/\/github\.com\//, ''); // Remove .git suffix if present repoPath = repoPath.replace(/\.git$/, ''); // Remove trailing slash if present repoPath = repoPath.replace(/\/$/, ''); // Should now be in format: owner/repo or owner/repo/additional-path // Take only the first two parts (owner/repo) const parts = repoPath.split('/'); if (parts.length >= 2) { return `@${parts[0]}/${parts[1]}`; } // Fallback to original if parsing fails return packageName; } /** * Try to fetch Smithery information regardless of npm/git status */ async function trySmitheryLookup(packageName, jsonMode = false) { const apiToken = process.env.SMITHERY_API_TOKEN; if (!apiToken) { logger_1.logger.info('\nFor Smithery registry information, set SMITHERY_API_TOKEN environment variable.'); return { found: false }; } try { const serverDetails = await (0, smithery_1.getServerDetails)(packageName, apiToken); if (!jsonMode) { // Display the server information console.log('\n=== Smithery Registry Information ==='); console.log(`Qualified Name: ${serverDetails.qualifiedName}`); console.log(`Display Name: ${serverDetails.displayName}`); if (serverDetails.deploymentUrl) { console.log(`Deployment URL: ${serverDetails.deploymentUrl}`); } if (serverDetails.iconUrl) { console.log(`Icon URL: ${serverDetails.iconUrl}`); } // Display security information if (serverDetails.security) { console.log(`\nSecurity Scan Passed: ${serverDetails.security.scanPassed === true ? 'Yes' : serverDetails.security.scanPassed === false ? 'No' : 'Not scanned'}`); } // Display connections displayConnections(serverDetails.connections); // Display tools displayTools(serverDetails.tools); } return { found: true, serverDetails }; } catch (error) { logger_1.logger.warn(`Could not fetch Smithery registry information: ${error.message}`); return { found: false }; } } /** * Command to fetch and display comprehensive information about an MCP server from integrated registries */ async function infoCommand(options) { const packageName = options.package; const jsonMode = options.json || false; logger_1.logger.info(`Fetching information for ${packageName}...`); logger_1.logger.verbose(`JSON mode: ${jsonMode}`); logger_1.logger.debug(`Options received: ${JSON.stringify(options)}`); let foundInNpm = false; let foundInGit = false; let foundInCloudSse = false; let foundInSmitery = false; let mcpInfo = null; let npmResult = null; let gitResult = null; let smitheryResult = null; try { // Step 0: Check for MCP configuration first logger_1.logger.info('Checking for MCP server configuration...'); logger_1.logger.verbose('Starting MCP configuration check...'); mcpInfo = await checkMcpConfiguration(packageName, jsonMode); if (mcpInfo.hasMcpConfig) { logger_1.logger.success('šŸŽ‰ MCP server configuration detected!'); logger_1.logger.verbose(`MCP config source: ${mcpInfo.source}`); } else if (mcpInfo.source === 'cloud-sse') { foundInCloudSse = true; logger_1.logger.success('šŸŒ©ļø Cloud SSE tool detected!'); logger_1.logger.verbose(`Cloud tool: ${mcpInfo.cloudTool?.name}`); } // Step 1: Check npm registry logger_1.logger.info('Checking npm registry...'); logger_1.logger.verbose('Querying npm registry API...'); npmResult = await (0, npm_1.checkPackageExistence)(packageName); if (npmResult.exists) { foundInNpm = true; logger_1.logger.success(`āœ“ Found in npm registry!`); logger_1.logger.verbose(`Package version: ${npmResult.packageInfo?.version}`); logger_1.logger.debug(`Full npm result: ${JSON.stringify(npmResult, null, 2)}`); if (!jsonMode) { // Display executability status displayExecutabilityStatus(npmResult.isExecutable, npmResult.executableName, npmResult.executablePath, npmResult.isExecutable ? `npx -y ${packageName}` : undefined, 'npm'); // Display package details if (npmResult.packageInfo) { displayPackageInfo(npmResult.packageInfo); } } // Step 2: Check GitHub repository from npm package.json if (npmResult.packageInfo) { const githubRepo = extractGitHubRepoFromPackageInfo(npmResult.packageInfo); if (githubRepo) { logger_1.logger.info('Checking GitHub repository from npm package.json...'); logger_1.logger.verbose(`GitHub repo URL: ${githubRepo}`); try { gitResult = jsonMode ? await (0, git_1.checkGitRepoExistenceQuiet)(githubRepo, jsonMode) : await (0, git_1.checkGitRepoExistence)(githubRepo); if (gitResult.exists) { foundInGit = true; logger_1.logger.success(`āœ“ Found GitHub repository from npm package.json!`); logger_1.logger.verbose(`Repository name: ${gitResult.repoInfo?.name}`); if (!jsonMode) { // Display repository details displayGitRepoInfo(gitResult); } // Clean up cloned repository if (gitResult.clonePath) { (0, git_1.cleanupClonedRepo)(gitResult.clonePath, jsonMode); } } else { logger_1.logger.warn(`āœ— GitHub repository from npm package.json not accessible`); } } catch (error) { logger_1.logger.warn(`Error checking GitHub repository from npm package.json: ${error.message}`); logger_1.logger.debug(`Full error: ${error.stack}`); } } else { logger_1.logger.verbose('No GitHub repository found in npm package.json'); } } } else { logger_1.logger.warn(`āœ— Not found in npm registry`); // Step 2: Check GitHub repository as fallback logger_1.logger.info('Checking GitHub repository...'); logger_1.logger.verbose('Attempting direct GitHub repository check...'); try { gitResult = jsonMode ? await (0, git_1.checkGitRepoExistenceQuiet)(packageName, jsonMode) : await (0, git_1.checkGitRepoExistence)(packageName); if (gitResult.exists) { foundInGit = true; logger_1.logger.success(`āœ“ Found GitHub repository!`); logger_1.logger.verbose(`Repository language: ${gitResult.repoInfo?.language}`); if (!jsonMode) { // Get npx command for git repo if executable let gitCommand; if (gitResult.isExecutable) { const npxCmd = await (0, git_1.getGitNpxCommand)(packageName); if (npxCmd) { gitCommand = `${npxCmd.command} ${npxCmd.args.join(' ')}`; } } // Display executability status displayExecutabilityStatus(gitResult.isExecutable, gitResult.executableName, gitResult.executablePath, gitCommand, 'git', gitResult.selectedServer?.path || gitResult.targetPath, gitResult.selectedServer?.name || gitResult.packageInfo?.name); // Display repository details displayGitRepoInfo(gitResult); } // Clean up cloned repository if (gitResult.clonePath) { (0, git_1.cleanupClonedRepo)(gitResult.clonePath, jsonMode); } } else { logger_1.logger.warn(`āœ— Not found on GitHub`); } } catch (error) { logger_1.logger.warn(`Error checking GitHub: ${error.message}`); logger_1.logger.debug(`Full error: ${error.stack}`); } } // Display MCP configuration information if (mcpInfo && !jsonMode) { displayMcpConfiguration(mcpInfo); // Clean up cloned repository if it exists if (mcpInfo.clonePath) { (0, git_1.cleanupClonedRepo)(mcpInfo.clonePath, jsonMode); } } // Step 3: Always try Smithery registry (regardless of npm/git status) logger_1.logger.info('Checking Smithery registry...'); logger_1.logger.verbose('Querying Smithery registry API...'); const smitheryPackageName = extractRepoNameForSmitery(packageName); logger_1.logger.debug(`Smithery package name: ${smitheryPackageName}`); smitheryResult = await trySmitheryLookup(smitheryPackageName, jsonMode); foundInSmitery = smitheryResult.found; if (foundInSmitery) { logger_1.logger.success(`āœ“ Found in Smithery registry!`); logger_1.logger.verbose(`Server display name: ${smitheryResult.serverDetails?.displayName}`); } else { logger_1.logger.warn(`āœ— Not found in Smithery registry`); } // Output results if (jsonMode) { // JSON output const result = { packageName, summary: { foundInNpm, foundInGit, foundInCloudSse, foundInSmitery, hasMcpConfig: mcpInfo?.hasMcpConfig || false } }; if (npmResult?.exists) { result.npm = { found: true, packageInfo: npmResult.packageInfo, isExecutable: npmResult.isExecutable, executableNam