Skip to main content
Glama

Frontend Test Generation & Code Review MCP Server

env.ts7.01 kB
import { z } from 'zod'; import dotenv from 'dotenv'; // 加载 .env 文件 dotenv.config(); // 环境变量 schema const envSchema = z.object({ OPENAI_API_KEY: z.string().min(1, 'OPENAI_API_KEY is required'), OPENAI_BASE_URL: z.string().url().optional().default('https://api.openai.com/v1'), OPENAI_MODEL: z.string().optional().default('gpt-4'), EMBEDDING_BASE_URL: z.string().url().optional(), EMBEDDING_MODEL: z.string().optional().default('text-embedding-3-small'), PHABRICATOR_HOST: z.string().url('PHABRICATOR_HOST must be a valid URL'), PHABRICATOR_TOKEN: z.string().min(1, 'PHABRICATOR_TOKEN is required'), // 可选配置 MODEL_TEMPERATURE: z.string().optional().default('0'), MODEL_TOP_P: z.string().optional().default('1'), CACHE_DIR: z.string().optional().default('.cache'), STATE_DIR: z.string().optional().default('.state'), ALLOW_PUBLISH_COMMENTS: z.string().optional().default('false'), }); export type Env = z.infer<typeof envSchema>; let env: Env | null = null; /** * API 提供商类型 */ export type ApiProvider = 'openai' | 'dashscope' | 'custom'; /** * 检测 API 提供商 */ function detectApiProvider(baseURL?: string): ApiProvider { if (!baseURL) { return 'openai'; // 默认为 OpenAI } if (baseURL.includes('dashscope.aliyuncs.com')) { return 'dashscope'; } if (baseURL.includes('api.openai.com')) { return 'openai'; } return 'custom'; } /** * 验证模型名称格式 */ function validateModelName(model: string, provider: ApiProvider, type: 'llm' | 'embedding'): { valid: boolean; message?: string; } { if (type === 'llm') { switch (provider) { case 'openai': // OpenAI 模型:gpt-4, gpt-4-turbo, gpt-3.5-turbo 等 if (model.startsWith('gpt-')) { return { valid: true }; } return { valid: false, message: `OpenAI LLM 模型名称应以 'gpt-' 开头,当前值: ${model}\n建议: gpt-4, gpt-4-turbo, gpt-3.5-turbo`, }; case 'dashscope': // DashScope 模型:qwen-*, qwen-turbo, qwen-plus 等 if (model.startsWith('qwen-') || model.startsWith('qwen2-')) { return { valid: true }; } return { valid: false, message: `DashScope LLM 模型名称应以 'qwen-' 或 'qwen2-' 开头,当前值: ${model}\n建议: qwen-plus, qwen-turbo, qwen-max`, }; default: // 自定义提供商,不验证格式 return { valid: true }; } } else { // embedding 模型 switch (provider) { case 'openai': if (model.startsWith('text-embedding-')) { return { valid: true }; } return { valid: false, message: `OpenAI Embedding 模型名称应以 'text-embedding-' 开头,当前值: ${model}\n建议: text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002`, }; case 'dashscope': if (model.startsWith('text-embedding-')) { return { valid: true }; } return { valid: false, message: `DashScope Embedding 模型名称应以 'text-embedding-' 开头,当前值: ${model}\n建议: text-embedding-v1, text-embedding-v2, text-embedding-v3`, }; default: return { valid: true }; } } } /** * 验证 API Key 格式 */ function validateApiKey(apiKey: string, provider: ApiProvider): { valid: boolean; message?: string; } { switch (provider) { case 'openai': if (apiKey.startsWith('sk-')) { return { valid: true }; } return { valid: false, message: `OpenAI API Key 应以 'sk-' 开头,当前值不符合格式`, }; case 'dashscope': if (apiKey.startsWith('sk-')) { return { valid: true }; } return { valid: false, message: `DashScope API Key 应以 'sk-' 开头,当前值不符合格式`, }; default: // 自定义提供商,只检查是否为空 if (apiKey && apiKey.length > 0) { return { valid: true }; } return { valid: false, message: 'API Key 不能为空', }; } } /** * 获取并验证环境变量 */ export function getEnv(): Env { if (env) { return env; } try { env = envSchema.parse({ OPENAI_API_KEY: process.env.OPENAI_API_KEY, OPENAI_BASE_URL: process.env.OPENAI_BASE_URL, OPENAI_MODEL: process.env.OPENAI_MODEL, EMBEDDING_BASE_URL: process.env.EMBEDDING_BASE_URL, EMBEDDING_MODEL: process.env.EMBEDDING_MODEL, PHABRICATOR_HOST: process.env.PHABRICATOR_HOST, PHABRICATOR_TOKEN: process.env.PHABRICATOR_TOKEN, MODEL_TEMPERATURE: process.env.MODEL_TEMPERATURE, MODEL_TOP_P: process.env.MODEL_TOP_P, CACHE_DIR: process.env.CACHE_DIR, STATE_DIR: process.env.STATE_DIR, ALLOW_PUBLISH_COMMENTS: process.env.ALLOW_PUBLISH_COMMENTS, }); return env; } catch (error) { if (error instanceof z.ZodError) { const missing = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', '); throw new Error(`Environment validation failed: ${missing}`); } throw error; } } /** * 验证 AI 配置 * 检查模型名称、API Key 格式等 */ export function validateAiConfig(config: { llm: { apiKey: string; baseURL?: string; model: string; }; embedding?: { baseURL?: string; model: string; enabled?: boolean; }; }): { valid: boolean; warnings: string[]; errors: string[]; } { const warnings: string[] = []; const errors: string[] = []; // 1. 验证 LLM 配置 const llmProvider = detectApiProvider(config.llm.baseURL); // 验证 API Key const apiKeyValidation = validateApiKey(config.llm.apiKey, llmProvider); if (!apiKeyValidation.valid) { errors.push(`LLM API Key: ${apiKeyValidation.message}`); } // 验证模型名称 const llmModelValidation = validateModelName(config.llm.model, llmProvider, 'llm'); if (!llmModelValidation.valid) { warnings.push(`LLM Model: ${llmModelValidation.message}`); } // 2. 验证 Embedding 配置(如果启用) if (config.embedding?.enabled !== false && config.embedding?.baseURL) { const embeddingProvider = detectApiProvider(config.embedding.baseURL); const embeddingModelValidation = validateModelName( config.embedding.model, embeddingProvider, 'embedding' ); if (!embeddingModelValidation.valid) { warnings.push(`Embedding Model: ${embeddingModelValidation.message}`); } // 如果 LLM 和 Embedding 使用不同的提供商,给出警告 if (llmProvider !== embeddingProvider) { warnings.push( `LLM 和 Embedding 使用不同的 API 提供商 (LLM: ${llmProvider}, Embedding: ${embeddingProvider}),这可能导致兼容性问题` ); } } return { valid: errors.length === 0, warnings, errors, }; }

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/NorthSeacoder/fe-testgen-mcp'

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