docs: MCP Tools Architecture

This commit is contained in:
Markov 2026-02-23 20:44:37 +01:00
parent 34e932842e
commit d3b9aead96

585
MCP-TOOLS-ARCHITECTURE.md Normal file
View File

@ -0,0 +1,585 @@
# 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<any>;
}
export interface ToolContext {
trackerClient: TrackerClient;
agentSlug: string;
transport: WsClientTransport;
}
export class ToolRegistry {
private tools = new Map<string, ToolDefinition>();
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<any> {
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<AgentMessage> {
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<void> {
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<void> {
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 получает полнофункциональных агентов с богатым набором инструментов для автономной работы с задачами, проектами и командой.