mcp-gorev-asistani
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-gorev-asistaniList all high priority tasks"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Gorev Asistani
A tutorial project running as a single Docker Compose service that sends user messages to an LLM on Groq, letting the LLM manage an in-memory task list using five MCP tools (list_tasks, list_tasks_by_priority, create_task, update_task, delete_task). Each task has a priority field (urgency: low/medium/high).
What does it do?
You send a natural-language message to the POST /chat endpoint (e.g. "mark the Docker task as completed"). The chat server sends this message to Groq along with the schemas of the 5 MCP tools it has. The model can call tools in sequence if needed (e.g. list_tasks first to find an id); each call is validated against JSON Schema, executed through the real MCP server, and the result is shown back to the model. Finally, a natural-language reply and a visible trace of the whole process are returned together.
Related MCP server: MCP Project Manager
Architecture
Two separate Node.js processes, inside the same container, talk over stdio via 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/File | Responsibility |
| Task CRUD, |
| Turns task-store into 5 MCP tools with JSON Schema, listens on stdio+JSON-RPC |
| Starts mcp-server as a child process, keeps a single (singleton) connection |
| Sends requests to Groq, converts MCP schemas -> Groq tool format |
|
|
Installation and running
1) Get a Groq API key
Go to https://console.groq.com/keys and sign in.
Create a new key with "Create API Key", give it any name you like (e.g.
mcp-gorev-asistani).Copy the displayed key (
gsk_...) - it won't be shown again.
2) Create the .env file
cp .env.example .envOpen the .env file and paste your key at the end of the GROQ_API_KEY= line.
Note: The
GROQ_MODELvalue may change over time - Groq occasionally removes models and adds new ones. To see the current list:curl -s https://api.groq.com/openai/v1/models -H "Authorization: Bearer $GROQ_API_KEY"
3) Run with Docker Compose
docker compose up --build -dTo watch the logs:
docker compose logs -fWhen you see the line Chat server is running at http://localhost:3000 it's ready (port 3000 inside the container, exposed to the outside as 3001 via compose.yaml - if port 3000 is busy on your machine, you can change the ports line in compose.yaml).
To stop:
docker compose downTest messages
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."}'Example response (3rd message - note that the id is first found with list_tasks and then passed to 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 } }
]
}The 4th message ("Delete the completed task.") showed an interesting behavior during testing: since the seed data already had a completed task (id=3) and after the 5th message another completed task (id=2) existed, the model was torn between the two options and asked the user which one they meant instead of guessing - without calling any tool. This is an expected/desired behavior of the project (not deleting the wrong task), not a bug.
Frequently asked questions
Why did adding a new tool (e.g. list_tasks_by_priority) only require me to change 2 files?
Because the app, mcp-client, and groq layers don't hardcode the tools at all - app asks mcp-server "what do you have" via listMcpTools() on every request and passes the returned list straight to Groq. So to define a new tool you only need to (1) add the logic to task-store and (2) add the schema to mcp-server - everything else flows automatically. This is the concrete payoff of the "separate responsibilities" decision in Step 1.
Why is there no database, why in-memory data?
The spec deliberately asks for this: the project aims to teach the MCP protocol and the tool-calling flow; persistence is a separate topic and would add unnecessary complexity. Map + seed data gives you the "start from a clean state on every launch" behavior for free.
Why Docker Compose, wasn't a single node command enough?
Docker eliminates the "it worked on my machine" problem and guarantees the project runs the same way on any machine. Compose makes the services (even though there's only one here) standard and startable with a single command - an exercise close to real-world setups.
Why JSON Schema validation, couldn't we just trust Groq?
LLM output isn't deterministic - the model can sometimes produce missing/wrong-typed arguments. Going straight to task-store without validating with ajv could lead to unexpected errors or inconsistent data. Validation is the code equivalent of the "don't trust, verify" principle applied to the LLM.
Why are tool definitions placed in the tools field rather than the system message?
The tools field is a structured contract in the Groq/OpenAI API - the model sees it as real, callable functions and produces its response in the structured tool_calls format. If we wrote it as plain text in the system message, the model would only read it as context, with no guarantee/structure for calling.
Why doesn't mcp-client restart mcp-server on every request? task-store lives in the RAM of the mcp-server process. If a new process were started on every request, the data would reset to seed each time - changes made in previous messages would be lost. That's why mcp-client keeps a SINGLE mcp-server connection (singleton) as long as the app process is alive.
Why isn't a single Groq call enough, why is a loop needed? When the user says "mark the Docker task", the model doesn't know its id
it first needs to call
list_tasksto find the right id, then call the tool that does the actual work with that id. This means multiple sequential tool calls in a single request; a fixed "ask-run-tell" flow doesn't support this, a real loop is needed.
Known limitations / not production-ready points
No persistence: If the container restarts (or crashes/is redeployed), all task data is lost. Real usage would need a database (Postgres, SQLite, etc.).
No multi-user / session separation: All users share the same task-store; there's no isolation between users (multi-tenancy).
No conversation memory: Each
/chatrequest starts independently. The user can't refer to previous messages (like "delete that one too") - context is only kept during the tool loop within the same request.Single concurrent tool call: Even if the model requests multiple tools in the same turn (parallel
tool_calls), only the first one is processed.No authentication / authorization: The
/chatendpoint is open to everyone, with no access control.No input size / rate limiting: Malicious or buggy clients can send unlimited requests, and the Groq bill can grow accordingly.
Ajv schema is recompiled on every request:
ajv.compile(...)could be cached for performance (doesn't matter at small scale).Model name can become outdated over time: Groq's model catalog changes (during this project
llama-3.3-70b-versatilewas removed) -GROQ_MODELshould be checked periodically.
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