Skip to main content
Glama
index.ts3.76 kB
import { createSpinner } from "nanospinner"; import { validatePackage } from "./actions/validatePackage"; import { cloneRepo } from "./actions/cloneRepo"; import { initializePackage } from "./actions/initializePackage"; import { join } from "path"; import { deletePackage } from "../remove/actions/deletePackage"; import { getPackagePath, getInstalledPath } from "@/helpers/paths"; import { readConfig, writeConfig } from "@/helpers/config"; import { resolveFromUserData } from "@/helpers/paths"; export const addPackage = async (mcpName: string) => { const spinner = createSpinner(`[${mcpName}] Installing`); let exitCode = 0; try { spinner.start(); const result = await validatePackage(mcpName); if (result.isInstalled) { let alias: string | undefined = result.alias || undefined; return spinner.warn( `[${mcpName}] Already installed\n \x1b[2mTo uninstall, use: furi remove ${alias}\x1b[0m` ); } if (!result.isValid) return spinner.error(`[${mcpName}] Could not find repo`); await cloneRepo(result.packageUrl); const response = await initializePackage(mcpName, spinner); if (!response.success) { spinner.warn(`Failed to build\n \x1b[2m${response.message}\x1b[0m`); // Write the prompt to stdout process.stdout.write( `\n[${mcpName}] Do you want to keep the repo? (y/n) ` ); // Read user input from stdin let input = ""; for await (const line of console) { input = line; break; } if (input.trim().toLowerCase() !== "y") { // Delete the package directory if the build failed await deletePackage(mcpName); spinner.error(`[${mcpName}] Failed to install`); return; } spinner.warn(`[${mcpName}] Failed to build but downloaded`); // Extract owner and repo name safely const parts = mcpName.split("/"); const owner = parts[0] || ""; const repo = parts[1] || ""; // Use the installed path if we can't get owner and repo const packagePath = owner && repo ? getPackagePath(owner, repo) : join(getInstalledPath(), mcpName); // Update configuration.json to register the package even though build failed try { const config = readConfig(); if (!config.installed) { config.installed = {}; } const socketPath = resolveFromUserData( `/transport/furi_${mcpName.replace("/", "-")}.sock` ); // Add the package to configuration with a note that it needs manual setup config.installed[mcpName] = { run: null, // No run command since build failed source: packagePath, socketPath: socketPath, originalRun: null, transportWrapper: false, }; writeConfig(config); console.log( ` \x1b[2mYou can edit the package in ${packagePath}\x1b[0m` ); console.log( ` \x1b[2mPackage registered in configuration but requires manual setup\x1b[0m` ); } catch (error) { console.error( ` \x1b[31mFailed to update configuration: ${ error instanceof Error ? error.message : String(error) }\x1b[0m` ); } return; } return spinner.success(`[${mcpName}] Installed`); } catch (error) { exitCode = 1; return spinner.error(`[${mcpName}] Failed to install`); } finally { spinner.stop(); if (exitCode !== 0) { // Optionally, if you need to ensure a non-zero exit code for scripting when errors occur: // process.exitCode = exitCode; // This sets the exit code for when Bun exits naturally } } };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ashwwwin/furi'

If you have feedback or need assistance with the MCP directory API, please join our Discord server