@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
JavaScript
"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