diff --git a/packages/package-list.json b/packages/package-list.json index 5262e2f..4d37ec1 100644 --- a/packages/package-list.json +++ b/packages/package-list.json @@ -191,7 +191,7 @@ { "name": "mcp-server-fetch", "description": "A Model Context Protocol server providing tools to fetch and convert web content for usage by LLMs", - "vendor": "Anthropic, PBC.", + "vendor": "Anthropic, PBC (https://anthropic.com)", "sourceUrl": "https://github.com/modelcontextprotocol/servers/blob/main/src/fetch", "homepage": "https://github.com/modelcontextprotocol/servers", "license": "MIT", @@ -200,7 +200,7 @@ { "name": "mcp-server-git", "description": "A Model Context Protocol server providing tools to read, search, and manipulate Git repositories programmatically via LLMs", - "vendor": "Anthropic, PBC.", + "vendor": "Anthropic, PBC (https://anthropic.com)", "sourceUrl": "https://github.com/modelcontextprotocol/servers/blob/main/src/git", "homepage": "https://github.com/modelcontextprotocol/servers", "license": "MIT", @@ -209,25 +209,25 @@ { "name": "mcp-server-sentry", "description": "MCP server for retrieving issues from sentry.io", - "vendor": "Unknown", + "vendor": "Anthropic, PBC (https://anthropic.com)", "sourceUrl": "https://github.com/modelcontextprotocol/servers/blob/main/src/sentry", "homepage": "https://github.com/modelcontextprotocol/servers", - "license": "Unknown", + "license": "MIT", "runtime": "python" }, { "name": "mcp-server-sqlite", "description": "A simple SQLite MCP server", - "vendor": "Unknown", + "vendor": "Anthropic, PBC (https://anthropic.com)", "sourceUrl": "https://github.com/modelcontextprotocol/servers/blob/main/src/sqlite", "homepage": "https://github.com/modelcontextprotocol/servers", - "license": "Unknown", + "license": "MIT", "runtime": "python" }, { "name": "mcp-server-time", "description": "A Model Context Protocol server providing tools for time queries and timezone conversions for LLMs", - "vendor": "Mariusz 'maledorak' Korzekwa", + "vendor": "Anthropic, PBC (https://anthropic.com)", "sourceUrl": "https://github.com/modelcontextprotocol/servers/blob/main/src/time", "homepage": "https://github.com/modelcontextprotocol/servers", "license": "MIT", diff --git a/src/extractors/modelcontextprotocol-extractor.ts b/src/extractors/modelcontextprotocol-extractor.ts index fa251ab..deefcd7 100644 --- a/src/extractors/modelcontextprotocol-extractor.ts +++ b/src/extractors/modelcontextprotocol-extractor.ts @@ -92,15 +92,11 @@ async function extractPythonPackage(pyprojectPath: string, repoUrl: string, subP const { project } = pyproject; - // Get the first author/maintainer for vendor info - const vendor = project.authors?.[0]?.name || - project.maintainers?.[0]?.name || - 'Unknown'; + // Set vendor to Anthropic + const vendor = 'Anthropic, PBC (https://anthropic.com)'; - // Handle license field which can be either a string or an object - const license = typeof project.license === 'string' - ? project.license - : project.license?.text || 'Unknown'; + // Set license to MIT + const license = 'MIT'; return { name: project.name || '', diff --git a/src/install.ts b/src/install.ts index a8b0864..4d4ba03 100644 --- a/src/install.ts +++ b/src/install.ts @@ -3,143 +3,44 @@ import { join } from 'path'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import { Package } from './types/index.js'; -import { installMCPServer } from './utils/config.js'; +import { installPackage as installPkg } from './utils/package-management.js'; import inquirer from 'inquirer'; -import { exec } from 'child_process'; -import { promisify } from 'util'; -import { packageHelpers } from './helpers/index.js'; import chalk from 'chalk'; -const execAsync = promisify(exec); - const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const packageListPath = join(__dirname, '../packages/package-list.json'); -async function handlePackageHelper(packageName: string): Promise | undefined> { - const helper = packageHelpers[packageName]; - if (!helper?.requiredEnvVars) return undefined; - - const envVars: Record = {}; - console.log(chalk.cyan('\nEnvironment Variable Configuration:')); - - // First check if env vars are needed and get user confirmation - console.log(chalk.yellow('\nThis package requires configuration of environment variables.')); - const { proceed } = await inquirer.prompt<{ proceed: boolean }>([{ - type: 'confirm', - name: 'proceed', - message: 'Would you like to configure them now?', - default: true - }]); - - if (!proceed) { - console.log(chalk.yellow('\nInstallation cancelled. Package requires environment configuration.')); - process.exit(0); - } - - for (const [envVar, config] of Object.entries(helper.requiredEnvVars)) { - const envConfig = config as { description: string; required: boolean; default?: string }; - const existingValue = process.env[envVar]; - - console.log(chalk.gray(`\n${envVar}:`)); - console.log(chalk.gray(`Description: ${envConfig.description}`)); - if (envConfig.default) { - console.log(chalk.gray(`Default: ${envConfig.default}`)); +async function promptForRuntime(): Promise<'node' | 'python'> { + const { runtime } = await inquirer.prompt<{ runtime: 'node' | 'python' }>([ + { + type: 'list', + name: 'runtime', + message: 'What runtime does this package use?', + choices: [ + { name: 'Node.js', value: 'node' }, + { name: 'Python', value: 'python' } + ] } - - if (existingValue) { - const { useExisting } = await inquirer.prompt<{ useExisting: boolean }>([{ - type: 'confirm', - name: 'useExisting', - message: `Found existing ${envVar} in environment. Use this value?`, - default: true - }]); - - if (useExisting) { - envVars[envVar] = existingValue; - console.log(chalk.green(`Using existing ${envVar}`)); - continue; - } - } - - const { configure } = await inquirer.prompt([{ - type: 'confirm', - name: 'configure', - message: `Would you like to configure ${envVar}${envConfig.required ? ' (required)' : ' (optional)'}?`, - default: envConfig.required - }]); - - if (configure) { - const { value } = await inquirer.prompt([{ - type: 'input', - name: 'value', - message: `Enter value for ${envVar}:`, - default: envConfig.default, - validate: (input) => { - if (envConfig.required && !input) { - return `${envVar} is required`; - } - return true; - } - }]); - - if (value) { - envVars[envVar] = value; - console.log(chalk.green(`✓ ${envVar} configured`)); - } - } else if (envConfig.required) { - console.log(chalk.yellow(`\n⚠️ Warning: ${envVar} is required but not configured. You'll need to set it manually.`)); - process.exit(0); - } - } - - return Object.keys(envVars).length > 0 ? envVars : undefined; + ]); + return runtime; } -export async function installPackage(pkg: Package | string): Promise { - try { - const packageName = typeof pkg === 'string' ? pkg : pkg.name; - - // Handle package-specific configuration and get environment variables - const env = await handlePackageHelper(packageName); - - // After successful installation, update the config with env variables - installMCPServer(packageName, env); - console.log('Updated Claude desktop configuration'); - - // Prompt user about restarting Claude - const { shouldRestart } = await inquirer.prompt<{ shouldRestart: boolean }>([ - { - type: 'confirm', - name: 'shouldRestart', - message: 'Would you like to restart the Claude desktop app to apply changes?', - default: true - } - ]); +function createUnknownPackage(packageName: string, runtime: 'node' | 'python'): Package { + return { + name: packageName, + description: 'Unverified package', + runtime, + vendor: '', + sourceUrl: '', + homepage: '', + license: '' + }; +} - if (shouldRestart) { - console.log('Restarting Claude desktop app...'); - try { - // Kill existing Claude process - await execAsync('pkill -x Claude || true'); - // Wait 2 seconds before restarting - console.log('Waiting for Claude to close...'); - await new Promise(resolve => setTimeout(resolve, 2000)); - // Start Claude again - await execAsync('open -a Claude'); - console.log('Claude desktop app has been restarted'); - } catch (error) { - console.warn('Failed to restart Claude desktop app automatically. Please restart it manually.'); - } - } else { - console.log('Please restart the Claude desktop app manually to apply changes.'); - } - - } catch (error) { - console.error('Failed to install package:', error); - throw error; - } +export async function installPackage(pkg: Package): Promise { + return installPkg(pkg); } export async function install(packageName: string): Promise { @@ -147,7 +48,7 @@ export async function install(packageName: string): Promise { const pkg = packageList.find(p => p.name === packageName); if (!pkg) { - console.warn(`Package ${packageName} not found in the curated list.`); + console.warn(chalk.yellow(`Package ${packageName} not found in the curated list.`)); const { proceedWithInstall } = await inquirer.prompt<{ proceedWithInstall: boolean }>([ { @@ -159,8 +60,14 @@ export async function install(packageName: string): Promise { ]); if (proceedWithInstall) { - console.log(`Proceeding with installation of ${packageName}...`); - await installPackage(packageName); + console.log(chalk.cyan(`Proceeding with installation of ${packageName}...`)); + + // Prompt for runtime for unverified packages + const runtime = await promptForRuntime(); + + // Create a basic package object for unverified packages + const unknownPkg = createUnknownPackage(packageName, runtime); + await installPkg(unknownPkg); } else { console.log('Installation cancelled.'); process.exit(1); @@ -168,5 +75,5 @@ export async function install(packageName: string): Promise { return; } - await installPackage(pkg); + await installPkg(pkg); } diff --git a/src/types/index.ts b/src/types/index.ts index 4c308c9..0d231d6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,11 +1,11 @@ export interface Package { name: string; description: string; + runtime: 'node' | 'python'; vendor: string; sourceUrl: string; homepage: string; license: string; - runtime: 'node' | 'python'; isInstalled?: boolean; }