Skip to main content
Glama

MCP Görev Asistanı

Kullanıcı mesajlarını Groq'taki bir LLM'e gönderen, LLM'in beş MCP aracını (list_tasks, list_tasks_by_priority, create_task, update_task, delete_task) kullanarak bellek içi (in-memory) bir görev listesini yönetmesini sağlayan, tek bir Docker Compose servisi olarak çalışan öğretici bir proje. Her görevin bir priority (aciliyet: düşük/orta/ yüksek) alanı vardır.

Ne yapıyor?

POST /chat ucuna doğal dilde bir mesaj gönderiyorsun (örn. "Docker görevini tamamlandı işaretle"). Chat sunucusu bu mesajı Groq'a, elindeki 5 MCP aracının şemasıyla birlikte gönderiyor. Model gerekirse (id bulmak için önce list_tasks gibi) art arda araç çağırabiliyor; her çağrı JSON Schema'ya karşı doğrulanıyor, gerçek MCP sunucusu üzerinden çalıştırılıp sonucu tekrar modele gösteriliyor. Sonunda doğal dil cevabı ve tüm sürecin görünür bir izini (trace) birlikte dönüyor.

Related MCP server: MCP Project Manager

Mimari

İki ayrı Node.js süreci, aynı container içinde, stdio üzerinden JSON-RPC ile konuşuyor:

[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/

Dosya

Sorumluluk

src/task-store

Görev CRUD'u, Map tabanlı bellek içi depo, seed veri

src/mcp-server

task-store'u JSON Schema'lı 5 MCP aracına çevirir, stdio+JSON-RPC dinler

src/mcp-client

mcp-server'i child process başlatır, tek (singleton) bağlantı tutar

src/groq

Groq'a istek atar, MCP şema -> Groq tool formatı dönüşümü

src/app

/chat endpoint'i, araç çağırma döngüsü, ajv doğrulama, trace üretimi

Kurulum ve çalıştırma

1) Groq API anahtarı al

  1. https://console.groq.com/keys adresine git, giriş yap.

  2. "Create API Key" ile yeni bir anahtar oluştur, ismini istediğin gibi ver (örn. mcp-görev-asistanı).

  3. Gösterilen anahtarı (gsk_...) kopyala - bir daha gösterilmiyor.

2) .env dosyasını oluştur

cp .env.example .env

.env dosyasını açıp GROQ_API_KEY= satırının sonuna anahtarını yapıştır.

Not: GROQ_MODEL değeri zaman içinde değişebilir - Groq zaman zaman modelleri kaldırıp yenilerini ekliyor. Güncel listeyi görmek için: curl -s https://api.groq.com/openai/v1/models -H "Authorization: Bearer $GROQ_API_KEY"

3) Docker Compose ile çalıştır

docker compose up --build -d

Logları izlemek için:

docker compose logs -f

Chat sunucusu http://localhost:3000 adresinde çalışıyor. satırını görünce hazır demektir (container içi port 3000, dışarıya compose.yaml üzerinden 3001 olarak açılıyor - kendi makinende 3000 meşgulse compose.yaml'daki ports satırını değiştirebilirsin).

Durdurmak için:

docker compose down

Deneme mesajları

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."}'

Örnek cevap (3. mesaj - id'nin önce list_tasks ile bulunup sonra update_task'a geçirildiğine dikkat et):

{
  "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 } }
  ]
}
  1. mesaj ("Tamamlanan görevi sil.") test sırasında ilginç bir davranış gösterdi: seed veride zaten tamamlanmış bir görev olduğu için (id=3) ve

  2. mesajdan sonra bir tane daha tamamlanmış görev (id=2) oluştuğu için, model iki seçenek arasında kaldı ve tahmin etmek yerine kullanıcıya hangisini kastettiğini sordu - hiçbir araç çağırmadan. Bu, projenin beklenen/istenen bir davranışı (yanlış görevi silmemek), hata değil.

Sık sorulan sorular

Yeni bir araç (örn. list_tasks_by_priority) eklemek neden sadece 2 dosyayı değiştirmemi gerektirdi? Çünkü app, mcp-client ve groq katmanları araçları HİÇ sabit kodlamıyor (hardcode) - app her istekte listMcpTools() ile mcp-server'a "elinde ne var" diye soruyor, dönen listeyi olduğu gibi Groq'a aktarıyor. Yani yeni bir araç tanımlamak için sadece (1) task-store'a mantığı, (2) mcp-server'a şemayı eklemek yeterli - geri kalan her şey otomatik akıyor. Bu, Adım 1'deki "sorumlulukları ayır" kararının somut karşılığı.

Neden veritabanı yok, bellek içi veri kullanıldı? Şartname bunu bilinçli olarak istiyor: proje MCP protokolünü ve araç çağırma akışını öğretmeyi hedefliyor, kalıcı depolama (persistence) ayrı bir konu ve gereksiz karmaşıklık katardı. Map + seed veri, "her başlangıçta temiz bir durumdan başla" davranışını bedavaya veriyor.

Neden Docker Compose, tek bir node komutu yeterli değil miydi? Docker, "bende çalışıyordu" sorununu ortadan kaldırıp projenin herhangi bir makinede aynı şekilde çalışmasını garanti ediyor. Compose ise servisleri (burada tek servis olsa da) standart, tek komutla başlatılabilir hale getiriyor - gerçek dünyadaki kurulumlara yakın bir alıştırma.

Neden JSON Schema doğrulaması var, Groq'a güvenmek yetmez miydi? LLM çıktısı deterministik değil - model bazen eksik/yanlış tipte argümanlar üretebilir. ajv ile doğrulamadan doğrudan task-store'a gitmek, beklenmedik hatalara veya tutarsız veriye yol açabilir. Doğrulama, LLM'e "güvenme, kontrol et" ilkesinin kod karşılığı.

Araç tanımları neden sistem mesajına değil tools alanına konuyor? tools alanı, Groq/OpenAI API'sinde yapılandırılmış (structured) bir sözleşme - model bunu gerçek, çağrılabilir fonksiyonlar olarak görür ve cevabı da yapılandırılmış tool_calls formatında üretir. Sistem mesajına düz metin olarak yazsak, model bunu sadece bağlam olarak okur, çağırma garantisi/yapısı olmazdı.

mcp-client neden mcp-server'i her istekte yeniden başlatmıyor? task-store, mcp-server sürecinin RAM'inde yaşıyor. Her istekte yeni bir süreç başlatılsaydı, veri her seferinde seed'e dönerdi - önceki mesajda yapılan değişiklikler kaybolurdu. Bu yüzden mcp-client, app süreci ayakta olduğu sürece TEK bir mcp-server bağlantısını (singleton) koruyor.

Neden tek bir Groq çağrısı yetmiyor, döngü (loop) gerekiyor? Kullanıcı "Docker görevini işaretle" dediği de model onun id'sini bilmez

  • önce list_tasks çağırıp doğru id'yi bulması, sonra asıl işlemi yapan aracı o id ile çağırması gerekir. Bu, tek istekte birden fazla ardışık araç çağrısı demektir; sabit "sor-çalıştır-anlat" akışı bunu desteklemez, gerçek bir döngü gerekir.

Bilinen eksikler / production'a hazır olmayan noktalar

  • Kalıcılık yok: Container yeniden başlarsa (ya da çöker/yeniden deploy edilirse) tüm görev verisi kaybolur. Gerçek kullanımda bir veritabanı (Postgres, SQLite, vs.) gerekir.

  • Çoklu kullanıcı / oturum ayrımı yok: Tüm kullanıcılar aynı task-store'u paylaşır; kullanıcılar arası izolasyon (multi-tenancy) yok.

  • Konuşma hafızası yok: Her /chat isteği bağımsız başlar. Kullanıcı önceki mesajlara atıfta bulunamaz ("onu da sil" gibi) - sadece aynı istek içindeki araç döngüsü boyunca bağlam korunur.

  • Tek eşzamanlı araç çağrısı: Model aynı turda birden fazla araç istese bile (paralel tool_calls), sadece ilki işleniyor.

  • Kimlik doğrulama / yetkilendirme yok: /chat ucu herkese açık, hiçbir erişim kontrolü yok.

  • Girdi boyutu / hız sınırı (rate limiting) yok: Kötü niyetli ya da hatalı istemciler sınırsızca istek gönderebilir, Groq faturası buna göre şişebilir.

  • Ajv şeması her istekte yeniden derleniyor: ajv.compile(...) performans için önbelleklenebilirdi (küçük ölçekte fark etmiyor).

  • Model adı zamanla eskiyebilir: Groq'un model kataloğu değişiyor (bu proje sırasında llama-3.3-70b-versatile kaldırılmış oldu) - GROQ_MODEL periyodik olarak kontrol edilmeli.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    A 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 npm
    2
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    A 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.
    -