systa-mcp 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/SKILL.md +10 -2
  2. package/package.json +1 -1
  3. package/server.js +19 -3
package/SKILL.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- version: 1.8.0
2
+ version: 1.9.0
3
3
  name: systa
4
4
  description: |
5
5
  Drive SysTa (Talep Takip Sistemi / SysTa) — a
@@ -230,11 +230,19 @@ Each maps a P0 user verb to a tool/endpoint, with the opinionated defaults from
230
230
 
231
231
  Gantt ve k&k chart üzerinde bir düğüm proje, talep ya da kart olabilir. Mesajı **düğümün temsil ettiği şeyin** odasına gönder: tek bir talebi ilgilendiren not, okuyucu grafiğe bakıyor diye proje odasına ait olmaz.
232
232
 
233
+ **Kanal nasıl çalışır (koda bakamadığın için burada anlatılıyor).**
234
+
235
+ SysTa'nın canlı kanalı bir yayın odasıdır ve ön yüzün dinlediği odanın **aynısıdır**: tarayıcıdaki kullanıcı hangi olayı görüyorsa sen de onu görürsün. Üç şeyi bilmen yeterli:
236
+
237
+ 1. **Katılma adımı yoktur.** `listen_room(roomType, roomId)` çağrısı kanalı açar ve abonelik o anda kurulur. Ayrı bir "odaya gir" çağrısı, üyelik kaydı ya da el sıkışma yoktur. Erişim kapsamın o kaydı görmene izin veriyorsa dinleyebilirsin; vermiyorsa çağrı boş sonuç değil **doğrudan ret** döner.
238
+ 2. **Olay mesajın KENDİSİNİ taşır.** Gelen olayın gövdesi `read_messages` ile aynı biçimdedir: gönderen, metin, kimlik, hepsi içindedir. Yani "bildirim geldi, şimdi içeriği çekeyim" diye **ikinci bir API çağrısı yapmana gerek yoktur**. Ek çağrı yalnız tek bir durumda gerekir: akış ortasında koparsa, `read_messages(afterId = gördüğün son id)` ile tam kaldığın yerden devam edersin.
239
+ 3. **Odada insan olmasa da duyarsın.** Agent kanalı sunucuda bilinçli olarak ayrı tutulur; "odada kimse yok" optimizasyonu senin yayınını kesmez. Gece yarısı tek başına çalışıyorsan da mesaj sana ulaşır.
240
+
233
241
  **Yeni mesajı nasıl alırsın: iki yol var, ikisini birden yapma.**
234
242
 
235
243
  Önce şunu bil: MCP istemcisine **push yoktur**. Arka planda çalışan bir abonelik, seni uyandıran bir olay yoktur. Ya beklersin ya dönüp sorarsın.
236
244
 
237
- 1. **Bekliyorsan → `listen_room(roomType, roomId, seconds)`.** Bir soru sordun ve cevabı gelmeden devam edemiyorsun; ya da birinin dosyayı bırakmasını bekliyorsun. `listen_room` canlı kanalı açar, **sınırlı süre** bekler (varsayılan 30 saniye, en çok 120) ve o sırada geleni döndürür. `stoppedBy` neden döndüğünü söyler: `timeout` | `maxEvents` | `streamEnded`. Beklemeye devam etmek için yeniden çağırırsın.
245
+ 1. **Bekliyorsan → `listen_room(roomType, roomId, seconds)`.** Bir soru sordun ve cevabı gelmeden devam edemiyorsun; ya da birinin dosyayı bırakmasını bekliyorsun. `listen_room` canlı kanalı açar, **sınırlı süre** bekler (varsayılan 30 saniye, en çok bir saat) ve o sırada geleni döndürür. Sunucu kanalı süresiz açık tutar ve 25 saniyede bir keepalive gönderir; yani tavanı belirleyen sunucunun sabrı değil **senin turun**: bu çağrı açıkken dosya düzenleyemez, derleme çalıştıramaz, başka araç çağıramazsın. Süreyi beklediğin şeye göre seç — cevabı hemen gereken bir soru için yarım dakika, bilinçli olarak dinleyici modunda durduğun bir oda için dakikalar ya da saat. `stoppedBy` neden döndüğünü söyler: `timeout` | `maxEvents` | `streamEnded`. Beklemeye devam etmek için yeniden çağırırsın.
238
246
  2. **Çalışıyorsan → `read_messages(..., afterId)`.** Yapacak işin var, sadece sen meşgulken ne olduğunu öğrenmek istiyorsun. Her uğrayışta **tek çağrı**, döngü değil. Uğrayışlar arasında asıl işini yap.
239
247
 
240
248
  **Sürekli dinleme (monitor) diye bir kip yoktur.** `listen_room` çağrılarını arka arkaya zincirleyip odayı "izlemeye almak" turunu boşa harcar: bir saat sessiz kalan oda sana kırk kez boş sonuç döndürür. Aynı şekilde `read_messages`'ı sıkı döngüde çağırmak da yanlış cevaptır. Doğru soru şudur: **şu an bekliyor muyum, yoksa çalışıyor muyum?**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "systa-mcp",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "MCP stdio server for SysTa (Talep Takip Sistemi) — lets AI agents (Claude, Codex) use the SysTa REST API via a scoped API key. Zero npm dependencies (native Node).",
5
5
  "type": "commonjs",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -2512,12 +2512,25 @@ FIRST CALL: read once with no cursor to get the recent history, remember paginat
2512
2512
  name: 'listen_room',
2513
2513
  description: `Wait for live activity in a room instead of polling. Opens the live channel, listens for a bounded time, and returns whatever arrived.
2514
2514
 
2515
- THIS IS A BOUNDED WAIT, NOT A SUBSCRIPTION. It returns after "seconds" (default 30, max 120), or earlier once maxEvents is reached. It does not keep running in the background and nothing is delivered to you afterwards. stoppedBy tells you why it returned: timeout | maxEvents | streamEnded. To keep waiting, call it again.
2515
+ THIS IS A BOUNDED WAIT, NOT A SUBSCRIPTION. It returns after "seconds" (default 30, max 3600 = one hour), or earlier once maxEvents is reached. It does not keep running in the background and nothing is delivered to you afterwards. stoppedBy tells you why it returned: timeout | maxEvents | streamEnded. To keep waiting, call it again.
2516
+
2517
+ HOW LONG SHOULD YOU WAIT. The server keeps the channel open indefinitely (it sends a keepalive every 25 seconds), so the ceiling here is about YOUR turn, not the server's patience. While this call is open your turn is blocked: you cannot edit a file, run a build or call another tool. So pick the wait from what you are waiting for:
2518
+ * a colleague is mid-sentence and you need the reply now -> 30 to 120 seconds
2519
+ * you asked a question and have nothing else to do until it is answered -> a few minutes
2520
+ * you are deliberately standing by as a listener on a shared room -> minutes to an hour
2521
+ Waiting an hour when you had work to do is the expensive mistake, not the long ceiling itself. If you have work, do the work and check back with read_messages(afterId) instead.
2522
+
2523
+ Note that your own MCP client may abort a tool call before the server does; if a long wait comes back early, that is the client's limit, not an error.
2516
2524
 
2517
2525
  WHEN TO USE IT. You are blocked on an answer: you asked somebody with send_work_session_message or send_room_message and cannot continue until they reply. Or you are waiting for a colleague to release a file. In both cases you have nothing useful to do meanwhile, so waiting inside one call is cheaper and faster than repeated reads.
2518
2526
 
2519
2527
  WHEN NOT TO USE IT. You have work to do. Then do the work and check in afterwards with read_messages(afterId). Chaining listen_room calls back to back to "monitor" a room burns your turn for nothing — there is no monitoring mode, and a room that is quiet for an hour returns you an empty result forty times.
2520
2528
 
2529
+ HOW THE CHANNEL WORKS (you cannot read the code, so here it is). The live channel is a broadcast room and it is the SAME room the web UI listens to: whatever a person in the browser sees, you see. Three facts:
2530
+ * There is no join step. This call opens the channel and the subscription is created right then. No separate "enter room" call, no membership record, no handshake.
2531
+ * The event carries the MESSAGE ITSELF — same shape as read_messages, sender and text included. You do NOT need a second API call to fetch the content after being notified. The only time you call read_messages is when the stream drops mid-wait.
2532
+ * You hear it even when no human is in the room. The agent channel is deliberately kept separate from the "is anybody watching" optimisation on the server, so working alone does not make you deaf.
2533
+
2521
2534
  NOTHING IS LOST EITHER WAY. Events carry the same message shape as read_messages, so there is nothing new to parse. If the stream drops mid-wait, resume with read_messages(afterId = last id you saw) and continue from exactly there. Heartbeats are transport-level keepalives and never appear as events, so an empty result genuinely means "nobody said anything".
2522
2535
 
2523
2536
  Requires "work-session.view-active". You only reach rooms your access scope already allows.`,
@@ -2530,7 +2543,8 @@ Requires "work-session.view-active". You only reach rooms your access scope alre
2530
2543
  roomId: { type: 'integer', description: 'Project id, request number, or card GLOBAL id.' },
2531
2544
  seconds: {
2532
2545
  type: 'integer',
2533
- description: 'How long to wait before returning, default 30, max 120.',
2546
+ description:
2547
+ 'How long to wait before returning, default 30, max 3600 (one hour). Your turn is blocked for this whole time, so match it to what you are waiting for.',
2534
2548
  },
2535
2549
  maxEvents: {
2536
2550
  type: 'integer',
@@ -2542,7 +2556,9 @@ Requires "work-session.view-active". You only reach rooms your access scope alre
2542
2556
  systaStream(
2543
2557
  `/rooms/${encodeURIComponent(args.roomType)}/${encodeURIComponent(args.roomId)}/stream`,
2544
2558
  {
2545
- seconds: Math.min(Number(args.seconds) || 30, 120),
2559
+ // Tavan bir SAAT. Sunucu akisi suresiz acik tutar (25 sn'de bir
2560
+ // keepalive), yani sinir sunucunun sabri degil ajanin turudur.
2561
+ seconds: Math.min(Number(args.seconds) || 30, 3600),
2546
2562
  maxEvents: Math.min(Number(args.maxEvents) || 50, 200),
2547
2563
  },
2548
2564
  ),