Skip to main content
Glama

Spec Workflow MCP

config.ts4.81 kB
import * as fs from 'fs'; import * as path from 'path'; import * as toml from 'toml'; import { homedir } from 'os'; export interface SpecWorkflowConfig { projectDir?: string; port?: number; autoStartDashboard?: boolean; dashboardOnly?: boolean; lang?: string; } export interface ConfigLoadResult { config: SpecWorkflowConfig | null; configPath: string | null; error?: string; } function expandTilde(filepath: string): string { if (filepath.startsWith('~')) { return path.join(homedir(), filepath.slice(1)); } return filepath; } function validatePort(port: number): boolean { return Number.isInteger(port) && port >= 1024 && port <= 65535; } function validateConfig(config: any): { valid: boolean; error?: string } { if (config.port !== undefined) { if (!validatePort(config.port)) { return { valid: false, error: `Invalid port: ${config.port}. Port must be between 1024 and 65535.` }; } } if (config.projectDir !== undefined && typeof config.projectDir !== 'string') { return { valid: false, error: `Invalid projectDir: must be a string.` }; } if (config.autoStartDashboard !== undefined && typeof config.autoStartDashboard !== 'boolean') { return { valid: false, error: `Invalid autoStartDashboard: must be a boolean.` }; } if (config.dashboardOnly !== undefined && typeof config.dashboardOnly !== 'boolean') { return { valid: false, error: `Invalid dashboardOnly: must be a boolean.` }; } if (config.lang !== undefined && typeof config.lang !== 'string') { return { valid: false, error: `Invalid lang: must be a string.` }; } return { valid: true }; } export function loadConfigFromPath(configPath: string): ConfigLoadResult { try { const expandedPath = expandTilde(configPath); if (!fs.existsSync(expandedPath)) { return { config: null, configPath: expandedPath, error: `Config file not found: ${expandedPath}` }; } const configContent = fs.readFileSync(expandedPath, 'utf-8'); const parsedConfig = toml.parse(configContent); const validation = validateConfig(parsedConfig); if (!validation.valid) { return { config: null, configPath: expandedPath, error: validation.error }; } const config: SpecWorkflowConfig = {}; if (parsedConfig.projectDir !== undefined) { config.projectDir = expandTilde(parsedConfig.projectDir); } if (parsedConfig.port !== undefined) { config.port = parsedConfig.port; } if (parsedConfig.autoStartDashboard !== undefined) { config.autoStartDashboard = parsedConfig.autoStartDashboard; } if (parsedConfig.dashboardOnly !== undefined) { config.dashboardOnly = parsedConfig.dashboardOnly; } if (parsedConfig.lang !== undefined) { config.lang = parsedConfig.lang; } return { config, configPath: expandedPath }; } catch (error) { if (error instanceof Error) { return { config: null, configPath: null, error: `Failed to load config file: ${error.message}` }; } return { config: null, configPath: null, error: 'Failed to load config file: Unknown error' }; } } export function loadConfigFile(projectDir: string, customConfigPath?: string): ConfigLoadResult { // If custom config path is provided, use it if (customConfigPath) { return loadConfigFromPath(customConfigPath); } // Otherwise, look for default config in project directory try { const expandedDir = expandTilde(projectDir); const configDir = path.join(expandedDir, '.spec-workflow'); const configPath = path.join(configDir, 'config.toml'); if (!fs.existsSync(configPath)) { return { config: null, configPath: null }; } return loadConfigFromPath(configPath); } catch (error) { if (error instanceof Error) { return { config: null, configPath: null, error: `Failed to load config file: ${error.message}` }; } return { config: null, configPath: null, error: 'Failed to load config file: Unknown error' }; } } export function mergeConfigs( fileConfig: SpecWorkflowConfig | null, cliArgs: Partial<SpecWorkflowConfig> ): SpecWorkflowConfig { const merged: SpecWorkflowConfig = {}; if (fileConfig) { Object.assign(merged, fileConfig); } Object.keys(cliArgs).forEach(key => { const value = cliArgs[key as keyof SpecWorkflowConfig]; if (value !== undefined) { (merged as any)[key] = value; } }); return merged; }

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