UNPKG

marketing-post-generator-mcp

Version:

A powerful MCP server for AI-powered marketing blog post generation with Claude integration

220 lines 10.2 kB
// Configuration management for the Marketing Post Generator MCP import { randomUUID } from 'crypto'; function parseBoolean(value, defaultValue) { if (value === undefined) return defaultValue; return value.toLowerCase() === 'true'; } function createHttpConfig() { const config = { enableJsonResponse: parseBoolean(process.env.MCP_HTTP_JSON_RESPONSE, false), enableDnsRebindingProtection: parseBoolean(process.env.MCP_HTTP_DNS_PROTECTION, false), sessionIdGenerator: () => randomUUID(), }; if (process.env.MCP_HTTP_ALLOWED_HOSTS) { config.allowedHosts = process.env.MCP_HTTP_ALLOWED_HOSTS.split(','); } if (process.env.MCP_HTTP_ALLOWED_ORIGINS) { config.allowedOrigins = process.env.MCP_HTTP_ALLOWED_ORIGINS.split(','); } return config; } export const DEFAULT_CONFIG = { server: { mode: process.env.MCP_MODE || 'local', transport: process.env.MCP_TRANSPORT || 'stdio', port: parseInt(process.env.MCP_PORT || '3000', 10), host: process.env.MCP_HOST || '0.0.0.0', http: createHttpConfig(), }, postgen: { dataDir: process.env.POSTGEN_DATA_DIR || '.postgen', cacheEnabled: parseBoolean(process.env.POSTGEN_CACHE_ENABLED, true), cacheTtl: parseInt(process.env.POSTGEN_CACHE_TTL || '3600000', 10), // 1 hour }, claude: { apiKey: process.env.CLAUDE_API_KEY || '', ...(process.env.CLAUDE_BASE_URL && { baseUrl: process.env.CLAUDE_BASE_URL }), maxRetries: parseInt(process.env.CLAUDE_MAX_RETRIES || '3', 10), timeout: parseInt(process.env.CLAUDE_TIMEOUT || '30000', 10), // 30 seconds rateLimit: { requestsPerMinute: parseInt(process.env.CLAUDE_RATE_LIMIT_REQUESTS || '60', 10), tokensPerMinute: parseInt(process.env.CLAUDE_RATE_LIMIT_TOKENS || '50000', 10), }, }, search: { defaultAdapter: process.env.SEARCH_DEFAULT_ADAPTER || 'web-scraping', fallbackAdapters: process.env.SEARCH_FALLBACK_ADAPTERS ? process.env.SEARCH_FALLBACK_ADAPTERS.split(',') : [], adapterConfigs: { 'web-scraping': { sampleSize: parseInt(process.env.SEARCH_WEB_SAMPLE_SIZE || '5', 10), maxRequestsPerSecond: parseInt(process.env.SEARCH_WEB_RATE_LIMIT || '2', 10), timeout: parseInt(process.env.SEARCH_WEB_TIMEOUT || '30000', 10), userAgent: process.env.SEARCH_WEB_USER_AGENT || 'Mozilla/5.0 (compatible; MarketingPostGenerator/1.0)', }, firecrawl: { apiKey: process.env.FIRECRAWL_API_KEY || '', baseUrl: process.env.FIRECRAWL_BASE_URL || 'https://api.firecrawl.dev', rateLimit: parseInt(process.env.FIRECRAWL_RATE_LIMIT || '30', 10), maxRetries: parseInt(process.env.FIRECRAWL_MAX_RETRIES || '3', 10), timeoutMs: parseInt(process.env.FIRECRAWL_TIMEOUT || '30000', 10), maxCreditsPerDay: parseInt(process.env.FIRECRAWL_MAX_CREDITS_PER_DAY || '1000', 10), }, }, }, logging: { level: process.env.LOG_LEVEL || 'info', format: process.env.LOG_FORMAT || 'simple', }, errorHandling: { enableErrorReporting: parseBoolean(process.env.ERROR_REPORTING_ENABLED, true), enableStackTrace: parseBoolean(process.env.ERROR_STACK_TRACE_ENABLED, true), maxRecentErrors: parseInt(process.env.ERROR_MAX_RECENT || '100', 10), excludeStackTraceForCodes: process.env.ERROR_EXCLUDE_STACK_CODES ? process.env.ERROR_EXCLUDE_STACK_CODES.split(',') : ['VALIDATION_ERROR', 'RATE_LIMIT_ERROR'], notificationEnabled: parseBoolean(process.env.ERROR_NOTIFICATION_ENABLED, false), }, rateLimit: { enableRateLimit: parseBoolean(process.env.RATE_LIMIT_ENABLED, true), defaultWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '60000', 10), // 1 minute defaultMaxRequests: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '60', 10), enableStandardHeaders: parseBoolean(process.env.RATE_LIMIT_STANDARD_HEADERS, true), enableLegacyHeaders: parseBoolean(process.env.RATE_LIMIT_LEGACY_HEADERS, false), }, }; function createRemoteHttpConfig() { const config = { enableJsonResponse: parseBoolean(process.env.MCP_HTTP_JSON_RESPONSE, false), enableDnsRebindingProtection: parseBoolean(process.env.MCP_HTTP_DNS_PROTECTION, true), sessionIdGenerator: () => randomUUID(), }; if (process.env.MCP_HTTP_ALLOWED_HOSTS) { config.allowedHosts = process.env.MCP_HTTP_ALLOWED_HOSTS.split(','); } else { config.allowedHosts = ['localhost']; } if (process.env.MCP_HTTP_ALLOWED_ORIGINS) { config.allowedOrigins = process.env.MCP_HTTP_ALLOWED_ORIGINS.split(','); } else { config.allowedOrigins = ['*']; } return config; } export const REMOTE_CONFIG = { server: { mode: 'remote', transport: 'http', port: parseInt(process.env.PORT || '3000', 10), host: process.env.HOST || '0.0.0.0', http: createRemoteHttpConfig(), }, cors: { allowedOrigins: process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(',') : ['*'], allowedHeaders: ['mcp-session-id', 'content-type', 'authorization'], credentials: true, }, }; export function getConfig() { const baseConfig = { ...DEFAULT_CONFIG }; if (baseConfig.server.mode === 'remote') { return { ...baseConfig, ...REMOTE_CONFIG, server: { ...baseConfig.server, ...REMOTE_CONFIG.server, http: { ...baseConfig.server.http, ...REMOTE_CONFIG.server?.http, }, }, }; } return baseConfig; } export function validateConfig(config) { if (!config.server.mode || !['local', 'remote'].includes(config.server.mode)) { throw new Error('Invalid server mode. Must be "local" or "remote"'); } if (!config.server.transport || !['stdio', 'http'].includes(config.server.transport)) { throw new Error('Invalid transport. Must be "stdio" or "http"'); } if (config.server.mode === 'remote' && (!config.server.port || config.server.port < 1 || config.server.port > 65535)) { throw new Error('Invalid port for remote mode. Must be between 1 and 65535'); } if (!config.postgen.dataDir) { throw new Error('PostGen data directory is required'); } if (!config.claude.apiKey) { throw new Error('Claude API key is required. Set CLAUDE_API_KEY environment variable'); } if (config.claude.maxRetries !== undefined && (config.claude.maxRetries < 0 || config.claude.maxRetries > 10)) { throw new Error('Claude max retries must be between 0 and 10'); } if (config.claude.timeout !== undefined && (config.claude.timeout < 1000 || config.claude.timeout > 120000)) { throw new Error('Claude timeout must be between 1000ms and 120000ms (2 minutes)'); } if (config.claude.rateLimit) { if (config.claude.rateLimit.requestsPerMinute < 1 || config.claude.rateLimit.requestsPerMinute > 1000) { throw new Error('Claude rate limit requests per minute must be between 1 and 1000'); } if (config.claude.rateLimit.tokensPerMinute < 1000 || config.claude.rateLimit.tokensPerMinute > 1000000) { throw new Error('Claude rate limit tokens per minute must be between 1000 and 1000000'); } } // Validate errorHandling configuration if (config.errorHandling) { if (typeof config.errorHandling.enableErrorReporting !== 'boolean') { throw new Error('Error handling enableErrorReporting must be a boolean'); } if (typeof config.errorHandling.enableStackTrace !== 'boolean') { throw new Error('Error handling enableStackTrace must be a boolean'); } if (typeof config.errorHandling.notificationEnabled !== 'boolean') { throw new Error('Error handling notificationEnabled must be a boolean'); } if (config.errorHandling.maxRecentErrors !== undefined && (config.errorHandling.maxRecentErrors < 10 || config.errorHandling.maxRecentErrors > 1000)) { throw new Error('Error handling maxRecentErrors must be between 10 and 1000'); } if (config.errorHandling.excludeStackTraceForCodes !== undefined && !Array.isArray(config.errorHandling.excludeStackTraceForCodes)) { throw new Error('Error handling excludeStackTraceForCodes must be an array'); } if (config.errorHandling.excludeStackTraceForCodes?.some((code) => typeof code !== 'string')) { throw new Error('Error handling excludeStackTraceForCodes must be an array of strings'); } } // Validate rateLimit configuration if (config.rateLimit) { if (typeof config.rateLimit.enableRateLimit !== 'boolean') { throw new Error('Rate limit enableRateLimit must be a boolean'); } if (typeof config.rateLimit.enableStandardHeaders !== 'boolean') { throw new Error('Rate limit enableStandardHeaders must be a boolean'); } if (typeof config.rateLimit.enableLegacyHeaders !== 'boolean') { throw new Error('Rate limit enableLegacyHeaders must be a boolean'); } if (config.rateLimit.defaultWindowMs !== undefined && (config.rateLimit.defaultWindowMs < 1000 || config.rateLimit.defaultWindowMs > 3600000)) { throw new Error('Rate limit defaultWindowMs must be between 1000ms (1 second) and 3600000ms (1 hour)'); } if (config.rateLimit.defaultMaxRequests !== undefined && (config.rateLimit.defaultMaxRequests < 1 || config.rateLimit.defaultMaxRequests > 10000)) { throw new Error('Rate limit defaultMaxRequests must be between 1 and 10000'); } } } //# sourceMappingURL=index.js.map