mcp-gorev-asistani
MCP Ассистент задач
Обучающий проект, работающий как один сервис Docker Compose: отправляет
сообщения пользователя LLM в Groq, позволяя модели управлять списком задач
в памяти (in-memory) с помощью пяти MCP-инструментов (list_tasks,
list_tasks_by_priority, create_task, update_task, delete_task).
Каждая задача имеет поле priority (срочность: низкий/средний/высокий).
Что он делает?
Вы отправляете сообщение на естественном языке на эндпоинт POST /chat
(например, «Отметь задачу Docker как выполненную»). Чат-сервер передаёт
это сообщение в Groq вместе со схемами 5 доступных MCP-инструментов. При
необходимости модель может вызывать инструменты последовательно (например,
сначала list_tasks, чтобы найти id); каждый вызов проверяется на
соответствие JSON Schema, выполняется через реальный MCP-сервер, а
результат снова показывается модели. В итоге возвращается ответ на
естественном языке и видимый след (trace) всего процесса.
Related MCP server: MCP Project Manager
Архитектура
Два отдельных процесса Node.js, в одном контейнере, общаются через stdio по JSON-RPC:
[app sureci] [mcp-server sureci]
Express (/chat) (child process, stdio ile baslatiliyor)
|- groq/ --HTTP--> Groq API
`- mcp-client/ --stdio/JSON-RPC--> mcp-server/ --> task-store/Файл | Ответственность |
| CRUD задач, хранилище в памяти на основе |
| Превращает task-store в 5 MCP-инструментов с JSON Schema, слушает stdio+JSON-RPC |
| Запускает mcp-server как дочерний процесс, держит единственное (singleton) соединение |
| Отправляет запросы в Groq, преобразование MCP-схем в формат инструментов Groq |
| Эндпоинт |
Установка и запуск
1) Получите API-ключ Groq
Перейдите на https://console.groq.com/keys и войдите.
Нажмите «Create API Key», чтобы создать новый ключ, назовите его как угодно (например,
mcp-gorev-asistani).Скопируйте показанный ключ (
gsk_...) — он больше не будет показан.
2) Создайте файл .env
cp .env.example .envОткройте файл .env и вставьте свой ключ в конец строки GROQ_API_KEY=.
Примечание: значение
GROQ_MODELсо временем может меняться — Groq периодически удаляет и добавляет модели. Чтобы увидеть актуальный список:curl -s https://api.groq.com/openai/v1/models -H "Authorization: Bearer $GROQ_API_KEY"
3) Запуск через Docker Compose
docker compose up --build -dДля просмотра логов:
docker compose logs -fКогда увидите строку Chat sunucusu http://localhost:3000 adresinde calisiyor. — всё готово (порт 3000 внутри контейнера, наружу открыт через compose.yaml как 3001 — если порт 3000 на вашей машине занят, можно изменить строку ports в compose.yaml).
Для остановки:
docker compose downТестовые сообщения
curl -X POST http://localhost:3001/chat -H "Content-Type: application/json" \
-d '{"message": "Hangi görevlerim var?"}'
curl -X POST http://localhost:3001/chat -H "Content-Type: application/json" \
-d '{"message": "JSON Schema öğrenmek için bir görev ekle."}'
curl -X POST http://localhost:3001/chat -H "Content-Type: application/json" \
-d '{"message": "Docker görevini tamamlandı olarak işaretle."}'
curl -X POST http://localhost:3001/chat -H "Content-Type: application/json" \
-d '{"message": "Tamamlanan görevi sil."}'Пример ответа (3-е сообщение — обратите внимание, что id сначала находится
через list_tasks, а затем передаётся в update_task):
{
"answer": "\"Docker Compose kur\" görevi tamamlandı olarak işaretlendi.",
"trace": [
{ "tool": "list_tasks", "arguments": {}, "validation": "passed",
"result": { "tasks": [ { "id": 1, "title": "MCP sartnamesini oku", "completed": false },
{ "id": 2, "title": "Docker Compose kur", "completed": false },
{ "id": 3, "title": "Groq API anahtarini al", "completed": true } ] } },
{ "tool": "update_task", "arguments": { "completed": true, "id": 2 }, "validation": "passed",
"result": { "id": 2, "title": "Docker Compose kur", "completed": true } }
]
}4-е сообщение («Удали выполненную задачу.») во время тестирования показало интересное поведение: поскольку в начальных данных уже была выполненная задача (id=3), а после 5-го сообщения появилась ещё одна выполненная задача (id=2), модель оказалась перед выбором из двух вариантов и вместо того, чтобы угадывать, спросила пользователя, какую именно он имеет в виду — не вызвав ни одного инструмента. Это ожидаемое/желаемое поведение проекта (не удалить не ту задачу), а не ошибка.
Часто задаваемые вопросы
Почему добавление нового инструмента (например, list_tasks_by_priority) потребовало изменения только 2 файлов?
Потому что слои app, mcp-client и groq вообще не хардкодят
инструменты — app при каждом запросе спрашивает mcp-server через
listMcpTools() «что у тебя есть» и передаёт полученный список в Groq
как есть. То есть для определения нового инструмента достаточно добавить
(1) логику в task-store и (2) схему в mcp-server — всё остальное
подхватывается автоматически. Это конкретное воплощение решения «разделить
ответственности» из Шага 1.
Почему нет базы данных, а используются данные в памяти?
Техническое задание сознательно этого требует: проект нацелен на обучение
протоколу MCP и потоку вызова инструментов, а постоянное хранение
(persistence) — отдельная тема, которая добавила бы лишнюю сложность.
Map + начальные данные дают поведение «начинай с чистого состояния при
каждом запуске» бесплатно.
Почему Docker Compose, разве одной команды node было бы недостаточно?
Docker устраняет проблему «у меня работало» и гарантирует, что проект
работает одинаково на любой машине. Compose же делает сервисы (даже если
здесь сервис один) стандартными и запускаемыми одной командой — это
упражнение, приближенное к реальным продакшн-установкам.
Зачем нужна проверка JSON Schema, разве нельзя было довериться Groq?
Вывод LLM недетерминирован — модель иногда может генерировать аргументы
с пропусками или неверными типами. Если идти напрямую в task-store без
проверки через ajv, это может привести к неожиданным ошибкам или
несогласованным данным. Проверка — это кодовая реализация принципа
«не доверяй LLM, проверяй».
Почему определения инструментов помещаются в поле tools, а не в системное сообщение?
Поле tools — это структурированный контракт в API Groq/OpenAI: модель
воспринимает их как реальные, вызываемые функции и генерирует ответ в
структурированном формате tool_calls. Если бы мы написали их простым
текстом в системном сообщении, модель читала бы их лишь как контекст, без
гарантии и структуры вызова.
Почему mcp-client не перезапускает mcp-server при каждом запросе? task-store живёт в памяти процесса mcp-server. Если бы при каждом запросе запускался новый процесс, данные каждый раз сбрасывались бы к начальным — изменения, сделанные в предыдущем сообщении, терялись бы. Поэтому mcp-client поддерживает ЕДИНСТВЕННОЕ соединение с mcp-server (singleton), пока жив процесс app.
Почему одного вызова Groq недостаточно, зачем нужен цикл (loop)? Когда пользователь говорит «Отметь задачу Docker», модель не знает её id:
сначала нужно вызвать
list_tasks, чтобы найти правильный id, а затем вызвать инструмент, выполняющий основное действие, с этим id. Это означает несколько последовательных вызовов инструментов в рамках одного запроса; фиксированный поток «спроси-выполни-расскажи» этого не поддерживает, нужен настоящий цикл.
Известные недостатки / моменты, не готовые к продакшену
Нет постоянства: Если контейнер перезапускается (или падает / передеплоивается), все данные задач теряются. Для реального использования нужна база данных (Postgres, SQLite и т.п.).
Нет разделения пользователей/сессий: Все пользователи используют один и тот же task-store; изоляции между пользователями (multi-tenancy) нет.
Нет памяти разговора: Каждый запрос
/chatначинается независимо. Пользователь не может ссылаться на предыдущие сообщения («удали и её тоже») — контекст сохраняется только в пределах цикла инструментов одного запроса.Только один одновременный вызов инструмента: Даже если модель запрашивает несколько инструментов в одном ходе (параллельные
tool_calls), обрабатывается только первый.Нет аутентификации/авторизации: Эндпоинт
/chatоткрыт для всех, никакого контроля доступа нет.Нет ограничения размера ввода / лимита скорости (rate limiting): Злонамеренные или ошибочные клиенты могут отправлять неограниченное количество запросов, и счёт Groq может соответственно вырасти.
Схема Ajv перекомпилируется при каждом запросе:
ajv.compile(...)можно было бы кэшировать для производительности (в малых масштабах это незаметно).Название модели может устареть со временем: Каталог моделей Groq меняется (в ходе этого проекта
llama-3.3-70b-versatileбыла удалена) —GROQ_MODELследует периодически проверять.
This server cannot be deployed
Maintenance
Related MCP Connectors
Manage Superlist tasks and lists in plain language from any MCP-compatible AI agent.
Local-first task manager: create, edit, and complete tasks, projects, and checklists via MCP.
Create, list, and complete todo items through MCP.
- DazbenchOAuthapp.dazbench
Task management your AI agents can actually run. One line becomes a context-ready task over MCP.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceA simple, powerful Todo list manager for Claude Desktop and other MCP-compatible AI assistants. Organize your tasks across different projects with priorities and never lose track of what needs to be done!15 npm2MIT
- FlicenseAqualityDmaintenanceEnables task management (create, list, update tasks with priority and status) using SQLite storage via MCP tools.3-
- FlicenseNot gradedqualityDmaintenanceA task manager MCP server that demonstrates all three MCP primitives (tools, resources, prompts). Enables users to manage tasks, read task summaries and details, and run structured planning/review prompts through natural language.-
- AlicenseNot gradedqualityAmaintenanceMCP server for Riah To-Do, enabling AI to manage priorities via tools like get_priorities, replace_priorities, add_priority, set_priority_completed, and remove_priority.MIT