@appaflytech/zeyrek-ai-mcp 0.0.1

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 (88) hide show
  1. package/.env.example +46 -0
  2. package/README.md +260 -0
  3. package/dist/config.js +128 -0
  4. package/dist/index.js +88 -0
  5. package/dist/knowledge/componentCatalog.js +438 -0
  6. package/dist/knowledge/componentEvents.js +164 -0
  7. package/dist/knowledge/coverage.js +60 -0
  8. package/dist/knowledge/normalize.js +1309 -0
  9. package/dist/knowledge/outlines.js +167 -0
  10. package/dist/knowledge/policy.js +44 -0
  11. package/dist/knowledge/reservedTables.js +75 -0
  12. package/dist/knowledge/rules.js +1725 -0
  13. package/dist/observability/trace.js +337 -0
  14. package/dist/platform/errors.js +132 -0
  15. package/dist/platform/http.js +169 -0
  16. package/dist/platform/responses.js +94 -0
  17. package/dist/platform/token.js +79 -0
  18. package/dist/resources/examples/entity-pair-m2m.json +105 -0
  19. package/dist/resources/examples/flow-list-to-form.json +65 -0
  20. package/dist/resources/examples/flow-load-table.json +178 -0
  21. package/dist/resources/examples/microservice-table-list.json +49 -0
  22. package/dist/resources/examples/middleware-authenticate.json +194 -0
  23. package/dist/resources/examples/page-detail-profile.json +95 -0
  24. package/dist/resources/examples/page-dynamic-form.json +221 -0
  25. package/dist/resources/examples/page-form-upsert.json +279 -0
  26. package/dist/resources/examples/page-html-embed.json +106 -0
  27. package/dist/resources/examples/page-sign-in.json +194 -0
  28. package/dist/resources/examples/workflow-basic.json +94 -0
  29. package/dist/resources/guides/component.md +108 -0
  30. package/dist/resources/guides/entity.md +348 -0
  31. package/dist/resources/guides/expressions.md +139 -0
  32. package/dist/resources/guides/getting-started.md +109 -0
  33. package/dist/resources/guides/html.md +106 -0
  34. package/dist/resources/guides/microservice.md +313 -0
  35. package/dist/resources/guides/middleware.md +271 -0
  36. package/dist/resources/guides/modify-existing.md +35 -0
  37. package/dist/resources/guides/page.md +1574 -0
  38. package/dist/resources/guides/view.md +89 -0
  39. package/dist/resources/guides/workflow.md +359 -0
  40. package/dist/resources/knowledge.js +44 -0
  41. package/dist/resources/schemas/CreateDatasourceCommand.json +54 -0
  42. package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +133 -0
  43. package/dist/resources/schemas/CreateEntityCommand.json +387 -0
  44. package/dist/resources/schemas/CreateMicroserviceCommand.json +528 -0
  45. package/dist/resources/schemas/CreateQueryCommand.json +43 -0
  46. package/dist/resources/schemas/CreateViewCommand.json +158 -0
  47. package/dist/resources/schemas/CreateWorkflowCommand.json +1719 -0
  48. package/dist/resources/schemas/Filter.json +124 -0
  49. package/dist/resources/schemas/GetRowsQuery.json +122 -0
  50. package/dist/resources/schemas/PreviewMicroserviceCommand.json +565 -0
  51. package/dist/resources/schemas/PreviewQueryCommand.json +74 -0
  52. package/dist/resources/schemas/PreviewWorkflowCommand.json +981 -0
  53. package/dist/resources/schemas/StepDto.json +900 -0
  54. package/dist/resources/schemas/UpdateDatasourceCommand.json +58 -0
  55. package/dist/resources/schemas/UpdateEntityCommand.json +679 -0
  56. package/dist/resources/schemas/UpdateMicroserviceCommand.json +512 -0
  57. package/dist/resources/schemas/UpdateQueryCommand.json +86 -0
  58. package/dist/resources/schemas/UpdateViewCommand.json +153 -0
  59. package/dist/resources/schemas/UpdateWorkflowCommand.json +1719 -0
  60. package/dist/resources/schemas.js +40 -0
  61. package/dist/server.js +63 -0
  62. package/dist/tools/access.js +27 -0
  63. package/dist/tools/applications.js +59 -0
  64. package/dist/tools/automations.js +103 -0
  65. package/dist/tools/common.js +18 -0
  66. package/dist/tools/components.js +280 -0
  67. package/dist/tools/datasources.js +82 -0
  68. package/dist/tools/dependencies.js +17 -0
  69. package/dist/tools/deployments.js +17 -0
  70. package/dist/tools/dtos.js +54 -0
  71. package/dist/tools/entities.js +166 -0
  72. package/dist/tools/files.js +138 -0
  73. package/dist/tools/flows.js +226 -0
  74. package/dist/tools/folders.js +51 -0
  75. package/dist/tools/layouts.js +105 -0
  76. package/dist/tools/microservices.js +198 -0
  77. package/dist/tools/organizations.js +65 -0
  78. package/dist/tools/pages.js +597 -0
  79. package/dist/tools/platformInfo.js +44 -0
  80. package/dist/tools/projects.js +152 -0
  81. package/dist/tools/queries.js +48 -0
  82. package/dist/tools/rows.js +115 -0
  83. package/dist/tools/screens.js +97 -0
  84. package/dist/tools/templates.js +65 -0
  85. package/dist/tools/variables.js +94 -0
  86. package/dist/tools/views.js +58 -0
  87. package/dist/tools/workflows.js +196 -0
  88. package/package.json +49 -0
package/.env.example ADDED
@@ -0,0 +1,46 @@
1
+ # Platform API adresleri (host makinesinden lokal compose icin)
2
+ ORG_API_BASE_URL=http://localhost:7000
3
+ TENANT_API_BASE_URL=http://localhost:5000
4
+
5
+ # Org cozumu: istekler Host: {ORGANIZATION}.{HOST_SUFFIX} header'i ile gider
6
+ ORGANIZATION=zeyrek-local
7
+ HOST_SUFFIX=localhost
8
+
9
+ # Varsayilanlar; tool parametresi her zaman ezer
10
+ DEFAULT_ENVIRONMENT=production
11
+ DEFAULT_PROJECT=
12
+
13
+ # local: kimlik asagidaki alanlardan, passthrough: istemcinin Authorization header'i aynen gecer
14
+ # local modda ya TOKEN (hazir Bearer JWT) ya da USERNAME+PASSWORD verin
15
+ AUTH_MODE=local
16
+ TOKEN=
17
+ USERNAME=
18
+ PASSWORD=
19
+
20
+ # Politika lint'i: strict (block kurallari istegi durdurur) | warn (hepsi uyariya iner) | off
21
+ POLICY=strict
22
+
23
+ # Tool cagrisi gunlugu: her cagri okunabilir tek blok olarak dosyaya yazilir.
24
+ # detail (varsayilan) istek/yanit govdelerini de yazar | summary govdesiz | off kapali.
25
+ # LOG_FILE verilirse tek sabit dosyaya yazilir, verilmezse LOG_DIR altinda gunluk dosya
26
+ # (gateway-YYYY-AA-GG.log). Parola/token alanlari her seviyede *** ile maskelenir.
27
+ LOG_LEVEL=detail
28
+ LOG_DIR=
29
+ LOG_FILE=
30
+ LOG_MAX_BODY_CHARS=2000
31
+
32
+ # Yanit budama esigi (bayt) ve istek zaman asimi (ms)
33
+ MAX_RESPONSE_BYTES=262144
34
+ REQUEST_TIMEOUT_MS=100000
35
+
36
+ # generate-schemas icin swagger adresleri. Bos birakilirsa sirayla denenir:
37
+ # 1) asagidaki override, 2) {API_BASE_URL}/swagger/v1/swagger.json, 3) localhost:3000 frontend proxy'si
38
+ ORG_SWAGGER_URL=
39
+ TENANT_SWAGGER_URL=
40
+
41
+ # Bos = tum moduller (148 tool). Hazir kumeler: core (veri+mantik, 92), studio (sayfa
42
+ # tasarimi, 45), admin (template/organizasyon/deployment, 15). Kume ve tekil modul adi
43
+ # karisik yazilabilir. Ornek: core,studio | entity,row,microservice
44
+ MODULES=
45
+
46
+ MCP_PORT=5100
package/README.md ADDED
@@ -0,0 +1,260 @@
1
+ # ngapps-mcp-gateway
2
+
3
+ NgApps platformunu MCP tool'ları olarak sunan bağımsız gateway — veri/mantık tarafı (project,
4
+ application, datasource, entity, row, microservice, query, workflow, automation, dto, view) ve
5
+ Studio tasarım tarafı (page, component, flow, layout, variable, folder, file) birlikte, **152
6
+ tool / 24 modül**. Durum + yol haritası:
7
+ [`docs/00-durum-ve-yol-haritasi.md`](docs/00-durum-ve-yol-haritasi.md);
8
+ tasarım: [`docs/`](docs/01-vizyon-ve-kapsam.md). Platform koduna
9
+ referans vermez; iki API'yi HTTP üzerinden sarar, istekler MVC binding'den geçtiği için
10
+ FluentValidation aynen çalışır.
11
+
12
+ ## Kurulum
13
+
14
+ ```bash
15
+ cd zeyrek-mcp
16
+ npm install
17
+ cp .env.example ../.env
18
+ ```
19
+
20
+ `.env` **repo kökünde**, `.mcp.json`'ın yanında durur (kök `.gitignore`'da `/.env` ile korunur).
21
+ Sunucu şu sırayla arar, ilk bulunan anahtar kazanır: `<çalışma dizini>/.env` →
22
+ `<paket>/.env` → `<paket>/../.env`.
23
+
24
+ > `npm install` yalnız `npm run dev` için değil: repo kökündeki `.mcp.json` sunucuyu
25
+ > `zeyrek-mcp/node_modules/.bin/tsx` ile başlatır. Bağımlılıklar kurulu değilken MCP istemcisi
26
+ > **hata vermeden sıfır tool ile** bağlanır — repoyu yeni klonladıysanız ilk adım budur.
27
+
28
+ Ayarlar `.env` yerine (ya da onunla birlikte) repo kökündeki `.mcp.json`'ın `env` bloğundan da
29
+ verilebilir; env bloğu her zaman `.env`'i ezer — ayrıntı [npm paketi olarak
30
+ kurulum](#npm-paketi-olarak-kurulum). Asgari şunlar gerekir:
31
+
32
+ | Değişken | Örnek | Not |
33
+ |----------|-------|-----|
34
+ | `ORG_API_BASE_URL` | `http://localhost:7000` | Organization.API |
35
+ | `TENANT_API_BASE_URL` | `http://localhost:5000` | Tenant.API |
36
+ | `ORGANIZATION` | `zeyrek-local` | Org subdomain'i; istekler `Host: {org}.{suffix}` ile gider |
37
+ | `USERNAME` / `PASSWORD` | | `/connect/token` ile takas edilir (AuthMode=local) |
38
+ | `DEFAULT_PROJECT` | `crm` | Opsiyonel; tool'daki `project` parametresi her zaman ezer |
39
+
40
+ ## Çalıştırma
41
+
42
+ ```bash
43
+ npm run dev
44
+ ```
45
+
46
+ Sağlık: `http://localhost:5100/healthz`. Sunucu stateless streamable HTTP konuşur (`/mcp`,
47
+ yalnız POST); `npm run start:stdio` ile stdio kipi de var.
48
+
49
+ ## Tool çağrısı günlüğü
50
+
51
+ Her MCP tool çağrısı, okunmak için biçimlenmiş tek bir blok olarak dosyaya yazılır — varsayılan
52
+ `zeyrek-mcp/logs/gateway-YYYY-MM-DD.log` (günlük dosya, `.gitignore`'da). Amaç: bir çağrının ne
53
+ yapmaya çalıştığını, içeriden hangi duraklardan geçtiğini ve nerede patladığını **koda inmeden**
54
+ okuyabilmek.
55
+
56
+ ```
57
+ ┌─ #1 · 11:27:27.082 · platform_whoami — Oturum bilgisi
58
+ │ amaç : Gateway'in platformda kimin adına çalıştığını döner; auth kurulumunu doğrulamak için ilk çağrılacak tool.
59
+ │ girdi : (parametresiz)
60
+ │ adımlar:
61
+ │ +2ms kimlik → önbellekte geçerli token yok — POST http://localhost:7000/connect/token · kullanıcı admin@zeyrek.com
62
+ │ +229ms kimlik ← HTTP 200 · token alındı, önbellekte 63158340 sn geçerli
63
+ │ +229ms istek → GET http://localhost:7000/connect/userinfo · org api · env=development
64
+ │ +237ms yanıt ← HTTP 200 · 8 ms · 174 B
65
+ │ gövde: {"sub":"01917edf-…","email":"admin@zeyrek.com","role":["super-admin"]}
66
+ └─ SONUÇ : başarılı · 238 ms · 4 adım · 137 B yanıt
67
+ ```
68
+
69
+ Adım etiketleri: `politika` (lint kuralları; `politika ✕` isteği hiç göndermez), `düzeltme`
70
+ (gateway'in gövdeye uyguladığı otomatik düzeltmeler — yanıttaki `gatewayNormalized`), `kimlik →/←`
71
+ (`/connect/token` turu), `istek →/yanıt ←` (platform API turu, tam URL + süre + boyut),
72
+ `kırpma ✂` (yanıt `MAX_RESPONSE_BYTES` sınırını aştı), `hata ✕` (yakalanan hata: sınıf,
73
+ HTTP kodu, mesaj, ilk 3 stack satırı). Tool gövdesine hiç girmeyen çağrılar — yanlış tool adı ya da
74
+ parametre şemasına takılan gövde — `MCP KATMANI REDDETTİ` bloğu olarak düşer; bunlar aksi hâlde
75
+ hiçbir yerde görünmezdi.
76
+
77
+ Arama: `SONUÇ : HATA` tüm başarısız çağrılar, `hata ✕` hata satırları, `#<n>` tek bir çağrı.
78
+
79
+ | Değişken | Varsayılan | Not |
80
+ |----------|-----------|-----|
81
+ | `LOG_LEVEL` | `detail` | `detail` istek/yanıt gövdelerini de yazar · `summary` yalnız durak + boyut + hata gövdeleri · `off` hiç dosya açmaz |
82
+ | `LOG_DIR` | `zeyrek-mcp/logs` | Günlük dosyaların klasörü |
83
+ | `LOG_FILE` | — | Verilirse tek sabit dosyaya yazar (tarih döndürmesi kapanır) |
84
+ | `LOG_MAX_BODY_CHARS` | `2000` | Tek bir gövde/parametre önizlemesinin karakter sınırı |
85
+
86
+ Adı `pass|secret|token|authorization|api key|credential|connectionString` desenine uyan alanlar
87
+ `***` ile maskelenir (`girdi` satırında ve gövde önizlemelerinde). Günlükleme yazma hatası tool
88
+ çağrısını **düşürmez**: ilk hatada stderr'e tek satır yazılıp günlükleme kapatılır.
89
+
90
+ ## Claude Code kaydı
91
+
92
+ ```bash
93
+ claude mcp add ngapps --transport http http://localhost:5100/mcp
94
+ ```
95
+
96
+ stdio alternatifi (port gerekmez, sunucuyu istemci başlatır):
97
+
98
+ ```bash
99
+ claude mcp add ngapps -- npx tsx <repo>/zeyrek-mcp/src/index.ts --stdio
100
+ ```
101
+
102
+ İlk doğrulama: oturumda `platform_whoami` tool'unu çağırtın — kimlik ve org çözümü tek seferde
103
+ test edilir.
104
+
105
+ ## npm paketi olarak kurulum
106
+
107
+ Repoyu klonlamadan, yayınlanmış paketle. Tüm ayarlar `.mcp.json`'ın `env` bloğundan gelir;
108
+ `.env` dosyasına gerek yoktur:
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "ngapps": {
114
+ "type": "stdio",
115
+ "command": "npx",
116
+ "args": ["-y", "@appaflytech/zeyrek-ai-mcp@latest", "--stdio"],
117
+ "env": {
118
+ "ORG_API_BASE_URL": "http://localhost:17000",
119
+ "TENANT_API_BASE_URL": "http://localhost:15000",
120
+ "ORGANIZATION": "zeyrek-test",
121
+ "HOST_SUFFIX": "zeyrek.local",
122
+ "DEFAULT_PROJECT": "emrah",
123
+ "DEFAULT_ENVIRONMENT": "development",
124
+ "USERNAME": "admin@zeyrek.com",
125
+ "PASSWORD": "${PASSWORD}",
126
+ "MODULES": "core",
127
+ "LOG_DIR": "logs"
128
+ }
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ Ayar öncelik sırası: **`.mcp.json` env bloğu → `.env` (varsa; repo içinden çalışırken kökte
135
+ durur) → şemadaki varsayılan.** `.env.example` tüm değişkenlerin tam listesidir. npx ile kurulan
136
+ pakette `.env` yoktur, tüm ayarlar env bloğundan gelir.
137
+
138
+ - `.mcp.json` sürüm kontrolündeyse parolayı düz yazmayın: Claude Code `${PASSWORD}` ve
139
+ `${PASSWORD:-varsayılan}` genişletmesi yapar, değer kabuk ortamından gelir.
140
+ - Genişletme **istemciye bağlıdır**: Claude Code açar, VS Code'un kendi MCP istemcisi açmaz ve
141
+ metni olduğu gibi geçirir. Bu yüzden sunucu, açılmamış `${…}` yer tutucusunu boş değerle aynı
142
+ sayıp **düşürür** — ayar `.env`'den ya da şema varsayılanından doldurulur, sunucu yer tutucu
143
+ metinle patlamaz (`dropUnusableEnvironment`). Ortama göre gerçekten değişen ayarı `.env`'e
144
+ koymak her istemcide çalışan yoldur.
145
+ - Boş bırakılan (`""`) alanlar **tanımsız** sayılır; varsayılana düşer ya da `.env`'den
146
+ doldurulur. Yani `"${MODULES:-}"` yazmak alanı hiç yazmamakla aynıdır.
147
+ - Değişken adları ön eksizdir (`USERNAME`, `PASSWORD`, `TOKEN`, `LOG_LEVEL` …), yani kabuk
148
+ ortamındaki aynı adlı değişkenlerle çakışabilir — `USERNAME` Windows'ta yerleşiktir. Bu yüzden
149
+ `.mcp.json`'da `${USERNAME:-…}` gibi genişletme kullanmayın; değeri düz yazın ya da `.env`'e
150
+ koyun.
151
+ - `LOG_DIR` verilmezse günlükler **çalışma dizininin** altındaki `logs/` klasörüne yazılır.
152
+ - Konfigürasyon geçersizse sunucu stderr'e tek satır sebep yazıp `exit 1` yapar — istemci artık
153
+ sessizce sıfır tool ile bağlanmaz.
154
+
155
+ Yayınlama (paket bakımcısı için):
156
+
157
+ ```bash
158
+ cd zeyrek-mcp
159
+ npm run typecheck && npm test
160
+ npm publish # prepack: tsc -p tsconfig.build.json + varlık kopyalama
161
+ ```
162
+
163
+ `dist/` içine `src/resources/{schemas,guides,examples}` altındaki 41 JSON/MD varlığı
164
+ `scripts/copy-assets.ts` kopyalar — `tsc` tek başına bunları taşımaz.
165
+
166
+ ## Kullanım kalıpları
167
+
168
+ - **Keşif önce:** `project_list` → `project_get` (environment id'leri burada) →
169
+ `datasource_list` → `entity_list`.
170
+ - **Derin gövdeler geçirgendir:** `entity_create` / `workflow_create` / `microservice_create`
171
+ `definition` parametresini API'ye birebir geçirir. En iyi şablon, mevcut bir kaydın `*_get`
172
+ çıktısıdır; step şeması için `workflow_step_schema` kullanılır.
173
+ - **Test kası:** `microservice_execute` gerçek runtime yolunu çağırır; dönen `httpStatus`
174
+ microservice'in kendi sonucudur. Beklenmedik sonuçta aynı parametrelerle
175
+ `microservice_debug` çağırın — adım adım `executionItems` ağacı döner.
176
+ - **Asenkron işler:** `automation_trigger` fire-and-forget'tır (`automation_histories` ile
177
+ izlenir); `deployment_start` bir saga başlatır (`deployment_status` ile izlenir).
178
+ - **Sayfa tasarımı:** `layout_*` → `page_create` → `page_state` → `page_schema_patch`
179
+ (micro-op); olay akışları `flow_*` + `set_event`. Şema değişikliği `page_update` ile değil
180
+ `page_schema_patch` ile yapılır; `page_build` diye bir tool **yok** (platform ucu üründe
181
+ olmayan ayrı bir servise delege ediyor) — ayrıntı `platform_guide('page')`.
182
+ - **Yazma tool'ları replace gövdeleri merge eder:** `page_update`, `layout_update`,
183
+ `component_update` kaydı önce okur, yalnız verdiğiniz alanları değiştirir; şema/olay kaybı
184
+ olmaz. `flow_*` uçlarının istediği barındırıcı gövdesini de gateway kurar.
185
+ - Tool seti `MODULES` ile daraltılabilir: tekil modül adı (`entity,row,microservice`)
186
+ ya da hazır küme — `core` (92 tool: veri + mantık), `studio` (49 tool: sayfa tasarımı),
187
+ `admin` (15 tool: template, organizasyon, deployment). Küme ve modül adları karışık
188
+ yazılabilir: `MODULES=core,page`.
189
+
190
+ ## Bilgi katmanı (Faz 1.5)
191
+
192
+ Tasarım: [`docs/07-bilgi-katmani.md`](docs/07-bilgi-katmani.md).
193
+ Üç savunma hattı:
194
+
195
+ - **Rehberler:** `platform_guide` tool'u (workflow, microservice, entity, page, component,
196
+ html, middleware, view, expressions, getting-started, modify-existing) + `ngapps://guides/*`
197
+ resource'ları. Bir modülde ilk yazma işleminden önce ilgili rehber okunmalı; tool
198
+ açıklamaları bunu söyler. Komponent davranış bilgisi ayrıca `component_get` çıktısında
199
+ `knowledge` alanı olarak döner (`src/knowledge/componentCatalog.ts`).
200
+ - **Altın örnekler:** `ngapps://examples/*` — boş org'da şablon kaynağı. Şu an sentetik seed;
201
+ platform ayaktayken `npm run harvest-examples -- --project qm` ham hasadı
202
+ `src/resources/examples/harvested/` altına yazar, küratörlükten geçen dosyalar `examples/`
203
+ köküne taşınır.
204
+ - **Politika lint'i:** entity/microservice/workflow/automation create/update/preview gövdeleri
205
+ API'ye gitmeden `src/knowledge/rules.ts` kurallarından geçer. Block kuralları (MS-001 join'li
206
+ kaynakta boş selectFields, WF-001 kopuk step grafı, WF-002 workflow'da returnDtoId, WF-005
207
+ tip×step matrisi) isteği durdurup düzeltme önerisi döner; warn bulguları yanıta
208
+ `policyFindings` olarak eklenir. `POLICY=strict|warn|off`, çağrı başına kaçış:
209
+ `policyOverride: true`. Kural envanteri: `docs/08-kural-envanteri.md`.
210
+
211
+ ## Büyük şema erişimi
212
+
213
+ Tam gövdeyi LLM bağlamına sokmadan çalışma modeli
214
+ ([tasarım](docs/09-buyuk-sema-stratejisi.md)):
215
+
216
+ 1. `project_overview` — projenin kompakt haritası (id/ad/tip envanteri)
217
+ 2. `workflow_get` / `microservice_get` / `entity_get` + `view: 'outline'` — iskelet
218
+ 3. `view: 'part', part: 'steps[id=...]'` — tek parçanın tam hâli
219
+ 4. `workflow_patch` / `microservice_patch` / `entity_patch` — RFC 6902 işlemleri; gateway
220
+ get→patch→lint→put zincirini kendi belleğinde yürütür, yanıt outline özetidir
221
+
222
+ ## Şema kaynakları
223
+
224
+ API'ler ayaktayken:
225
+
226
+ ```bash
227
+ npm run generate-schemas
228
+ ```
229
+
230
+ Swagger'dan seçili komut şemalarını `src/resources/schemas/` altına yazar; sunucu bunları
231
+ `ngapps://schemas/*` MCP resource'ları olarak yayınlar (`ngapps://schemas/index` dizindir).
232
+ Üretilen JSON'lar klasörde durur ve gateway'le birlikte taşınır — script yalnızca yeniden
233
+ üretmek için gerekir.
234
+
235
+ Swagger adresi sırayla denenir: `ORG_SWAGGER_URL` / `TENANT_SWAGGER_URL`
236
+ override'ları → `{API_BASE_URL}/swagger/v1/swagger.json` → `localhost:3000` frontend proxy'si
237
+ (`/api/org` ve `/api`). Hangi adresin kullanıldığı çıktıda yazar.
238
+
239
+ ## Test
240
+
241
+ ```bash
242
+ npm run typecheck
243
+ npm test
244
+ ```
245
+
246
+ Testler gerçek ağa çıkmaz (undici `MockAgent`); MCP katmanı `InMemoryTransport` üzerinden
247
+ gerçek el sıkışmasıyla doğrulanır.
248
+
249
+ ## Bilinen sınırlar (PoC)
250
+
251
+ - `project_create/update` `LoaderImage` yüklemez (multipart dosya kapsam dışı; urlencoded form
252
+ kullanılır).
253
+ - `row_list.selectedFields` kırpması gateway tarafında yapılır: platform `GetRowsQuery.SelectedFields`
254
+ alanını yalnızca many-to-many alt sorgularını daraltmak için okur, skaler kolonlar için her zaman
255
+ tam satır döner. Gateway satırları verilen alanlara (+`id`) indirger; alan eşleşmesi
256
+ büyük/küçük harf duyarsızdır.
257
+ - `microservice_execute` dosya (stream) çıktısını içerik olarak aktarmaz.
258
+ - Passthrough auth modu tanımlı ama uçtan uca tatbik edilmedi; PoC `local` modda test edilir.
259
+ - Docker/compose servisi bilinçli olarak ertelendi (Faz 3 backlog'u —
260
+ `docs/00-durum-ve-yol-haritasi.md` §5.4).
package/dist/config.js ADDED
@@ -0,0 +1,128 @@
1
+ import { z } from 'zod';
2
+ export const moduleNames = [
3
+ 'platform',
4
+ 'project',
5
+ 'application',
6
+ 'datasource',
7
+ 'entity',
8
+ 'row',
9
+ 'microservice',
10
+ 'query',
11
+ 'workflow',
12
+ 'automation',
13
+ 'dto',
14
+ 'view',
15
+ 'page',
16
+ 'component',
17
+ 'flow',
18
+ 'layout',
19
+ 'variable',
20
+ 'folder',
21
+ 'file',
22
+ 'access',
23
+ 'template',
24
+ 'organization',
25
+ 'dependency',
26
+ 'deployment'
27
+ ];
28
+ export const modulePresets = {
29
+ core: ['platform', 'project', 'application', 'datasource', 'entity', 'row', 'microservice', 'query', 'workflow', 'automation', 'dto', 'view', 'dependency'],
30
+ studio: ['platform', 'page', 'component', 'flow', 'layout', 'variable', 'folder', 'file', 'access'],
31
+ admin: ['platform', 'template', 'organization', 'deployment']
32
+ };
33
+ function expandModuleNames(entries) {
34
+ const modules = [];
35
+ const unknown = [];
36
+ for (const entry of entries) {
37
+ const preset = modulePresets[entry];
38
+ if (preset) {
39
+ modules.push(...preset);
40
+ continue;
41
+ }
42
+ if (moduleNames.includes(entry)) {
43
+ modules.push(entry);
44
+ continue;
45
+ }
46
+ unknown.push(entry);
47
+ }
48
+ return { modules: [...new Set(modules)], unknown };
49
+ }
50
+ const environmentSchema = z.object({
51
+ ORG_API_BASE_URL: z.string().url(),
52
+ TENANT_API_BASE_URL: z.string().url(),
53
+ ORGANIZATION: z.string().min(1),
54
+ HOST_SUFFIX: z.string().min(1).default('localhost'),
55
+ DEFAULT_ENVIRONMENT: z.string().min(1).default('production'),
56
+ DEFAULT_PROJECT: z.string().optional(),
57
+ AUTH_MODE: z.enum(['local', 'passthrough']).default('local'),
58
+ TOKEN: z.string().optional(),
59
+ USERNAME: z.string().optional(),
60
+ PASSWORD: z.string().optional(),
61
+ POLICY: z.enum(['strict', 'warn', 'off']).default('strict'),
62
+ MAX_RESPONSE_BYTES: z.coerce.number().int().positive().default(262144),
63
+ REQUEST_TIMEOUT_MS: z.coerce.number().int().positive().default(100000),
64
+ MODULES: z.string().optional(),
65
+ LOG_LEVEL: z.enum(['off', 'summary', 'detail']).default('detail'),
66
+ LOG_DIR: z.string().min(1).optional(),
67
+ LOG_FILE: z.string().min(1).optional(),
68
+ LOG_MAX_BODY_CHARS: z.coerce.number().int().positive().default(2000),
69
+ MCP_PORT: z.coerce.number().int().positive().default(5100)
70
+ });
71
+ export const environmentKeys = Object.keys(environmentSchema.shape);
72
+ /**
73
+ * `.mcp.json` env bloğundan gelen KULLANILAMAZ değerleri süreç ortamından düşürür ki `.env`
74
+ * (dotenv mevcut anahtarları ezmez) ve şema varsayılanları devreye girebilsin. İki hâl
75
+ * kullanılamazdır: boş string (README §Ayar öncelik sırası: boş = tanımsız) ve genişletilmemiş
76
+ * `${VAR:-…}` yer tutucusu — Claude Code bu sözdizimini açar, VS Code'un kendi MCP istemcisi
77
+ * açmadan olduğu gibi geçirir ve düşürülmezse konfigürasyon doğrulaması yer tutucu metinle patlar.
78
+ */
79
+ export function dropUnusableEnvironment(env) {
80
+ for (const key of environmentKeys) {
81
+ const value = env[key];
82
+ if (value === '' || (value !== undefined && /^\$\{[^}]*\}$/.test(value))) {
83
+ delete env[key];
84
+ }
85
+ }
86
+ }
87
+ export function loadConfig(env) {
88
+ const parsed = environmentSchema.safeParse(env);
89
+ if (!parsed.success) {
90
+ const missing = parsed.error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}`).join('; ');
91
+ throw new Error(`Gateway konfigürasyonu geçersiz — ${missing}. Gerekli değişkenler için zeyrek-mcp/.env.example dosyasına bakın.`);
92
+ }
93
+ const values = parsed.data;
94
+ if (values.AUTH_MODE === 'local' && !values.TOKEN && (!values.USERNAME || !values.PASSWORD)) {
95
+ throw new Error('AUTH_MODE=local için TOKEN ya da USERNAME + PASSWORD zorunludur.');
96
+ }
97
+ if (values.AUTH_MODE === 'passthrough' && (values.TOKEN || values.USERNAME || values.PASSWORD)) {
98
+ throw new Error('AUTH_MODE=passthrough iken TOKEN/USERNAME/PASSWORD tanımlanamaz — kimlik istemciden gelir.');
99
+ }
100
+ const requested = values.MODULES
101
+ ? values.MODULES.split(',').map(name => name.trim()).filter(name => name.length > 0)
102
+ : [...moduleNames];
103
+ const { modules, unknown: unknownModules } = expandModuleNames(requested);
104
+ if (unknownModules.length > 0) {
105
+ throw new Error(`MODULES bilinmeyen modül/küme içeriyor: ${unknownModules.join(', ')}. Kümeler: ${Object.keys(modulePresets).join(', ')}. Modüller: ${moduleNames.join(', ')}.`);
106
+ }
107
+ return {
108
+ orgApiBaseUrl: values.ORG_API_BASE_URL.replace(/\/+$/, ''),
109
+ tenantApiBaseUrl: values.TENANT_API_BASE_URL.replace(/\/+$/, ''),
110
+ organization: values.ORGANIZATION,
111
+ hostSuffix: values.HOST_SUFFIX,
112
+ defaultEnvironment: values.DEFAULT_ENVIRONMENT,
113
+ defaultProject: values.DEFAULT_PROJECT,
114
+ authMode: values.AUTH_MODE,
115
+ token: values.TOKEN,
116
+ username: values.USERNAME,
117
+ password: values.PASSWORD,
118
+ policyMode: values.POLICY,
119
+ maxResponseBytes: values.MAX_RESPONSE_BYTES,
120
+ requestTimeoutMs: values.REQUEST_TIMEOUT_MS,
121
+ modules: modules,
122
+ logLevel: values.LOG_LEVEL,
123
+ logDirectory: values.LOG_DIR,
124
+ logFile: values.LOG_FILE,
125
+ logMaxBodyChars: values.LOG_MAX_BODY_CHARS,
126
+ port: values.MCP_PORT
127
+ };
128
+ }
package/dist/index.js ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
+ import { configureLogging, logGatewayEvent } from './observability/trace.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { Platform, requestAuthStorage } from './platform/http.js';
6
+ import { createGatewayServer } from './server.js';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { dropUnusableEnvironment, loadConfig } from './config.js';
9
+ import { join, dirname } from 'node:path';
10
+ import { existsSync } from 'node:fs';
11
+ import express from 'express';
12
+ import dotenv from 'dotenv';
13
+ import pino from 'pino';
14
+ dropUnusableEnvironment(process.env);
15
+ const packageRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
16
+ const envFiles = [join(process.cwd(), '.env'), join(packageRoot, '.env'), join(packageRoot, '..', '.env')];
17
+ for (const envFile of envFiles) {
18
+ if (existsSync(envFile)) {
19
+ dotenv.config({ path: envFile });
20
+ }
21
+ }
22
+ const logger = pino(pino.destination(2));
23
+ let config;
24
+ try {
25
+ config = loadConfig(process.env);
26
+ }
27
+ catch (error) {
28
+ logger.error(error instanceof Error ? error.message : String(error));
29
+ process.exit(1);
30
+ }
31
+ const platform = new Platform(config);
32
+ const useStdio = process.argv.includes('--stdio');
33
+ configureLogging(config, useStdio ? 'stdio' : 'http');
34
+ if (useStdio) {
35
+ if (config.authMode === 'passthrough') {
36
+ logger.error('stdio kipi passthrough auth ile kullanılamaz; AUTH_MODE=local yapın.');
37
+ process.exit(1);
38
+ }
39
+ const server = createGatewayServer(platform);
40
+ await server.connect(new StdioServerTransport());
41
+ logger.info({ modules: config.modules }, 'ngapps mcp gateway stdio üzerinde hazır');
42
+ logGatewayEvent('gateway stdio üzerinde hazır');
43
+ }
44
+ else {
45
+ const app = express();
46
+ app.use(express.json({ limit: '8mb' }));
47
+ app.get('/healthz', (_request, response) => {
48
+ response.json({ ok: true, organization: config.organization, modules: config.modules });
49
+ });
50
+ app.post('/mcp', async (request, response) => {
51
+ const server = createGatewayServer(platform);
52
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true });
53
+ response.on('close', () => {
54
+ void transport.close();
55
+ void server.close();
56
+ });
57
+ try {
58
+ await requestAuthStorage.run(request.headers.authorization, async () => {
59
+ await server.connect(transport);
60
+ await transport.handleRequest(request, response, request.body);
61
+ });
62
+ }
63
+ catch (error) {
64
+ logger.error({ err: error }, 'mcp isteği başarısız');
65
+ logGatewayEvent(`MCP isteği taşıma katmanında başarısız oldu: ${error instanceof Error ? `${error.name}: ${error.message}` : String(error)}`);
66
+ if (!response.headersSent) {
67
+ response.status(500).json({
68
+ jsonrpc: '2.0',
69
+ error: { code: -32603, message: 'Internal server error' },
70
+ id: null
71
+ });
72
+ }
73
+ }
74
+ });
75
+ const rejectNonPost = (_request, response) => {
76
+ response.status(405).json({
77
+ jsonrpc: '2.0',
78
+ error: { code: -32000, message: 'Method not allowed: gateway stateless çalışır, yalnızca POST kabul eder' },
79
+ id: null
80
+ });
81
+ };
82
+ app.get('/mcp', rejectNonPost);
83
+ app.delete('/mcp', rejectNonPost);
84
+ app.listen(config.port, () => {
85
+ logger.info({ port: config.port, modules: config.modules, authMode: config.authMode }, 'ngapps mcp gateway http üzerinde hazır');
86
+ logGatewayEvent(`gateway http üzerinde hazır · port ${config.port}`);
87
+ });
88
+ }