Skip to main content
Glama
index.ts9.84 kB
#!/usr/bin/env node import { SpecWorkflowMCPServer } from './server.js'; import { MultiProjectDashboardServer } from './dashboard/multi-server.js'; import { DashboardSessionManager } from './core/dashboard-session.js'; import { homedir } from 'os'; import { WorkspaceInitializer } from './core/workspace-initializer.js'; import { readFileSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; // Default dashboard port const DEFAULT_DASHBOARD_PORT = 5000; function showHelp() { console.error(` Spec Workflow MCP Server - A Model Context Protocol server for spec-driven development USAGE: spec-workflow-mcp [path] [options] ARGUMENTS: path Project path (defaults to current directory) Supports ~ for home directory OPTIONS: --help Show this help message --dashboard Run dashboard-only mode (no MCP server) --port <number> Specify dashboard port (1024-65535) Default: 5000 Only use if port 5000 is unavailable IMPORTANT: Only ONE dashboard instance runs at a time. All MCP servers connect to the same dashboard. The dashboard runs on port 5000 by default. MODES OF OPERATION: 1. MCP Server Only (default): spec-workflow-mcp spec-workflow-mcp ~/my-project Starts MCP server without dashboard. Dashboard can be started separately. 2. Dashboard Only Mode: spec-workflow-mcp --dashboard spec-workflow-mcp --dashboard --port 8080 Runs only the web dashboard without MCP server (default port: 5000). Projects will automatically appear in the dashboard as MCP servers register. Only one dashboard instance is needed for all your projects. EXAMPLES: # Start MCP server in current directory (no dashboard) spec-workflow-mcp # Start MCP server in a specific project directory spec-workflow-mcp ~/projects/my-app # Run dashboard (default port 5000) - START THIS FIRST spec-workflow-mcp --dashboard # Run dashboard on custom port (if 5000 is unavailable) spec-workflow-mcp --dashboard --port 8080 TYPICAL WORKFLOW: 1. Start the dashboard once: spec-workflow-mcp --dashboard 2. Start MCP servers for your projects (in separate terminals): spec-workflow-mcp ~/project1 spec-workflow-mcp ~/project2 spec-workflow-mcp ~/project3 All projects will appear in the same dashboard at http://localhost:5000 PARAMETER FORMATS: --port 3456 Space-separated format --port=3456 Equals format For more information, visit: https://github.com/Pimzino/spec-workflow-mcp `); } function expandTildePath(path: string): string { if (path.startsWith('~/') || path === '~') { return path.replace('~', homedir()); } return path; } function parseArguments(args: string[]): { projectPath: string; isDashboardMode: boolean; port?: number; lang?: string; } { const isDashboardMode = args.includes('--dashboard'); let customPort: number | undefined; // Check for invalid flags const validFlags = ['--dashboard', '--port', '--help', '-h']; for (const arg of args) { if (arg.startsWith('--') && !arg.includes('=')) { if (!validFlags.includes(arg)) { throw new Error(`Unknown option: ${arg}\nUse --help to see available options.`); } } else if (arg.startsWith('--') && arg.includes('=')) { const flagName = arg.split('=')[0]; if (!validFlags.includes(flagName)) { throw new Error(`Unknown option: ${flagName}\nUse --help to see available options.`); } } } // Parse --port parameter (supports --port 3000 and --port=3000 formats) for (let i = 0; i < args.length; i++) { const arg = args[i]; if (arg.startsWith('--port=')) { // Handle --port=3000 format const portStr = arg.split('=')[1]; if (portStr) { const parsed = parseInt(portStr, 10); if (isNaN(parsed)) { throw new Error(`Invalid port number: ${portStr}. Port must be a number.`); } if (parsed < 1024 || parsed > 65535) { throw new Error(`Port ${parsed} is out of range. Port must be between 1024 and 65535.`); } customPort = parsed; } else { throw new Error('--port parameter requires a value (e.g., --port=3000)'); } } else if (arg === '--port' && i + 1 < args.length) { // Handle --port 3000 format const portStr = args[i + 1]; const parsed = parseInt(portStr, 10); if (isNaN(parsed)) { throw new Error(`Invalid port number: ${portStr}. Port must be a number.`); } if (parsed < 1024 || parsed > 65535) { throw new Error(`Port ${parsed} is out of range. Port must be between 1024 and 65535.`); } customPort = parsed; i++; // Skip the next argument as it's the port value } else if (arg === '--port') { throw new Error('--port parameter requires a value (e.g., --port 3000)'); } } // Get project path (filter out flags and their values) const filteredArgs = args.filter((arg, index) => { if (arg === '--dashboard') return false; if (arg.startsWith('--port=')) return false; if (arg === '--port') return false; // Check if this arg is a value following --port if (index > 0 && args[index - 1] === '--port') return false; return true; }); // For dashboard-only mode, use cwd as default (dashboard doesn't need it) const rawProjectPath = filteredArgs[0] || process.cwd(); const projectPath = expandTildePath(rawProjectPath); // Warn if no explicit path was provided and we're using cwd (but only for MCP server mode) if (!filteredArgs[0] && !isDashboardMode) { console.warn(`Warning: No project path specified, using current directory: ${projectPath}`); console.warn('Consider specifying an explicit path for better clarity.'); } return { projectPath, isDashboardMode, port: customPort, lang: undefined }; } async function main() { try { const args = process.argv.slice(2); // Check for help flag if (args.includes('--help') || args.includes('-h')) { showHelp(); process.exit(0); } // Parse command-line arguments const cliArgs = parseArguments(args); let projectPath = cliArgs.projectPath; // Apply configuration from CLI args const isDashboardMode = cliArgs.isDashboardMode || false; const port = cliArgs.port; const lang = cliArgs.lang; if (isDashboardMode) { // Check if a dashboard is already running (always check, regardless of port) const sessionManager = new DashboardSessionManager(); const existingSession = await sessionManager.getDashboardSession(); if (existingSession) { console.error(`Dashboard is already running at: ${existingSession.url}`); console.error(''); console.error('You can:'); console.error(` 1. Use the existing dashboard at: ${existingSession.url}`); console.error(` 2. Stop it first (Ctrl+C or kill ${existingSession.pid}), then start a new one`); console.error(''); console.error('Note: Only one dashboard instance is needed for all your projects.'); process.exit(1); } // Use specified port or default const dashboardPort = port || DEFAULT_DASHBOARD_PORT; // Dashboard only mode - use new multi-project dashboard console.error(`Starting Unified Multi-Project Dashboard`); if (port) { console.error(`Using custom port: ${port}`); } else { console.error(`Using default port: ${DEFAULT_DASHBOARD_PORT}`); } const dashboardServer = new MultiProjectDashboardServer({ autoOpen: true, port: dashboardPort }); try { const dashboardUrl = await dashboardServer.start(); console.error(`Dashboard started at: ${dashboardUrl}`); console.error('Projects will automatically appear as MCP servers register.'); console.error('Press Ctrl+C to stop the dashboard'); } catch (error: any) { console.error(`Failed to start dashboard: ${error.message}`); process.exit(1); } // Handle graceful shutdown const shutdown = async () => { console.error('\nShutting down dashboard...'); await dashboardServer.stop(); process.exit(0); }; process.on('SIGINT', shutdown); process.on('SIGTERM', shutdown); // Keep the process running process.stdin.resume(); } else { // MCP server mode console.error(`Starting Spec Workflow MCP Server for project: ${projectPath}`); console.error(`Working directory: ${process.cwd()}`); const server = new SpecWorkflowMCPServer(); await server.initialize(projectPath, lang); // Handle graceful shutdown process.on('SIGINT', async () => { await server.stop(); process.exit(0); }); process.on('SIGTERM', async () => { await server.stop(); process.exit(0); }); } } catch (error: any) { console.error('Error:', error.message); // Provide additional context for common path-related issues if (error.message.includes('ENOENT') || error.message.includes('path') || error.message.includes('directory')) { console.error('\nProject path troubleshooting:'); console.error('- Verify the project path exists and is accessible'); console.error('- For Claude CLI users, ensure you used: claude mcp add spec-workflow npx -y @pimzino/spec-workflow-mcp@latest -- /path/to/your/project'); console.error('- Check that the path doesn\'t contain special characters that need escaping'); console.error(`- Current working directory: ${process.cwd()}`); } process.exit(1); } } main().catch(() => process.exit(1));

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/Pimzino/spec-workflow-mcp'

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