@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.
- package/.env.example +46 -0
- package/README.md +260 -0
- package/dist/config.js +128 -0
- package/dist/index.js +88 -0
- package/dist/knowledge/componentCatalog.js +438 -0
- package/dist/knowledge/componentEvents.js +164 -0
- package/dist/knowledge/coverage.js +60 -0
- package/dist/knowledge/normalize.js +1309 -0
- package/dist/knowledge/outlines.js +167 -0
- package/dist/knowledge/policy.js +44 -0
- package/dist/knowledge/reservedTables.js +75 -0
- package/dist/knowledge/rules.js +1725 -0
- package/dist/observability/trace.js +337 -0
- package/dist/platform/errors.js +132 -0
- package/dist/platform/http.js +169 -0
- package/dist/platform/responses.js +94 -0
- package/dist/platform/token.js +79 -0
- package/dist/resources/examples/entity-pair-m2m.json +105 -0
- package/dist/resources/examples/flow-list-to-form.json +65 -0
- package/dist/resources/examples/flow-load-table.json +178 -0
- package/dist/resources/examples/microservice-table-list.json +49 -0
- package/dist/resources/examples/middleware-authenticate.json +194 -0
- package/dist/resources/examples/page-detail-profile.json +95 -0
- package/dist/resources/examples/page-dynamic-form.json +221 -0
- package/dist/resources/examples/page-form-upsert.json +279 -0
- package/dist/resources/examples/page-html-embed.json +106 -0
- package/dist/resources/examples/page-sign-in.json +194 -0
- package/dist/resources/examples/workflow-basic.json +94 -0
- package/dist/resources/guides/component.md +108 -0
- package/dist/resources/guides/entity.md +348 -0
- package/dist/resources/guides/expressions.md +139 -0
- package/dist/resources/guides/getting-started.md +109 -0
- package/dist/resources/guides/html.md +106 -0
- package/dist/resources/guides/microservice.md +313 -0
- package/dist/resources/guides/middleware.md +271 -0
- package/dist/resources/guides/modify-existing.md +35 -0
- package/dist/resources/guides/page.md +1574 -0
- package/dist/resources/guides/view.md +89 -0
- package/dist/resources/guides/workflow.md +359 -0
- package/dist/resources/knowledge.js +44 -0
- package/dist/resources/schemas/CreateDatasourceCommand.json +54 -0
- package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +133 -0
- package/dist/resources/schemas/CreateEntityCommand.json +387 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +528 -0
- package/dist/resources/schemas/CreateQueryCommand.json +43 -0
- package/dist/resources/schemas/CreateViewCommand.json +158 -0
- package/dist/resources/schemas/CreateWorkflowCommand.json +1719 -0
- package/dist/resources/schemas/Filter.json +124 -0
- package/dist/resources/schemas/GetRowsQuery.json +122 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +565 -0
- package/dist/resources/schemas/PreviewQueryCommand.json +74 -0
- package/dist/resources/schemas/PreviewWorkflowCommand.json +981 -0
- package/dist/resources/schemas/StepDto.json +900 -0
- package/dist/resources/schemas/UpdateDatasourceCommand.json +58 -0
- package/dist/resources/schemas/UpdateEntityCommand.json +679 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +512 -0
- package/dist/resources/schemas/UpdateQueryCommand.json +86 -0
- package/dist/resources/schemas/UpdateViewCommand.json +153 -0
- package/dist/resources/schemas/UpdateWorkflowCommand.json +1719 -0
- package/dist/resources/schemas.js +40 -0
- package/dist/server.js +63 -0
- package/dist/tools/access.js +27 -0
- package/dist/tools/applications.js +59 -0
- package/dist/tools/automations.js +103 -0
- package/dist/tools/common.js +18 -0
- package/dist/tools/components.js +280 -0
- package/dist/tools/datasources.js +82 -0
- package/dist/tools/dependencies.js +17 -0
- package/dist/tools/deployments.js +17 -0
- package/dist/tools/dtos.js +54 -0
- package/dist/tools/entities.js +166 -0
- package/dist/tools/files.js +138 -0
- package/dist/tools/flows.js +226 -0
- package/dist/tools/folders.js +51 -0
- package/dist/tools/layouts.js +105 -0
- package/dist/tools/microservices.js +198 -0
- package/dist/tools/organizations.js +65 -0
- package/dist/tools/pages.js +597 -0
- package/dist/tools/platformInfo.js +44 -0
- package/dist/tools/projects.js +152 -0
- package/dist/tools/queries.js +48 -0
- package/dist/tools/rows.js +115 -0
- package/dist/tools/screens.js +97 -0
- package/dist/tools/templates.js +65 -0
- package/dist/tools/variables.js +94 -0
- package/dist/tools/views.js +58 -0
- package/dist/tools/workflows.js +196 -0
- 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
|
+
}
|