systa-mcp 1.0.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 (4) hide show
  1. package/README.md +163 -0
  2. package/SKILL.md +187 -0
  3. package/package.json +34 -0
  4. package/server.js +2226 -0
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # SysTa MCP Server
2
+
3
+ Bir [Model Context Protocol](https://modelcontextprotocol.io) (MCP) stdio sunucusu.
4
+ Claude gibi AI ajanlarının, kullanıcının profilinden ürettiği **scoped API anahtarı**
5
+ ile SysTa REST API'sini "araç" olarak kullanmasını sağlar.
6
+
7
+ - **Sıfır npm bağımlılığı** — native Node (18+ global `fetch`) + JSON-RPC 2.0 (stdio).
8
+ - **Güvenlik sunucu tarafında** — tüm scope/izin zorlaması backend'dedir. MCP yalnızca
9
+ `Authorization: Bearer <key>` + `X-Vendor-Code` ile isteği proxy'ler; anahtarın kapsamı
10
+ dışındaki çağrılar backend tarafından `403` ile reddedilir.
11
+
12
+ ## Kurulum
13
+
14
+ Anahtarı SysTa'da **Ayarlar → API Anahtarları → Yeni Anahtar** ile üretin (scope'ları
15
+ seçin; anahtar yalnızca o anda gösterilir). Anahtar **self-routing**'tir: vendor bilgisi
16
+ anahtarın içine gömülüdür, backend vendor'ı anahtardan çözer — nötr (subdomain'siz) bir
17
+ API adresi yeterlidir.
18
+
19
+ ### Claude Code (önerilen — npx, dosya indirmeden)
20
+
21
+ ```bash
22
+ claude mcp add systa \
23
+ -e SYSTA_API_KEY=sk_live_... \
24
+ -e SYSTA_API_BASE_URL=https://systa.example.com/api \
25
+ -- npx -y systa-mcp
26
+ ```
27
+
28
+ İstemci skill'ini (trigger phrase'ler, varsayılanlar, progressive disclosure) tek
29
+ komutla kur:
30
+
31
+ ```bash
32
+ npx -y systa-mcp --install-skill # -> ~/.claude/skills/systa/SKILL.md
33
+ ```
34
+
35
+ ### Çevre değişkenleri
36
+
37
+ | Değişken | Örnek | Açıklama |
38
+ | ------------------------ | ------------------------------- | --------------------------------------------------------------------------------------------------- |
39
+ | `SYSTA_API_BASE_URL` | `https://systa.example.com/api` | API kök adresi (`/api` dahil), nötr host |
40
+ | `SYSTA_API_KEY` | `sk_live_<vendor>_...` | Profilden üretilen anahtar (bir kez gösterilir) |
41
+ | `SYSTA_VENDOR_CODE` | `vizyoneks` | OPSIYONEL — verilirse anahtarın vendor'ıyla aynı olmalı; boş bırakılırsa backend anahtardan türetir |
42
+ | `SYSTA_MCP_STRICT_TOOLS` | `1` | OPSIYONEL — kapsam çözülemezse tüm aksiyon araçlarını gizle (fail-closed) |
43
+
44
+ ### Yerel geliştirme / yerel klona karşı
45
+
46
+ ```bash
47
+ claude mcp add systa \
48
+ -e SYSTA_API_KEY=sk_live_... \
49
+ -e SYSTA_API_BASE_URL=http://vizyoneks.localhost:3000/api \
50
+ -- node /path/to/Backend/mcp-server/server.js
51
+ ```
52
+
53
+ ### Komutlar
54
+
55
+ | Komut | İşlev |
56
+ | --------------------------- | ------------------------------------------------------ |
57
+ | `systa-mcp` | MCP stdio sunucusunu çalıştırır (Claude Code kullanır) |
58
+ | `systa-mcp --install-skill` | Gömülü skill'i `~/.claude/skills/systa/`'ya kopyalar |
59
+ | `systa-mcp --version` | Sürümü yazar |
60
+ | `systa-mcp --help` | Yardım |
61
+
62
+ ## Araçlar (tools)
63
+
64
+ Toplam **44 araç** vardır; `tools/list` yanıtı anahtarın kapsamına göre filtrelenir
65
+ (bkz. "Scope-aware araç listesi"). Aşağıdakiler en sık kullanılan çekirdek araçlardır —
66
+ tam katalog `list_capabilities` ile keşfedilir.
67
+
68
+ | Araç | Açıklama |
69
+ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
70
+ | `list_requests` | Talepleri listele (limit/offset/search/statusId) — `request.read` |
71
+ | `get_request` | Tek bir talebi id ile getir — `request.read` |
72
+ | `list_projects` | Projeleri listele — `project.read` |
73
+ | `create_request` | Talep oluştur (title/description/companyId/statusId/assignedTo) — `request.create` |
74
+ | `add_request_comment` | Talebe yorum ekle (düz metin otomatik TipTap'e sarılır) — `request.comment.create` + `request.tabs.comments.view` |
75
+ | `systa_api_call` | Genel REST çağrısı (diğer endpoint'ler); kapsam sunucu tarafında zorlanır |
76
+ | `download_request_file` | Dosya ekini (talep/görev kartı/proje) YEREL diske indirir, kaydedilen yolu döner — `file.download` |
77
+ | `upload_file_to` | Yerel dosyaları multipart olarak ek diye yükler (talep/proje/görev kartı/orphan) — `file.upload` |
78
+ | `list_capabilities` | **Bu anahtar ne yapabilir?** — scope-filtreli modül/endpoint kataloğu (yetkisiz endpoint görünmez); her metot için safety class + gereken izin. Ayrıca SysTa platform özeti (overview), TR glossary ve her modülün açıklamasını içerir |
79
+ | `describe_module` | Bir modülün (örn. request/kanban/plan) amacı, kavramları ve çağrılabilir endpoint'leri — kullanıcı niyetini doğru modüle eşlemek için (oryantasyon) |
80
+ | `describe_endpoint` | Tek endpoint detayı: alan tipleri (fields), güvenlik sınıfı, açıklama — çağrı gövdesini kurmadan önce |
81
+
82
+ `systa_api_call` ile, özel bir aracı olmayan herhangi bir endpoint çağrılabilir
83
+ (örn. `POST /requests`, `POST /requests/42/comments`). Anahtarın scope'u dışındaki
84
+ çağrılar `403` döner.
85
+
86
+ ### Dosya ekleri (download_request_file / upload_file_to)
87
+
88
+ `systa_api_call` JSON-only olduğundan binary taşıyamaz — dosya ekleri için bu iki
89
+ araç kullanılır. Tüm erişim/güvenlik kontrolleri (izin, şirket erişimi, uzantı/MIME
90
+ allowlist, magic byte, rate limit) **sunucu tarafında** çalışır.
91
+
92
+ - **`download_request_file`** — `{ fileId, savePath? }`: `GET /files/:id/download` çağırır,
93
+ binary'yi yerel diske yazar. `savePath` verilmezse OS temp dizinine
94
+ (`systa-mcp-downloads/`) kaydeder; mevcut bir dizin verilirse içine, dosya yolu
95
+ verilirse o yola yazar. Dönen değer: `savedPath`, `fileName`, `mimeType`, `sizeBytes`.
96
+ Gereken scope: `file.download`.
97
+ - **`upload_file_to`** — `{ path, filePaths[], method? }`: multipart (`file` alanı) yükleme.
98
+ Yaygın hedefler: `/requests/:requestNumber/files` (talep eki),
99
+ `/projects/:projectId/files` (proje dosyası),
100
+ `/requests/:requestId/kanban/cards/:cardId/files` (görev kartı eki),
101
+ `/files/orphan-upload` (alt form ön-yükleme). Mevcut dosyayı değiştirmek için
102
+ `method: "PUT"` + `/requests/:n/files/:id` (tek dosya). Gereken scope: `file.upload`.
103
+ Executable/script uzantıları sunucu tarafından reddedilir.
104
+
105
+ `file.download` ve `file.upload` yıkıcı sayılmadığından `*` / `file.*` wildcard
106
+ scope'larına dahildir; `file.delete` ise yalnızca açık scope ile verilebilir.
107
+
108
+ ### Keşfedilebilirlik (discoverability)
109
+
110
+ Sunucu, `initialize` yanıtında bir **server-seviye rehber** (`instructions`) döner:
111
+ ajana scope semantiğini (`*`/`domain.*` wildcard, `.delete` istisnası), güvenlik
112
+ sınıflarını ve "önce `list_capabilities`, sonra `describe_endpoint`" akışını öğretir.
113
+ Böylece AI ajan, anahtarın **gerçekte neler yapabileceğini** (kategori + özet + alan
114
+ tipleri + güvenlik sınıfı) kendi keşfeder — kapsam dışı yüzey sızmaz.
115
+
116
+ Endpoint-bazlı detayın yanında, `list_capabilities` bir **kavramsal oryantasyon katmanı**
117
+ da döner (DB: `ai_orientation_catalog`): SysTa platform özeti (`overview`), TR **glossary**
118
+ (talep/görev/efor/pano/durum… → modül/kavram) ve her modülün **açıklaması** (`description` +
119
+ `concepts`). Bu sayede kod tabanına hiç erişimi olmayan bir ajan, kullanıcının doğal dilini
120
+ doğru modül ve endpoint'e eşleyebilir. `describe_module(module)` tek bir modülü topluca verir.
121
+
122
+ ### Scope-aware araç listesi (tools/list)
123
+
124
+ `tools/list` yanıtı da anahtarın kapsamına göre filtrelenir: bir named tool yalnızca
125
+ anahtar o aracın gerektirdiği izne sahipse listelenir. **Kapsam dışı araçlar ajana hiç
126
+ görünmez** — örn. yalnızca `request.create` izni olan bir anahtar yalnızca `create_request`
127
+
128
+ - `prepare_create_request` ve keşif araçlarını (`list_capabilities`, `describe_module`,
129
+ `describe_endpoint`, `systa_api_call`) görür; `update`/`delete`/kanban/plan araçları
130
+ listede yer almaz. Böylece ajan kapsam dışı bir aracı denemez (gereksiz `403` olmaz). İzin
131
+ seti, anahtarın scope-filtreli kataloğundan türetilir (tek kaynak backend; wildcard/`.delete`
132
+ mantığı orada). `SYSTA_MCP_STRICT_TOOLS=1` ile kapsam çözülemezse fail-closed davranır.
133
+
134
+ ## Manuel test (handshake)
135
+
136
+ ```bash
137
+ printf '%s\n' \
138
+ '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' \
139
+ '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
140
+ '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
141
+ | SYSTA_API_BASE_URL=http://vizyoneks.localhost:3000/api SYSTA_API_KEY=sk_live_... node server.js
142
+ ```
143
+
144
+ ## Notlar
145
+
146
+ - Anahtar süresi dolduğunda (varsayılan 90 gün) Ayarlar'dan yeni anahtar üretip env'i güncelleyin.
147
+ - Anahtar iptal edildiğinde (Ayarlar → iptal) tüm çağrılar derhal `401` döner.
148
+ - Yıkıcı işlemler (silme, toplu) için anahtara bu scope'ları **vermemeniz** önerilir.
149
+
150
+ ## Yayınlama (maintainer)
151
+
152
+ Paket sıfır bağımlılıklıdır; `files` whitelist'i yalnızca `server.js`, `SKILL.md`,
153
+ `README.md` içerir. SKILL.md kaynağı `Analiz Dökümanları/12_AI_ve_Otomasyon/systa_client_skill_TASLAK.md`'dir
154
+ — güncellenince pakete tekrar kopyalanmalıdır.
155
+
156
+ ```bash
157
+ cd Backend/mcp-server
158
+ npm pack --dry-run # tarball içeriğini doğrula (yalnız 4 dosya)
159
+ npm login # npm hesabı (publish için)
160
+ npm publish # publishConfig.access=public ile public yayınlanır
161
+ ```
162
+
163
+ Sürüm `package.json` ve `server.js` (`SERVER_VERSION`) içinde **birlikte** yükseltilir.
package/SKILL.md ADDED
@@ -0,0 +1,187 @@
1
+ ---
2
+ version: 0.1.0
3
+ name: systa
4
+ description: |
5
+ Drive SysTa (Talep Takip Sistemi / SysTa) — a
6
+ multi-tenant request, project, kanban, plan, SLA,
7
+ approval, release and reporting platform — from
8
+ Claude Code / claude.ai via its scoped API key + MCP
9
+ server. Talks user verbs ("open a request", "assign
10
+ it to me", "comment", "change status", "what's on my
11
+ plate", "start a project", "add a kanban card",
12
+ "submit plan for approval", "export a report") and
13
+ maps them to SysTa REST endpoints over the MCP
14
+ capability catalog. Use when (TR): "talep aç",
15
+ "bana/şuna ata", "yorum ekle", "durumu değiştir /
16
+ tamamla / kapat", "üzerimdeki işler", "proje aç",
17
+ "kanban kartı ekle", "onaya sun", "onayla/reddet",
18
+ "izin talebi", "rapor al / dışa aktar", "sürüm
19
+ oluştur". Use when (EN): "create a SysTa request",
20
+ "log a ticket", "assign / reassign", "add a comment",
21
+ "move/close the ticket", "show my open work", "create
22
+ project", "add task card", "request approval",
23
+ "approve/reject", "export report", "create release".
24
+ Multi-tenant (vendor schema) aware; resolves names →
25
+ ids; honors dynamic required fields. NOT for: editing
26
+ SysTa source code, running psql/DB migrations directly,
27
+ Higgsfield media generation, or any non-SysTa product.
28
+ argument-hint: '[natural-language SysTa intent] [--vendor <schema>] [--dry-run]'
29
+ allowed-tools: Bash, ToolSearch, mcp__systa__*
30
+ ---
31
+
32
+ # SysTa
33
+
34
+ Drive SysTa through its MCP server (or, where MCP is unavailable, its REST API with a scoped API key). SysTa = **Talep Takip Sistemi** (SysTa) — a multi-tenant work-management platform: requests, projects, kanban/task boards, plans/Gantt, SLAs, approvals, releases, forms, reports and admin. This skill maps **user verbs** to endpoints; it never edits SysTa's codebase and never touches the database directly.
35
+
36
+ The golden rule: **talk intent, resolve ids behind the scenes, ask the user only for what is genuinely missing, and pre-resolve dynamic required fields before submitting.**
37
+
38
+ ## Step 0 — Bootstrap
39
+
40
+ Before any SysTa action, confirm connectivity, auth and identity. Do this once per session (cache the result).
41
+
42
+ 1. **Find the connection.** Prefer the SysTa MCP server. If the deferred MCP tools aren't loaded yet, fetch their schemas:
43
+
44
+ ```
45
+ ToolSearch query: "select:mcp__systa__list_capabilities,mcp__systa__describe_endpoint"
46
+ ```
47
+
48
+ If there is no MCP server, fall back to the REST API with a scoped API key. The key is **never typed into chat** — read it from the environment / a local secret file:
49
+
50
+ ```bash
51
+ : "${SYSTA_BASE_URL:?set SYSTA_BASE_URL, e.g. https://<vendor>.systa.example.com}"
52
+ : "${SYSTA_API_KEY:?export a scoped sk_live_... key (do not paste in chat)}"
53
+ ```
54
+
55
+ 2. **Auth + identity check ("who am I").** Confirm the key/session is live and learn the caller's identity, vendor schema and permissions — this drives every default (assignee, companyId, scope):
56
+
57
+ ```bash
58
+ curl -fsS -H "Authorization: Bearer $SYSTA_API_KEY" \
59
+ "$SYSTA_BASE_URL/api/auth/me"
60
+ ```
61
+
62
+ Capture: `userId`, `companyId` (default company), `vendorSchema`, and the permission/scope set. If this returns `401`/`403` or `API key not found`, stop and tell the user the key is missing/expired/over-scoped — do **not** guess credentials.
63
+
64
+ 3. **Vendor scope.** SysTa is schema-per-vendor; every mutation runs inside the caller's vendor schema. The vendor is derived from the key/session — never inject another vendor's ids. If the user references a company/team/user, it is resolved **within** their vendor.
65
+
66
+ 4. **Decide MCP vs REST for the session.** If `list_capabilities` works, use the MCP tools for discovery (`list_capabilities` → `describe_endpoint`) and let the server enforce scope. Otherwise drive `curl` against the REST paths shown in each workflow.
67
+
68
+ If bootstrap fails, deliver a one-line reason ("anahtar süresi dolmuş", "key expired", "endpoint için yetki yok") and stop — never fabricate a result.
69
+
70
+ ## SysTa nedir / temel kavramlar (glossary)
71
+
72
+ Short shared vocabulary. Use these words with the user; never expose raw REST paths or internal jargon.
73
+
74
+ | Kavram (TR) | Concept (EN) | Ne demek |
75
+ | --------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
76
+ | Talep | Request / ticket | Core unit of work. Has `title` (min 5), `companyId`, `statusId`, priority, category, assignee, comments, files, relations. Çoğu iş bir talebin etrafında döner. |
77
+ | Durum | Status | Lifecycle state (Açık/Open, Devam Ediyor/In Progress, Tamamlandı/Done). `is_final` durumlar kapanışı temsil eder. Resolved via `GET /api/statuses`. |
78
+ | Öncelik | Priority | normal / high / critical. Belirtilmezse `normal`. |
79
+ | Kategori | Category | Talep sınıflandırması (catalog/config). |
80
+ | Yorum | Comment | Talebe eklenen not/yorum (`commentText` plain string ok). |
81
+ | Atama | Assignment | `assignedTo` = bir kullanıcı. "bana/üzerime" → mevcut `userId`. |
82
+ | Proje | Project | Talepleri kapsayan üst yapı; milestone, paydaş, sağlık/risk/SLA dashboard, alt-proje hiyerarşisi. |
83
+ | Kanban / Görev panosu | Kanban / task board | Bir talebin altında kolonlar + kartlar; kart yaşam döngüsü: oluştur → ata → taşı → tamamla. `boardId` daima bir `requestId`'ye bağlı. |
84
+ | Plan / Baseline | Plan / baseline | Talepleri Gantt'ta planlama; baseline = onaylı plan snapshot'ı; tracking = gerçeğe karşı izleme (diff/burndown/timeline). |
85
+ | SLA | SLA | Süre taahhütleri (ilk yanıt, çözüm). Instance bir talebe bağlanır; pause/resume edilebilir. |
86
+ | Onay | Approval | Toplu onaya gönderme + onayla/reddet; plan onayı ve talep onayı ayrı akışlar. |
87
+ | Sürüm | Release | Yazılım sürüm yönetimi: liste → item → onay → Go/No-Go → deployment workflow. |
88
+ | Vendor şema | Vendor schema | Multi-tenant izolasyon; her vendor ayrı schema (`vendor_xxx`). Public referans alınmaz. |
89
+
90
+ ## UX Rules
91
+
92
+ 1. **Be concise; summarize.** No raw IDs, no JSON dumps in chat. Report "Talep #1423 açıldı — 'Login hatası', sana atandı" / "Request #1423 created and assigned to you." Surface a stable handle the user recognizes (talep numarası, başlık), not internal uuids.
93
+ 2. **No jargon.** Don't narrate "calling describe_endpoint", "POST /api/requests", "resolving statusId". Speak in the product's user verbs.
94
+ 3. **Detect language and reply in it.** If the user writes Turkish, answer in Turkish; if English, English. Field keys and enum values passed to the API stay as the API expects (`statusKey`, `priority=high`) — only the conversation is localized.
95
+ 4. **Smart defaults + ask one thing at a time.** Apply opinionated defaults from the intent summary (`channel='API'`, `priority='normal'`, assignee=self for "bana", `strategy='any_one'`/`'all_required'` per module). Ask **one** genuinely-missing thing, never a batch ("ver bana başlık, şirket, durum, öncelik, kategori" YASAK). Never invent a `title`, a password, a webhook URL, or a secret — ask for those.
96
+ 5. **Resolve dynamic required fields up front.** Before a create/mutation, resolve the entity's required fields _for this vendor_ (e.g. `statusId` via `GET /api/statuses`, `companyId` from `who-am-i`, approver name → `userId` via user lookup). Don't submit a half-filled body and let it 400 — pre-resolve, then submit. Forms with dynamic schemas: pull the schema first (`get_form_schema`) so required fields are known.
97
+ 6. **Safety tiers gate confirmation.** `read_only` → just do it. `mutating`/`idempotent` → do it, then report. **`destructive`** (revoke access, delete, hard removal) and live side-effecting actions (publish, send invite, advance release workflow, test webhook) → show a one-line "şunu yapacağım" and get an explicit OK first. Publishing (announcement/release notes/product update) is **never** auto-published — show a summary, get approval.
98
+ 7. **Don't over-ask scope.** `companyId`/`userId`/`vendorSchema` come from `who-am-i`; don't ask the user for them when a single sane value exists.
99
+
100
+ ## Discovery
101
+
102
+ You don't memorize 600+ endpoints. Discover on demand.
103
+
104
+ - **`list_capabilities`** — call when you need to find _which_ module/intent serves the user's verb, or when the user asks "ne yapabilirsin / what can you do". Returns scope-filtered modules (this key's reachable surface), each with a short summary, category, safety class and required permission. Use it to pick the right tool before acting; never claim a capability the catalog doesn't list for this key.
105
+ - **`describe_endpoint`** — call when you've picked a tool and need its exact required fields, body shape, enums and defaults before submitting. Prefer this over guessing a body. It returns the field schema (`fieldKey`, type, required, enum, default) so you can pre-fill dynamic required fields and avoid `VALIDATION_FAILED`.
106
+ - **Rule of thumb:** ambiguous intent → `list_capabilities` first; chosen intent but unsure of body → `describe_endpoint`; clear intent + known body → act directly. For REST fallback, the equivalents are `GET /api/api-keys/me/capabilities` (preview of reachable endpoints) and the per-endpoint field schema returned by the MCP `describe_endpoint`.
107
+
108
+ ## Çekirdek iş akışları (core workflows)
109
+
110
+ Each maps a P0 user verb to a tool/endpoint, with the opinionated defaults from the catalog. Resolve ids first, act, then summarize in the user's language.
111
+
112
+ ### Talep aç (open a request) — `create_request` → `POST /api/requests`
113
+
114
+ 1. Need `title` (min 5 chars) — if missing or too short, ask once. Never invent it.
115
+ 2. Defaults: `channel='API'` (AI/MCP source), `companyId` ← who-am-i, `statusId` ← default open/new status (resolve via `GET /api/statuses`, pick the non-final entry status), `priority='normal'` unless the user signals "acil/critical". `description` can be a plain string.
116
+ 3. Submit; report "Talep #<num> açıldı — '<title>'". If the user also said "bana ata", chain assignment below.
117
+
118
+ ### Üzerimdeki işler / talepleri listele (what's on my plate) — `list_requests` → `GET /api/requests`
119
+
120
+ - "taleplerim / on me" → `assignedTo=<my userId>`. "açık/open" → final olmayan durumlar. Default `limit=20-50`, sort `created_at desc`, `companyId` from scope. Summarize as a short list (numara + başlık + durum), not raw rows.
121
+
122
+ ### Talep detayı (show a request) — `get_request` → `GET /api/requests/:requestNumber`
123
+
124
+ - Resolve the user's number/title to `requestNumber`. If ambiguous, `list_requests` first to find candidates, then fetch.
125
+
126
+ ### Bana / birine ata (assign) — `assign_request` → `PUT /api/requests/:requestNumber`
127
+
128
+ - "bana/üzerime" → `assignedTo=<my userId>`. A name → resolve via user lookup (`GET /api/users?search=`) to `userId`. Partial update — only send `assignedTo`.
129
+
130
+ ### Yorum ekle (comment) — `add_request_comment` → `POST /api/requests/:requestNumber/comments`
131
+
132
+ - Plain text → `commentText`. At least one of `commentText` / `commentTextJson` / `fileIds` required. No mentions unless asked.
133
+
134
+ ### Durum değiştir / tamamla / kapat (change status) — `change_request_status` → `PUT /api/requests/:requestNumber`
135
+
136
+ - "tamamla/kapat" → pick the appropriate `is_final` status (resolve via `GET /api/statuses`). A named status → resolve to `statusId`. If the user wrote a closing note, add it as a comment; if not, don't.
137
+
138
+ ### Proje aç (start a project) — `create_project` → `POST /api/projects`
139
+
140
+ - `projectCode` is auto-generated by the backend — **don't ask for it** (preview via `GET /api/projects/next-code` if needed). `companyId` ← who-am-i; dates optional. Report "Proje '<name>' oluşturuldu (kod: <code>)".
141
+
142
+ ### Projemi / projeleri gör + durum (list / health) — `list_projects` / `get_project_health`
143
+
144
+ - List: `GET /api/projects` (default `page=1, limit=20`, recent first). "durum/sağlık" → combine `health-score` + `risk-score` + `sla-status` into one summary.
145
+
146
+ ### Kanban kart ekle (add a task card) — `create_kanban_card` → `POST /api/task-boards/:boardId/cards`
147
+
148
+ - `boardId` is always tied to a `requestId` — first resolve the board via the request's kanban hierarchy (`GET /api/requests/:requestId/kanban/hierarchy`). Defaults: first/entry column if `columnId` omitted, `priority='normal'`, unassigned unless "bana ata", `cardTitle` min 3 chars (ask to clarify if shorter).
149
+
150
+ ### Kartı taşı / tamamla (move / complete card) — `move_kanban_card` / `complete_kanban_card`
151
+
152
+ - Move: `PUT /api/task-boards/:boardId/cards/:cardId/move`; resolve the target column name → `columnId` from board detail; append to end if no position given. Complete: `PUT .../complete` — server sets `isCompleted=true`, 100%.
153
+
154
+ ### Onaya sun / onayla / bekleyenler (approvals)
155
+
156
+ - Submit (request approval): `request_approval` → `POST /api/approvals/batch`, `strategy='any_one'` default, approver names → ids. Plan onayı ayrı: `submit_plan_for_approval` → `POST /api/plan/approvals/submit` (`strategy='all_required'`).
157
+ - Respond: `respond_to_approval` → `POST /api/approvals/responses/:id/respond`; "onayla"→`approved`, "reddet"→`rejected` (rette kısa sebep iste, zorunlu değil).
158
+ - Pending: `list_pending_approvals` → `GET /api/approvals/requests-awaiting` (mevcut kullanıcının onayını bekleyenler).
159
+
160
+ ### İzin talebi (leave) — `create_leave_request` → `POST /api/user-leaves`
161
+
162
+ - `userId`=self (sormadan), `leaveType='annual'`, `isHalfDay=false`, dates normalized to `YYYY-MM-DD` ("yarın/cuma" → tarih), `returnToWorkDate` = next working day after end. "izinlerim" → `list_leaves` with `userId=self`.
163
+
164
+ ### Rapor al / dışa aktar (report) — `preview_report` / `export_report`
165
+
166
+ - Önce önizle (`POST /api/reports/preview`, read-only), sonra dışa aktar (`POST /api/reports/export`, `format='xlsx'` unless "csv"). `reportType` is the required pivot (request/sla/user/organization/project/lifecycle/subform) — infer from intent. Resolve columns via `GET /api/reports/columns` if the user only named a type. "bu ay/geçen ay" → dynamic date filter.
167
+
168
+ ### Sürüm oluştur (release) — `create_release_list` → `POST /api/releases/lists`
169
+
170
+ - `releaseType='standard'`, `requireAllStakeholderApprovals=false`, `companyId` from scope. Add items with `add_release_item`. Deployment workflow steps (`close-servers` → `start-db-migration` → `start-server-update` → `open-servers` → `complete`) are live ops — **never auto-advance blindly**; show which step you're on and confirm. Release notes: generate → review → publish (never auto-publish).
171
+
172
+ ## Zincirleme & hata kurtarma (chaining & error recovery)
173
+
174
+ SysTa returns structured errors. Recover deterministically instead of giving up.
175
+
176
+ 1. **`400 VALIDATION_FAILED`** — the response carries `details[]` with `fieldKey`, message, and often `expected`/`enum`. For each entry:
177
+ - If it's a missing required field you can resolve (e.g. `statusId`, `companyId`, `categoryId`), resolve it (status list / who-am-i / category list) and **add the field, then retry once**.
178
+ - If it's a bad enum (`priority`, `decision`, `accessLevel`), map the user's word to an allowed value (`onayla→approved`, `reddet→rejected`, `acil→high`) and retry.
179
+ - If it's genuinely user-owned (a `title`, a date, an approver name, a secret), **ask the user for exactly that field** — quote the human-friendly meaning, not the raw key.
180
+ - Retry once after a fix. If it fails again with the same field, surface it to the user rather than looping.
181
+ 2. **`UNEXPECTED_FILE_FIELD` / `UNKNOWN_PARAM`** — you sent a flag/field the endpoint doesn't accept. Re-check with `describe_endpoint` and drop it. (Web/UI-only fields aren't valid on the API surface.)
182
+ 3. **`404` on a `:requestNumber` / `:id`** — the handle didn't resolve. Run the matching list/search (`list_requests`, `list_projects`, `list_users?search=`, `search_tags`) to map name/number → id, then retry. Never hard-code an id.
183
+ 4. **ID resolution chain (general).** Most mutations need an id the user gave you as a name: company → `list_companies`, team → `list_teams` (name→`teamCode`), user → `list_users?search=` (name→`userId`, "ben/bana"→self), status → `GET /api/statuses` (name→`statusId`), tag → `search_tags`, board → request's kanban hierarchy (requestId→`boardId`→`columnId`). Resolve first, act second.
184
+ 5. **`401/403`** — expired or out-of-scope key. Don't retry blindly; tell the user the auth/permission problem (in their language) and stop. For `403 permission`, name the capability the key lacks; don't attempt a privilege workaround.
185
+ 6. **`409 conflict`** (optimistic concurrency on cards/edits) — re-read the entity to get the latest `updatedAt`, then retry the mutation once with the fresh value; warn the user only if it conflicts again.
186
+ 7. **Dual-path "list vs create" endpoints** (e.g. `POST /api/sla/definitions`, `POST /api/sla/standby-configs`) — an empty/filter-only body lists; a full body creates. Choose the body shape that matches the intent; don't accidentally create when the user asked to list.
187
+ 8. **Multi-tenant safety.** Never carry an id across vendors. If a resolved id isn't found in the caller's vendor scope, treat it as not-found (step 3), not as a public-schema fallback.
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "systa-mcp",
3
+ "version": "1.0.0",
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
+ "type": "commonjs",
6
+ "main": "server.js",
7
+ "bin": {
8
+ "systa-mcp": "server.js"
9
+ },
10
+ "files": [
11
+ "server.js",
12
+ "SKILL.md",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "start": "node server.js"
17
+ },
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "model-context-protocol",
24
+ "systa",
25
+ "claude",
26
+ "ai-agent",
27
+ "talep-takip"
28
+ ],
29
+ "license": "UNLICENSED",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "homepage": "https://systa.vizyoneks.com.tr"
34
+ }