Skip to main content
Glama
cli.ts6 kB
#!/usr/bin/env node import { Command } from "commander"; import open from "open"; import { createServer } from "http"; import { getApiKey, getBaseUrl, isAuthenticated, saveConfig } from "./config.js"; import { verifyApiKey } from "./api.js"; const program = new Command(); program .name("nexus-mcp") .description("MCP server for Nexus - AI-assisted Project Delivery Platform") .version("0.1.0"); program .command("login") .description("Authenticate with Nexus") .option("--no-browser", "Don't open browser automatically") .action(async (options) => { console.log("Starting authentication flow...\n"); // Create a temporary server to receive the callback const server = createServer((req, res) => { const url = new URL(req.url || "", `http://localhost`); if (url.pathname === "/callback") { const apiKey = url.searchParams.get("key"); const error = url.searchParams.get("error"); if (error) { res.writeHead(400, { "Content-Type": "text/html" }); res.end(` <html> <body style="font-family: system-ui; padding: 40px; text-align: center;"> <h1 style="color: #dc2626;">Authentication Failed</h1> <p>${error}</p> <p>You can close this window.</p> </body> </html> `); console.error(`\nAuthentication failed: ${error}`); server.close(); process.exit(1); } if (apiKey) { saveConfig({ apiKey }); res.writeHead(200, { "Content-Type": "text/html" }); res.end(` <html> <body style="font-family: system-ui; padding: 40px; text-align: center;"> <h1 style="color: #16a34a;">Authentication Successful!</h1> <p>You can close this window and return to your terminal.</p> </body> </html> `); console.log("\n✓ Authentication successful!"); console.log(" API key saved to ~/.nexus-mcp/config.json\n"); console.log("You can now use the MCP server with Claude Code:"); console.log(" claude mcp add nexus -- npx @nexus/mcp-server\n"); server.close(); process.exit(0); } } res.writeHead(404); res.end("Not found"); }); // Find an available port server.listen(0, "127.0.0.1", () => { const address = server.address(); if (!address || typeof address === "string") { console.error("Failed to start callback server"); process.exit(1); } const callbackUrl = `http://127.0.0.1:${address.port}/callback`; const baseUrl = getBaseUrl(); const authUrl = `${baseUrl}/auth/mcp?callback=${encodeURIComponent(callbackUrl)}`; console.log("Opening browser for authentication..."); console.log(`\nIf the browser doesn't open, visit:\n${authUrl}\n`); if (options.browser !== false) { open(authUrl).catch(() => { console.log("Failed to open browser automatically."); }); } console.log("Waiting for authentication..."); }); // Timeout after 5 minutes setTimeout(() => { console.error("\nAuthentication timed out."); server.close(); process.exit(1); }, 5 * 60 * 1000); }); program .command("auth") .description("Set API key manually") .requiredOption("--key <key>", "Nexus API key") .action(async (options) => { saveConfig({ apiKey: options.key }); console.log("API key saved to ~/.nexus-mcp/config.json"); try { const result = await verifyApiKey(); if (result.valid) { console.log(`\n✓ Authenticated as ${result.user?.email}`); console.log(` Organization: ${result.org?.name}\n`); } else { console.error("\n✗ Invalid API key"); process.exit(1); } } catch (error) { console.error(`\n✗ Failed to verify API key: ${error}`); process.exit(1); } }); program .command("status") .description("Check authentication status") .action(async () => { if (!isAuthenticated()) { console.log("Not authenticated. Run: nexus-mcp login"); process.exit(1); } try { const result = await verifyApiKey(); if (result.valid) { console.log("✓ Authenticated"); console.log(` User: ${result.user?.name} (${result.user?.email})`); console.log(` Organization: ${result.org?.name}`); console.log(` API URL: ${getBaseUrl()}`); } else { console.log("✗ API key is invalid or expired"); console.log(" Run: nexus-mcp login"); process.exit(1); } } catch (error) { console.error(`✗ Failed to verify: ${error}`); process.exit(1); } }); program .command("logout") .description("Remove stored credentials") .action(() => { saveConfig({ apiKey: undefined }); console.log("Logged out. API key removed."); }); program .command("config") .description("Configure Nexus MCP") .option("--url <url>", "Set Nexus API URL") .option("--org <orgId>", "Set default organization ID") .action((options) => { if (options.url) { saveConfig({ baseUrl: options.url }); console.log(`API URL set to: ${options.url}`); } if (options.org) { saveConfig({ orgId: options.org }); console.log(`Default org set to: ${options.org}`); } if (!options.url && !options.org) { const apiKey = getApiKey(); console.log("Current configuration:"); console.log(` API URL: ${getBaseUrl()}`); console.log(` API Key: ${apiKey ? apiKey.slice(0, 12) + "..." : "(not set)"}`); } }); program .command("serve", { isDefault: true }) .description("Start the MCP server (default command)") .action(async () => { // Import and run the server const { startServer } = await import("./index.js"); await startServer(); }); program.parse();

Latest Blog Posts

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/iamserge/nexus-mcp'

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