# MCP Tools Architecture — Team Board **Версия:** 1.0 **Дата:** 2026-02-23 **Автор:** Winston (BMAD) --- ## 1. Исследование MCP ### Что такое MCP Model Context Protocol (MCP) — открытый стандарт для подключения AI приложений к внешним системам. MCP работает как "USB-C для AI" — стандартизированный способ подключения ИИ к данным, инструментам и рабочим процессам. **Архитектура клиент-сервер:** - **MCP Host** (AI приложение): Управляет одним или множеством MCP клиентов - **MCP Client**: Поддерживает соединение с MCP сервером и получает контекст - **MCP Server**: Программа, предоставляющая контекст MCP клиентам **Двухуровневая архитектура:** 1. **Data layer** (Протокол данных): - JSON-RPC 2.0 для коммуникации клиент-сервер - Управление жизненным циклом, capabilities negotiation - Основные примитивы: Tools, Resources, Prompts 2. **Transport layer** (Транспорт): - **STDIO**: Прямое соединение между процессами (локальные серверы) - **HTTP Streamable**: HTTP POST с Server-Sent Events (удаленные серверы) ### Ключевые концепции MCP **Серверные примитивы:** - **Tools**: Выполняемые функции (например, API вызовы, операции с файлами) - **Resources**: Источники данных для контекста (содержимое файлов, записи БД) - **Prompts**: Шаблоны для взаимодействия с языковыми моделями **Клиентские примитивы:** - **Sampling**: Запрос language model completion от клиента - **Elicitation**: Запрос дополнительной информации от пользователя - **Logging**: Отправка логов для отладки **Lifecycle Management:** 1. Инициализация соединения 2. Negotiation capabilities через handshake 3. Динамическое обнаружение tools через `tools/list` 4. Выполнение tools через `tools/call` 5. Real-time уведомления о изменениях --- ## 2. Анализ текущей архитектуры Picogent ### Как работает сейчас Picogent — агент для Team Board с архитектурой: ``` Picogent Agent ├── WebSocket Transport (WsClientTransport) ├── REST Client (TrackerClient) ├── Event Router (EventRouter) └── Claude API Integration ``` **Текущий стек:** - **Transport**: WebSocket для событий + REST для мутаций - **Events**: `task.assigned`, `message.new` → обработка через EventRouter - **Actions**: Только REST API через TrackerClient - **LLM**: Прямая интеграция с Claude API (Anthropic SDK) ### Интеграционные точки 1. **Agent.json конфигурация:** ```json { "capabilities": ["coding", "review"], "chat_listen": "mentions", "task_listen": "assigned" } ``` 2. **EventRouter обрабатывает:** - `task.assigned` → запускает `runAgent()` - `message.new` → отвечает если упомянут 3. **TrackerClient предоставляет REST методы:** - Tasks: `listTasks()`, `takeTask()`, `updateTask()` - Messages: `sendMessage()`, `listMessages()` - Projects: `listProjects()`, `getProject()` ### Ограничения текущего подхода - **Монолитный EventRouter**: Вся логика в одном классе - **Hardcoded инструменты**: REST методы зашиты в код агента - **Нет tool discovery**: ИИ не знает какие действия доступны - **Сложное расширение**: Добавление новых действий требует изменения кода --- ## 3. Решение: MCP vs Function Calling ### Сравнение подходов | Критерий | MCP Server | Function Calling | Рекомендация | |----------|-----------|------------------|-------------| | **Стандартизация** | ✅ Открытый стандарт | ❌ Зависит от LLM провайдера | MCP | | **Совместимость** | ✅ Любые MCP hosts | ❌ Только Claude/OpenAI | MCP | | **Tool Discovery** | ✅ Динамический `tools/list` | ❌ Статичные definitions | MCP | | **Real-time updates** | ✅ Notifications | ❌ Нет | MCP | | **Сложность реализации** | ⚠️ Средняя (протокол) | ✅ Простая (JSON schema) | Function Calling | | **Готовые SDK** | ✅ Python, TypeScript | ❌ Самописные | MCP | ### Гибридный подход — рекомендация **Используем Function Calling с MCP-совместимой архитектурой:** 1. **Tool definitions** в формате совместимом с MCP 2. **Простая реализация** без полного MCP сервера 3. **Готовность к миграции** на полный MCP в будущем **Обоснование:** - **Прагматизм**: Function calling проще реализовать и отладить - **Быстрый результат**: Не нужен отдельный MCP сервер - **Совместимость**: Структуры данных готовы для MCP - **Эволюция**: Легко мигрировать на полный MCP позже --- ## 4. Каталог инструментов ### 4.1 Tasks (Задачи) | Tool Name | Description | Parameters | Returns | |-----------|-------------|------------|---------| | `list_tasks` | Список задач с фильтрацией | `project_id?`, `status?`, `assignee?`, `labels?` | `TaskOut[]` | | `get_task` | Получить задачу по ID | `task_id: string` | `TaskOut` | | `create_task` | Создать новую задачу | `project_slug: string`, `title: string`, `description?`, `type?`, `priority?`, `assignee_slug?` | `TaskOut` | | `update_task` | Обновить поля задачи | `task_id: string`, `title?`, `status?`, `priority?`, `assignee_slug?` | `TaskOut` | | `take_task` | Взять задачу себе (атомарно) | `task_id: string`, `agent_slug: string` | `TaskOut` | | `reject_task` | Отклонить задачу с причиной | `task_id: string`, `reason: string` | `{ok: true, reason: string}` | | `assign_task` | Назначить задачу другому | `task_id: string`, `assignee_slug: string` | `TaskOut` | | `watch_task` | Подписаться на уведомления | `task_id: string`, `agent_slug: string` | `{ok: true, watchers: string[]}` | **Пример tool definition:** ```json { "name": "take_task", "title": "Взять задачу в работу", "description": "Атомарно назначить задачу агенту, если она свободна", "inputSchema": { "type": "object", "properties": { "task_id": {"type": "string", "description": "ID или ключ задачи (TE-15)"}, "agent_slug": {"type": "string", "description": "Slug агента"} }, "required": ["task_id", "agent_slug"] } } ``` ### 4.2 Steps (Этапы задач) | Tool Name | Description | Parameters | Returns | |-----------|-------------|------------|---------| | `list_steps` | Этапы задачи | `task_id: string` | `StepOut[]` | | `add_step` | Добавить этап в чеклист | `task_id: string`, `title: string` | `StepOut` | | `complete_step` | Отметить этап выполненным | `task_id: string`, `step_id: string` | `StepOut` | | `update_step` | Обновить название этапа | `task_id: string`, `step_id: string`, `title?: string`, `done?: boolean` | `StepOut` | ### 4.3 Messages (Сообщения и комментарии) | Tool Name | Description | Parameters | Returns | |-----------|-------------|------------|---------| | `send_message` | Отправить сообщение в чат или комментарий к задаче | `content: string`, `chat_id?: string`, `task_id?: string`, `mentions?: string[]` | `MessageOut` | | `list_messages` | Получить сообщения | `chat_id?: string`, `task_id?: string`, `limit?: number` | `MessageOut[]` | | `reply_message` | Ответить в треде | `parent_id: string`, `content: string` | `MessageOut` | **Unified Message модель** — одна сущность для: - **Chat messages**: `chat_id` заполнен - **Task comments**: `task_id` заполнен - **Thread replies**: `parent_id` заполнен ### 4.4 Projects (Проекты) | Tool Name | Description | Parameters | Returns | |-----------|-------------|------------|---------| | `list_projects` | Список активных проектов | - | `ProjectOut[]` | | `get_project` | Информация о проекте | `slug: string` | `ProjectOut` | ### 4.5 Members (Участники) | Tool Name | Description | Parameters | Returns | |-----------|-------------|------------|---------| | `list_members` | Участники проекта | - | `MemberOut[]` | | `get_member` | Информация об участнике | `slug: string` | `MemberOut` | | `update_my_status` | Обновить свой статус | `status: string` | `{status: string}` | ### 4.6 Files (Файлы) — будущие | Tool Name | Description | Parameters | Returns | |-----------|-------------|------------|---------| | `upload_file` | Загрузить файл к сообщению | `message_id: string`, `filename: string`, `content: base64` | `AttachmentOut` | | `list_files` | Файлы задачи/проекта | `task_id?: string`, `project_id?: string` | `AttachmentOut[]` | | `download_file` | Скачать файл | `attachment_id: string` | `{filename: string, content: base64}` | --- ## 5. Архитектура реализации ### 5.1 Компонентная структура ``` picogent/ ├── src/ │ ├── tools/ # MCP-совместимые tools │ │ ├── registry.ts # Реестр всех tools │ │ ├── tasks.ts # Task tools │ │ ├── messages.ts # Message tools │ │ ├── projects.ts # Project tools │ │ └── members.ts # Member tools │ ├── mcp/ │ │ ├── types.ts # MCP-совместимые типы │ │ ├── tool-executor.ts # Выполнение tools │ │ └── tool-builder.ts # Построение tool definitions │ ├── agent.ts # Интеграция с Claude + tools │ └── router.ts # Обновлённый EventRouter ``` ### 5.2 Tool Registry (Центральный реестр) ```typescript // tools/registry.ts export interface ToolDefinition { name: string; title: string; description: string; inputSchema: JSONSchema; handler: (params: any, context: ToolContext) => Promise; } export interface ToolContext { trackerClient: TrackerClient; agentSlug: string; transport: WsClientTransport; } export class ToolRegistry { private tools = new Map(); register(tool: ToolDefinition): void { this.tools.set(tool.name, tool); } list(): ToolDefinition[] { return Array.from(this.tools.values()); } async execute(name: string, params: any, context: ToolContext): Promise { const tool = this.tools.get(name); if (!tool) throw new Error(`Tool not found: ${name}`); return tool.handler(params, context); } } ``` ### 5.3 Task Tools Implementation ```typescript // tools/tasks.ts import { ToolDefinition } from './registry.js'; export const takeTaskTool: ToolDefinition = { name: 'take_task', title: 'Взять задачу в работу', description: 'Атомарно назначить задачу агенту, если она свободна', inputSchema: { type: 'object', properties: { task_id: { type: 'string', description: 'ID задачи' }, agent_slug: { type: 'string', description: 'Slug агента' } }, required: ['task_id', 'agent_slug'] }, async handler(params, context) { try { const result = await context.trackerClient.takeTask( params.task_id, params.agent_slug ); return { content: [{ type: 'text', text: `✅ Задача ${result.key} взята в работу` }], structuredContent: result }; } catch (error) { return { content: [{ type: 'text', text: `❌ Ошибка: ${error.message}` }], isError: true }; } } }; export const listTasksTool: ToolDefinition = { name: 'list_tasks', title: 'Список задач', description: 'Получить список задач с фильтрацией', inputSchema: { type: 'object', properties: { project_id: { type: 'string', description: 'ID проекта' }, status: { type: 'string', enum: ['backlog', 'todo', 'in_progress', 'in_review', 'done'] }, assignee: { type: 'string', description: 'Slug исполнителя' } } }, async handler(params, context) { const tasks = await context.trackerClient.listTasks(params); return { content: [{ type: 'text', text: `Найдено задач: ${tasks.length}\n${tasks.map(t => `- ${t.key}: ${t.title} (${t.status})`).join('\n')}` }], structuredContent: tasks }; } }; ``` ### 5.4 Интеграция с Claude ```typescript // agent.ts (модифицированный) import { ToolRegistry } from './tools/registry.js'; export async function* runAgent(prompt: string, options: AgentOptions): AsyncIterator { const toolRegistry = new ToolRegistry(); // Регистрируем все tools registerAllTools(toolRegistry); // Создаём tool definitions для Claude const tools = toolRegistry.list().map(tool => ({ name: tool.name, description: tool.description, input_schema: tool.inputSchema })); const response = await anthropic.messages.create({ model: options.model, messages: [{ role: 'user', content: prompt }], tools, system: options.systemPrompt }); // Обрабатываем tool calls for (const content of response.content) { if (content.type === 'tool_use') { const result = await toolRegistry.execute( content.name, content.input, { trackerClient: options.trackerClient, agentSlug: options.agentSlug } ); yield { type: 'text', content: result.content?.[0]?.text || 'Tool executed', sessionId: options.sessionId }; } else { yield { type: 'text', content: content.text, sessionId: options.sessionId }; } } } ``` ### 5.5 Обновлённый EventRouter ```typescript // router.ts (упрощённый) export class EventRouter { constructor( private config: AgentConfig, private toolRegistry: ToolRegistry, private taskTracker: TaskTracker, ) {} async handleEvent(event: TrackerEvent): Promise { const context = { trackerClient: new TrackerClient(this.config.trackerUrl, this.config.token), agentSlug: this.config.slug, transport: this.taskTracker }; switch (event.event) { case 'task.assigned': await this.handleTaskAssigned(event.data, context); break; case 'message.new': await this.handleMessageNew(event.data, context); break; } } private async handleTaskAssigned(data: any, context: ToolContext): Promise { const task = data.task || data; // Строим промпт с доступными tools const toolsDescription = this.toolRegistry.list() .map(t => `- ${t.name}: ${t.description}`) .join('\n'); const prompt = ` # Задача: ${task.key} — ${task.title} ${task.description || ''} ## Доступные инструменты: ${toolsDescription} Выполни задачу используя доступные инструменты. Начни с обновления статуса на "in_progress". `; // Запускаем агента с tools for await (const msg of runAgent(prompt, { toolRegistry: this.toolRegistry, agentSlug: this.config.slug, trackerClient: context.trackerClient })) { // Логируем результат console.log(`Agent output: ${msg.content}`); } } } ``` ### 5.6 Структура файлов ``` picogent/ ├── src/ │ ├── tools/ │ │ ├── registry.ts # Центральный реестр tools │ │ ├── tasks.ts # 8 task tools │ │ ├── steps.ts # 4 step tools │ │ ├── messages.ts # 3 message tools │ │ ├── projects.ts # 2 project tools │ │ ├── members.ts # 3 member tools │ │ └── index.ts # Export всех tools │ ├── mcp/ │ │ ├── types.ts # MCP-совместимые типы │ │ └── executor.ts # Tool execution engine │ ├── tracker/ │ │ ├── client.ts # REST client (существующий) │ │ └── types.ts # Tracker API types │ ├── transport/ │ │ └── ws-client.ts # WebSocket transport (существующий) │ ├── agent.ts # Модифицированный для tools │ ├── router.ts # Упрощённый EventRouter │ └── index.ts # Точка входа ├── package.json # + @anthropic-ai/sdk dependency └── agent.json # Конфигурация (существующая) ``` --- ## 6. План реализации ### Phase 1: Базовая инфраструктура tools (Неделя 1) **День 1-2: Создание Tool Registry** - [ ] `src/tools/registry.ts` — интерфейсы и реестр - [ ] `src/mcp/types.ts` — MCP-совместимые типы - [ ] Тесты для registry **День 3-4: Интеграция с Claude** - [ ] Модификация `agent.ts` для поддержки tools - [ ] Tool execution pipeline - [ ] Error handling для tool calls **День 5-7: Базовые Task Tools** - [ ] `take_task`, `list_tasks`, `get_task` - [ ] Интеграция с существующим TrackerClient - [ ] Тестирование на простых задачах ### Phase 2: Полный набор tools (Неделя 2) **День 1-3: Все Task и Step Tools** - [ ] Реализация всех 8 task tools - [ ] 4 step tools для чеклистов - [ ] Валидация параметров и ошибок **День 4-5: Message Tools** - [ ] `send_message`, `list_messages`, `reply_message` - [ ] Поддержка unified модели (чат + комментарии) **День 6-7: Project и Member Tools** - [ ] Project tools: `list_projects`, `get_project` - [ ] Member tools: `list_members`, `update_my_status` - [ ] Интеграционные тесты ### Phase 3: Продвинутые возможности (Неделя 3) **День 1-2: Обновлённый EventRouter** - [ ] Рефакторинг router.ts под tools - [ ] Улучшенная обработка `task.assigned` - [ ] Dynamic tool discovery **День 3-4: Error Handling и Reliability** - [ ] Robust error handling в tools - [ ] Retry logic для API calls - [ ] Graceful degradation **День 5-7: Документация и тесты** - [ ] Tool documentation - [ ] Integration tests - [ ] Performance тесты ### Phase 4: Готовность к MCP миграции (Неделя 4) **День 1-3: MCP Compatibility Layer** - [ ] Full MCP tool definitions format - [ ] MCP server skeleton (не активный) - [ ] Migration path documentation **День 4-5: Production Deploy** - [ ] Deploy обновлённого Picogent - [ ] Monitoring и логирование - [ ] Performance optimization **День 6-7: Итерации на основе feedback** - [ ] Bug fixes - [ ] UX improvements - [ ] Documentation updates ### Критерии готовности **Phase 1 Complete:** - ✅ Агент может взять задачу используя `take_task` tool - ✅ Список задач через `list_tasks` tool работает - ✅ Error handling для недоступных tools **Phase 2 Complete:** - ✅ Все 20 tools реализованы и работают - ✅ Агент может выполнить полный цикл: взять задачу → добавить этапы → обновить статус → прокомментировать **Phase 3 Complete:** - ✅ Production-ready качество кода - ✅ Comprehensive error handling - ✅ Full integration test suite **Phase 4 Complete:** - ✅ MCP-compatible архитектура - ✅ Готовность к миграции на полный MCP сервер - ✅ Документация для developers --- ## Заключение **Выбранный подход** — гибридная архитектура с Function Calling в MCP-совместимом формате — даёт нам: 1. **Быстрый результат**: Можно реализовать за 3-4 недели 2. **Простота**: Не требует отдельного MCP сервера 3. **Гибкость**: 20+ tools покрывают все операции Tracker API 4. **Масштабируемость**: Tool Registry легко расширяется 5. **Будущее**: Готовность к миграции на полный MCP **Ключевые преимущества:** - **Dynamic tool discovery**: ИИ знает какие действия доступны - **Structured error handling**: Понятные ошибки для self-correction - **Unified architecture**: Все операции через единый интерфейс - **MCP compatibility**: Готовность к стандарту будущего Team Board получает полнофункциональных агентов с богатым набором инструментов для автономной работы с задачами, проектами и командой.