Skip to main content
Glama
server.ts35.2 kB
/** * MCP Server 模块 * 提供 Claude Code 集成的多智能体协作服务 */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs'; import { join } from 'node:path'; import { loadConfig } from './config/loader.js'; import type { Config } from './config/schema.js'; import { createAdapter } from './adapters/index.js'; import { TechLead } from './agents/tech-lead.js'; import { Orchestrator, type TeamResult } from './collaboration/orchestrator.js'; import { HistoryManager } from './collaboration/history.js'; import { globalStats } from './collaboration/stats.js'; import { workflowManager } from './collaboration/workflow.js'; import { createRequire } from 'node:module'; /** 内置专家角色定义 */ const BUILTIN_EXPERTS: Record<string, { name: string; role: string; tier: 'fast' | 'balanced' | 'powerful' }> = { frontend: { name: '前端专家', role: '你是一位资深前端工程师,精通 React、Vue、TypeScript、CSS 等前端技术。', tier: 'balanced' }, backend: { name: '后端专家', role: '你是一位资深后端工程师,精通 API 设计、数据库、Node.js、Python 等后端技术。', tier: 'powerful' }, qa: { name: 'QA专家', role: '你是一位资深 QA 工程师,擅长代码审查、测试、安全分析和 Bug 修复。', tier: 'balanced' }, }; /** * 获取所有可用专家(内置 + 自定义) */ function getAllExperts(config: Config): Record<string, { name: string; role: string; tier: 'fast' | 'balanced' | 'powerful' }> { const experts = { ...BUILTIN_EXPERTS }; // 添加自定义专家 if (config.customExperts) { for (const [id, custom] of Object.entries(config.customExperts)) { experts[id] = { name: custom.name, role: custom.prompt, tier: custom.tier || 'balanced', }; } } return experts; } /** * 生成专家 enum 和描述 */ function generateExpertEnumInfo(experts: Record<string, { name: string; role: string; tier: 'fast' | 'balanced' | 'powerful' }>): { enum: string[]; description: string } { const ids = Object.keys(experts); const descriptions = ids.map(id => `${id}(${experts[id].name})`); return { enum: ids, description: `专家类型:${descriptions.join('、')}`, }; } /** 从 package.json 读取版本号 */ const require = createRequire(import.meta.url); const { version: SERVER_VERSION } = require('../package.json'); /** * 创建 Tech Lead 实例 */ function createTechLead(config: ReturnType<typeof loadConfig>): TechLead { const modelConfig = config.models[config.lead.model]; if (!modelConfig) { throw new Error(`Tech Lead 模型 ${config.lead.model} 未找到`); } return new TechLead(createAdapter(modelConfig)); } /** * 创建 MCP Server * @returns MCP Server 实例 */ export async function createServer(): Promise<Server> { // 加载配置 const config = loadConfig(); // 创建 Tech Lead(专家由 Orchestrator 动态创建) const techLead = createTechLead(config); // 创建编排器和历史管理器 const orchestrator = new Orchestrator({ lead: techLead, config, maxIterations: config.collaboration?.maxIterations, }); const historyManager = new HistoryManager(); // 创建 MCP Server const server = new Server( { name: 'claude-team', version: SERVER_VERSION }, { capabilities: { tools: {} } } ); // 获取所有可用专家(内置 + 自定义) const allExperts = getAllExperts(config); const expertEnumInfo = generateExpertEnumInfo(allExperts); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'team_work', description: '让 AI 开发团队协作完成任务。团队包含前端专家、后端专家、QA专家,会智能分配任务并互相协作。', inputSchema: { type: 'object', properties: { task: { type: 'string', description: '任务描述,例如:帮我写一个用户登录功能', }, context: { type: 'string', description: '额外的上下文信息(可选)', }, }, required: ['task'], }, }, { name: 'ask_expert', description: '向特定专家咨询问题', inputSchema: { type: 'object', properties: { expert: { type: 'string', enum: expertEnumInfo.enum, description: expertEnumInfo.description, }, question: { type: 'string', description: '要咨询的问题', }, }, required: ['expert', 'question'], }, }, { name: 'code_review', description: '让专家审查代码', inputSchema: { type: 'object', properties: { code: { type: 'string', description: '要审查的代码', }, reviewer: { type: 'string', enum: expertEnumInfo.enum, description: `审查者:${expertEnumInfo.description}`, }, context: { type: 'string', description: '代码的背景信息(可选)', }, }, required: ['code', 'reviewer'], }, }, { name: 'fix_bug', description: '让 QA 专家修复 Bug', inputSchema: { type: 'object', properties: { code: { type: 'string', description: '有 Bug 的代码', }, error: { type: 'string', description: '错误信息或 Bug 描述', }, }, required: ['code', 'error'], }, }, { name: 'history_list', description: '查看团队协作历史记录列表', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: '返回记录数量,默认 10', }, }, }, }, { name: 'history_get', description: '获取某次协作的详细记录', inputSchema: { type: 'object', properties: { id: { type: 'string', description: '协作记录 ID', }, }, required: ['id'], }, }, { name: 'history_search', description: '搜索协作历史记录', inputSchema: { type: 'object', properties: { query: { type: 'string', description: '搜索关键词', }, limit: { type: 'number', description: '返回记录数量,默认 10', }, }, required: ['query'], }, }, { name: 'history_context', description: '获取最近的协作上下文,可用于继续之前的工作', inputSchema: { type: 'object', properties: { count: { type: 'number', description: '获取最近几次协作,默认 3', }, }, }, }, { name: 'usage_stats', description: '查看各模型的使用统计(调用次数、成功率、平均耗时)', inputSchema: { type: 'object', properties: {}, }, }, { name: 'team_dashboard', description: '查看团队当前状态:可用专家、模型配置、最近活动', inputSchema: { type: 'object', properties: {}, }, }, { name: 'cost_estimate', description: '预估任务执行成本(Token 用量、预计耗时)', inputSchema: { type: 'object', properties: { task: { type: 'string', description: '要预估的任务描述', }, }, required: ['task'], }, }, { name: 'explain_plan', description: '解释 Tech Lead 会如何分配任务(不实际执行)', inputSchema: { type: 'object', properties: { task: { type: 'string', description: '要分析的任务描述', }, }, required: ['task'], }, }, { name: 'read_project_files', description: '读取项目文件内容,让专家了解代码上下文', inputSchema: { type: 'object', properties: { path: { type: 'string', description: '文件或目录路径(相对于当前工作目录)', }, pattern: { type: 'string', description: '文件匹配模式(如 *.ts, *.js),仅读取目录时有效', }, maxFiles: { type: 'number', description: '最多读取文件数(默认 10)', }, }, required: ['path'], }, }, { name: 'generate_commit_message', description: '根据代码变更生成 Git commit message', inputSchema: { type: 'object', properties: { diff: { type: 'string', description: '代码变更内容(git diff 输出)', }, style: { type: 'string', enum: ['conventional', 'simple', 'detailed'], description: '提交信息风格:conventional(约定式)、simple(简洁)、detailed(详细)', }, }, required: ['diff'], }, }, { name: 'analyze_project_structure', description: '分析项目结构,识别技术栈和架构', inputSchema: { type: 'object', properties: { path: { type: 'string', description: '项目根目录路径(默认当前目录)', }, }, }, }, { name: 'list_workflows', description: '列出所有可用的工作流模板', inputSchema: { type: 'object', properties: {}, }, }, { name: 'run_workflow', description: '使用指定工作流执行任务', inputSchema: { type: 'object', properties: { workflow: { type: 'string', enum: ['code-generation', 'bug-fix', 'refactoring', 'code-review', 'documentation'], description: '工作流 ID', }, task: { type: 'string', description: '任务描述', }, context: { type: 'string', description: '额外上下文(可选)', }, }, required: ['workflow', 'task'], }, }, { name: 'suggest_workflow', description: '根据任务自动推荐合适的工作流', inputSchema: { type: 'object', properties: { task: { type: 'string', description: '任务描述', }, }, required: ['task'], }, }, ], })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'team_work': { const { task, context } = args as { task: string; context?: string }; const startTime = Date.now(); // 收集进度信息 const progressLogs: string[] = []; orchestrator.setProgressCallback((message, progress) => { const timestamp = new Date().toLocaleTimeString(); const progressStr = progress ? ` (${progress}%)` : ''; const log = `[${timestamp}]${progressStr} ${message}`; progressLogs.push(log); // 同时输出到 stderr 以便调试 console.error(log); }); // 记录统计 const endTimer = globalStats.startTimer('team_work', 'orchestrator'); let result: TeamResult; try { result = await orchestrator.execute(task, context); endTimer(true); } catch (error) { endTimer(false, (error as Error).message); throw error; } const duration = Date.now() - startTime; // 保存到历史记录 const historyEntry = historyManager.save({ task, summary: result.summary, experts: result.outputs.map(o => o.expertId), outputs: result.outputs.map(o => ({ expertId: o.expertId, expertName: o.expertName, content: o.content, })), conversation: result.conversation.map(m => ({ from: m.from, content: m.content, type: m.type, })), duration, }); // 构建进度日志文本 const progressText = progressLogs.length > 0 ? `\n\n---\n📊 **执行过程**:\n${progressLogs.join('\n')}\n⏱️ 总耗时: ${(duration / 1000).toFixed(1)}s` : ''; return { content: [ { type: 'text', text: formatTeamResult(result) + progressText + `\n\n---\n📝 **历史记录 ID**: \`${historyEntry.id}\``, }, ], }; } case 'ask_expert': { const { expert, question } = args as { expert: string; question: string }; // 从动态专家列表中获取配置 const expertConfig = allExperts[expert] ?? { name: '技术专家', role: '你是一位技术专家。', tier: 'balanced' as const }; const response = await orchestrator.askDynamicExpert(expertConfig.tier, expertConfig.role, question); return { content: [{ type: 'text', text: `**${expertConfig.name}** 回复:\n\n${response}` }], }; } case 'code_review': { const { code, reviewer, context } = args as { code: string; reviewer?: string; context?: string }; // 如果指定了审查者,使用对应专家的角色 let reviewerConfig: { name: string; role: string; tier: 'fast' | 'balanced' | 'powerful' } = { name: '代码审查专家', role: '你是一位资深代码审查专家。', tier: 'balanced' }; if (reviewer && allExperts[reviewer]) { reviewerConfig = allExperts[reviewer]; } const reviewRole = `${reviewerConfig.role}\n\n请审查以下代码,关注代码质量、潜在 Bug、安全问题和最佳实践。${context ? `\n背景: ${context}` : ''}`; const review = await orchestrator.askDynamicExpert(reviewerConfig.tier, reviewRole, `请审查以下代码:\n\n${code}`); return { content: [{ type: 'text', text: `**${reviewerConfig.name}** 审查结果:\n\n${review}` }], }; } case 'fix_bug': { const { code, error } = args as { code: string; error: string }; const fixRole = '你是一位资深 Bug 修复专家,擅长分析错误信息并提供修复方案。请分析问题根因,给出修复后的完整代码。'; const fix = await orchestrator.askDynamicExpert( 'powerful', fixRole, `请修复以下代码中的 Bug:\n\n代码:\n\`\`\`\n${code}\n\`\`\`\n\n错误信息:${error}` ); return { content: [{ type: 'text', text: fix }], }; } case 'history_list': { const { limit } = args as { limit?: number }; const summaries = historyManager.list(limit || 10); return { content: [ { type: 'text', text: historyManager.formatList(summaries), }, ], }; } case 'history_get': { const { id } = args as { id: string }; const entry = historyManager.get(id); if (!entry) { throw new Error(`History entry ${id} not found`); } return { content: [ { type: 'text', text: historyManager.formatEntry(entry), }, ], }; } case 'history_search': { const { query, limit } = args as { query: string; limit?: number }; const results = historyManager.search(query, limit || 10); return { content: [ { type: 'text', text: results.length > 0 ? historyManager.formatList(results) : `未找到包含 "${query}" 的协作记录`, }, ], }; } case 'history_context': { const { count } = args as { count?: number }; const recent = historyManager.getRecent(count || 3); if (recent.length === 0) { return { content: [ { type: 'text', text: '暂无协作历史记录', }, ], }; } const contextText = recent.map(entry => { return `### ${entry.task}\n**ID**: ${entry.id}\n**时间**: ${new Date(entry.timestamp).toLocaleString()}\n\n${entry.summary}`; }).join('\n\n---\n\n'); return { content: [ { type: 'text', text: `## 📚 最近的协作上下文\n\n${contextText}`, }, ], }; } case 'usage_stats': { return { content: [ { type: 'text', text: globalStats.formatStats(), }, ], }; } case 'team_dashboard': { // 构建团队仪表盘信息 const expertList = Object.entries(allExperts) .map(([id, e]) => `- **${e.name}** (\`${id}\`) - ${e.tier} 级别`) .join('\n'); const modelList = Object.entries(config.models) .map(([name, m]) => `- **${name}**: ${m.model} (${m.provider}, ${m.tier || 'balanced'})`) .join('\n'); const recentHistory = historyManager.list(3); const recentText = recentHistory.length > 0 ? recentHistory.map(h => `- ${h.task.slice(0, 50)}${h.task.length > 50 ? '...' : ''} (${new Date(h.timestamp).toLocaleString()})`).join('\n') : '暂无记录'; const stats = globalStats.getGlobalStats(); const dashboard = `# 🎛️ 团队仪表盘 ## 👥 可用专家 (${Object.keys(allExperts).length} 个) ${expertList} ## 🤖 模型配置 ${modelList} ## 📊 运行统计 - 总调用次数: ${stats.totalCalls} - 成功率: ${stats.totalCalls > 0 ? ((stats.totalSuccess / stats.totalCalls) * 100).toFixed(1) : 0}% - 平均耗时: ${stats.avgDuration.toFixed(0)}ms ## 📜 最近活动 ${recentText}`; return { content: [{ type: 'text', text: dashboard }], }; } case 'cost_estimate': { const { task } = args as { task: string }; // 简单的 token 估算(基于任务描述长度和复杂度) const taskTokens = Math.ceil(task.length / 4); // 粗略估算输入 tokens const isComplex = task.includes('优化') || task.includes('架构') || task.includes('重构') || task.includes('安全'); const estimatedExperts = isComplex ? 3 : 2; const tokensPerExpert = isComplex ? 4000 : 2000; const estimatedInputTokens = taskTokens + (estimatedExperts * 500); // 系统提示词 const estimatedOutputTokens = estimatedExperts * tokensPerExpert; const totalTokens = estimatedInputTokens + estimatedOutputTokens; // 费用估算(基于 GPT-4o 价格:$5/1M input, $15/1M output) const inputCost = (estimatedInputTokens / 1000000) * 5; const outputCost = (estimatedOutputTokens / 1000000) * 15; const totalCost = inputCost + outputCost; // 耗时估算 const avgDuration = globalStats.getGlobalStats().avgDuration || 5000; const estimatedTime = (avgDuration * estimatedExperts) / 1000; const estimate = `# 💰 成本预估 ## 任务分析 - **任务描述**: ${task.slice(0, 100)}${task.length > 100 ? '...' : ''} - **复杂度**: ${isComplex ? '高' : '中'} - **预计专家数**: ${estimatedExperts} 个 ## Token 预估 | 类型 | 数量 | |------|------| | 输入 Tokens | ~${estimatedInputTokens.toLocaleString()} | | 输出 Tokens | ~${estimatedOutputTokens.toLocaleString()} | | **总计** | **~${totalTokens.toLocaleString()}** | ## 费用预估 (基于 GPT-4o) - 输入: $${inputCost.toFixed(4)} - 输出: $${outputCost.toFixed(4)} - **总计**: **$${totalCost.toFixed(4)}** ## 时间预估 - 预计耗时: ~${estimatedTime.toFixed(0)} 秒 > ⚠️ 这是粗略估算,实际费用取决于模型选择和任务复杂度`; return { content: [{ type: 'text', text: estimate }], }; } case 'explain_plan': { const { task } = args as { task: string }; // 让 Tech Lead 分析任务但不执行 const analysis = await techLead.analyze(task); const expertPlan = analysis.experts .map((e: { id: string; name: string; tier: string; role: string }, i: number) => { const subtask = analysis.subtasks.find(t => t.expertId === e.id); return `${i + 1}. **${e.name}** (${e.tier})\n - 角色: ${e.role.slice(0, 100)}...\n - 任务: ${subtask?.description || '待分配'}`; }) .join('\n\n'); const plan = `# 🧠 任务执行计划 ## 任务分析 **原始任务**: ${task} ## Tech Lead 分析结果 ### 工作流类型 \`${analysis.workflow}\` ${analysis.workflow === 'sequential' ? '(顺序执行)' : analysis.workflow === 'parallel' ? '(并行执行)' : '(并行+审查)'} ### 专家分配 (${analysis.experts.length} 个) ${expertPlan} ### 执行顺序 ${analysis.workflow === 'parallel' ? '所有专家将并行执行任务' : analysis.experts.map((e: { name: string }, i: number) => `${i + 1}. ${e.name}`).join(' → ')} --- > 💡 这只是计划预览,使用 \`team_work\` 工具实际执行任务`; return { content: [{ type: 'text', text: plan }], }; } case 'read_project_files': { const { path: targetPath, pattern, maxFiles = 10 } = args as { path: string; pattern?: string; maxFiles?: number }; const fullPath = join(process.cwd(), targetPath); if (!existsSync(fullPath)) { throw new Error(`路径不存在: ${targetPath}`); } const stat = statSync(fullPath); let result = ''; if (stat.isFile()) { // 读取单个文件 const content = readFileSync(fullPath, 'utf-8'); result = `# 📄 ${targetPath}\n\n\`\`\`\n${content.slice(0, 10000)}${content.length > 10000 ? '\n... (内容已截断)' : ''}\n\`\`\``; } else if (stat.isDirectory()) { // 读取目录下的文件 const files = readdirSync(fullPath) .filter(f => { if (pattern) { const regex = new RegExp(pattern.replace('*', '.*')); return regex.test(f); } return true; }) .slice(0, maxFiles); result = `# 📁 ${targetPath}\n\n`; for (const file of files) { const filePath = join(fullPath, file); const fileStat = statSync(filePath); if (fileStat.isFile()) { const content = readFileSync(filePath, 'utf-8'); result += `## ${file}\n\`\`\`\n${content.slice(0, 3000)}${content.length > 3000 ? '\n... (内容已截断)' : ''}\n\`\`\`\n\n`; } } } return { content: [{ type: 'text', text: result }], }; } case 'generate_commit_message': { const { diff, style = 'conventional' } = args as { diff: string; style?: string }; const stylePrompts: Record<string, string> = { conventional: '使用约定式提交格式:type(scope): description。type 可以是 feat/fix/docs/style/refactor/test/chore。', simple: '使用简洁风格:一行描述主要变更。', detailed: '使用详细风格:标题 + 空行 + 详细说明(列出所有变更点)。', }; const prompt = `请根据以下代码变更生成 Git commit message。 ${stylePrompts[style] || stylePrompts.conventional} 代码变更: \`\`\`diff ${diff.slice(0, 8000)} \`\`\` 请只输出 commit message,不要其他内容。`; const response = await orchestrator.askDynamicExpert('fast', '你是一位 Git 提交规范专家。', prompt); return { content: [{ type: 'text', text: `# 📝 推荐的 Commit Message\n\n\`\`\`\n${response}\n\`\`\`` }], }; } case 'analyze_project_structure': { const { path: projectPath = '.' } = args as { path?: string }; const fullPath = join(process.cwd(), projectPath); if (!existsSync(fullPath)) { throw new Error(`路径不存在: ${projectPath}`); } // 检测项目特征 const features: string[] = []; const techStack: string[] = []; // 检测 package.json const pkgPath = join(fullPath, 'package.json'); if (existsSync(pkgPath)) { const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')); features.push('Node.js 项目'); const deps = { ...pkg.dependencies, ...pkg.devDependencies }; if (deps.react) techStack.push('React'); if (deps.vue) techStack.push('Vue'); if (deps.angular) techStack.push('Angular'); if (deps.next) techStack.push('Next.js'); if (deps.express) techStack.push('Express'); if (deps.nestjs || deps['@nestjs/core']) techStack.push('NestJS'); if (deps.typescript) techStack.push('TypeScript'); if (deps.tailwindcss) techStack.push('TailwindCSS'); } // 检测其他配置文件 if (existsSync(join(fullPath, 'tsconfig.json'))) features.push('TypeScript 配置'); if (existsSync(join(fullPath, 'docker-compose.yml')) || existsSync(join(fullPath, 'Dockerfile'))) features.push('Docker 支持'); if (existsSync(join(fullPath, '.github'))) features.push('GitHub Actions'); if (existsSync(join(fullPath, 'pyproject.toml')) || existsSync(join(fullPath, 'requirements.txt'))) features.push('Python 项目'); if (existsSync(join(fullPath, 'Cargo.toml'))) features.push('Rust 项目'); if (existsSync(join(fullPath, 'go.mod'))) features.push('Go 项目'); // 统计目录结构 const dirs = readdirSync(fullPath).filter(f => { const stat = statSync(join(fullPath, f)); return stat.isDirectory() && !f.startsWith('.') && f !== 'node_modules'; }); const analysis = `# 🏗️ 项目结构分析 ## 项目类型 ${features.length > 0 ? features.map(f => `- ${f}`).join('\n') : '- 未识别'} ## 技术栈 ${techStack.length > 0 ? techStack.map(t => `- ${t}`).join('\n') : '- 未检测到常用框架'} ## 目录结构 ${dirs.map(d => `- 📁 ${d}/`).join('\n') || '- (空目录)'} ## 建议 ${techStack.includes('React') ? '- 前端任务可分配给 **frontend** 专家' : ''} ${techStack.includes('Express') || techStack.includes('NestJS') ? '- 后端任务可分配给 **backend** 专家' : ''} ${features.includes('TypeScript 配置') ? '- 项目使用 TypeScript,专家应输出类型安全的代码' : ''} ${features.includes('Docker 支持') ? '- 部署相关任务可考虑添加 **devops** 自定义专家' : ''}`; return { content: [{ type: 'text', text: analysis }], }; } case 'list_workflows': { const workflows = workflowManager.listWorkflows(); const list = workflows.map(w => { const stepsCount = w.steps.filter(s => s.type === 'expert').length; return `### ${w.name} (\`${w.id}\`) ${w.description} - **触发词**: ${w.triggers.join(', ')} - **步骤数**: ${stepsCount} 个专家步骤 - **流程**: ${w.steps.filter(s => s.type === 'expert').map(s => s.name).join(' → ')}`; }).join('\n\n'); return { content: [{ type: 'text', text: `# 📋 可用工作流模板\n\n${list}\n\n---\n> 使用 \`run_workflow\` 执行指定工作流,或使用 \`suggest_workflow\` 自动推荐` }], }; } case 'run_workflow': { const { workflow: workflowId, task, context } = args as { workflow: string; task: string; context?: string }; const workflow = workflowManager.getWorkflow(workflowId); if (!workflow) { throw new Error(`工作流不存在: ${workflowId}`); } // 转换为 Tech Lead 格式 const { experts } = workflowManager.toTaskAnalysis(workflow, task); const startTime = Date.now(); const progressLogs: string[] = []; orchestrator.setProgressCallback((message, progress) => { const timestamp = new Date().toLocaleTimeString(); const progressStr = progress ? ` (${progress}%)` : ''; progressLogs.push(`[${timestamp}]${progressStr} ${message}`); }); // 使用工作流执行任务 progressLogs.push(`📋 使用工作流: ${workflow.name}`); progressLogs.push(`👥 创建 ${experts.length} 位专家: ${experts.map((e: { name: string }) => e.name).join(', ')}`); const result = await orchestrator.execute(task, context); const duration = Date.now() - startTime; // 保存到历史 historyManager.save({ task: `[${workflow.name}] ${task}`, summary: result.summary, experts: result.outputs.map(o => o.expertId), outputs: result.outputs.map(o => ({ expertId: o.expertId, expertName: o.expertName, content: o.content, })), conversation: result.conversation.map(m => ({ from: m.from, content: m.content, type: m.type, })), duration, }); const progressText = `\n\n---\n📊 **执行过程**:\n${progressLogs.join('\n')}\n⏱️ 总耗时: ${(duration / 1000).toFixed(1)}s`; return { content: [{ type: 'text', text: `# 🔄 ${workflow.name} 执行结果\n\n${result.summary}${progressText}` }], }; } case 'suggest_workflow': { const { task } = args as { task: string }; const matched = workflowManager.matchWorkflow(task); if (matched) { const stepsDesc = matched.steps .filter(s => s.type === 'expert') .map((s, i) => `${i + 1}. **${s.name}** - ${s.expert?.role.slice(0, 50)}...`) .join('\n'); return { content: [{ type: 'text', text: `# 💡 推荐工作流 ## ${matched.name} (\`${matched.id}\`) ${matched.description} ### 执行步骤 ${stepsDesc} ### 触发原因 任务包含关键词: ${matched.triggers.filter(t => task.toLowerCase().includes(t.toLowerCase())).join(', ')} --- > 使用 \`run_workflow\` 执行此工作流: > \`{ "workflow": "${matched.id}", "task": "${task.slice(0, 50)}..." }\`` }], }; } else { return { content: [{ type: 'text', text: `# 💡 工作流推荐 未找到匹配的预定义工作流。 **建议**: 使用 \`team_work\` 让 Tech Lead 动态分析任务并创建专家团队。 **可用工作流**: - \`code-generation\` - 代码生成(写、创建、实现) - \`bug-fix\` - Bug 修复(修复、错误、fix) - \`refactoring\` - 代码重构(重构、优化) - \`code-review\` - 代码审查(审查、review) - \`documentation\` - 文档生成(文档、doc)` }], }; } } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); return server; } /** * 格式化团队执行结果为 Markdown * @param result - 团队执行结果 * @returns 格式化的 Markdown 字符串 */ function formatTeamResult(result: TeamResult): string { const sections: string[] = []; // 任务总结 sections.push(`## 📋 任务总结\n\n${result.summary}`); // 各专家产出 for (const output of result.outputs) { sections.push(`## 👤 ${output.expertName}\n\n${output.content}`); } // 生成的文件列表 const allFiles = result.outputs.flatMap((o) => o.files ?? []); if (allFiles.length > 0) { const fileList = allFiles.map((f) => `- \`${f.path}\``).join('\n'); sections.push(`## 📁 生成的文件\n\n${fileList}`); } return sections.join('\n\n---\n\n'); } /** * 启动 MCP Server * 使用 stdio 传输与 Claude Code 通信 */ export async function startServer(): Promise<void> { const server = await createServer(); const transport = new StdioServerTransport(); await server.connect(transport); console.error('Claude Team MCP Server 已启动'); }

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/7836246/claude-team-mcp'

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