MCP konektory: nacte nastroje ze serveru a udela z nich kroky
Firma si zalozi napojeni na svuj MCP server, stiskne Nacist nastroje a jeho
nastroje se objevi v builderu jako kroky automatizace vcetne toho, jake
promenne prijimaji a jake vraceji.
Pribylo:
- sluzba `mcp` - jedina v katalogu bez pevnych operaci, rekne je az server.
Udaje: adresa serveru, token nebo klic v X-API-Key
- POST /connectors/:id/mcp/tools - zepta se serveru na tools/list a ulozi
vysledek. Je to zaroven overeni konektoru, proto u MCP neni tlacitko Overit
- src/mcp/client.ts - handshake, sezeni z hlavicky odpovedi, odpoved jako JSON
i jako SSE stream, strankovani nastroju, nic z toho nevyhazuje vyjimku
- src/mcp/schema.ts - ze schematu vzniknou pole kroku a zpatky se z vyplnenych
retezcu udelaji argumenty ve spravnych typech. Ten druhy smer je ten
podstatny: server ceka {"limit": 10}, ne {"limit": "10"}
- src/data/mcpTools.ts - nastroje v katalogu, kes nad tim, co je u konektoru
- sloupec `mcp` u konektoru (migrace 004). Bez ulozeni by po restartu zmizely
z katalogu kroky, ktere uzivatel uz ma ve stromech
- vnitrni krok runMcpTool - jedna obsluha pro vsechny nastroje vsech serveru
Rozhodnuti:
- nastroj patri firme, ne katalogu. serviceCatalog(tenantId) bez firmy nevrati
zadny, takze zapomenuty argument znamena "nic", ne "vsechno"
- ID operace nese ID konektoru (tool:<konektor>:<nastroj>), protoze firma muze
mit dva servery a na obou nastroj `search`
- krok se neopakuje, MCP nema idempotencni klic
- chyba nemaze nastroje, vypadek serveru nesmi vymazat kroky z automatizaci
- servery se pri startu neobvolavaji, jeden nedostupny by shodil katalog vsem
Dokumentace: prepsany 24-mcp-konektory.md na skutecny stav, novy
00-pro-programatory.md (rozcestnik, model ctyr pojmu, pravidla, ktera plati
vsude, co je krehke), doplnene 01, 12 a 99.
Mimochodem opraveno: setStatus v connectors/postgres.ts melo v RETURNING
doslovny retezec ${COLUMNS} misto dosazeni, a dva odstavce v dokumentu 12 byly
dvakrat.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
3e6b365eec
commit
435e254c90
@@ -0,0 +1,159 @@
|
||||
# 00 - Pro programatory
|
||||
|
||||
Rozcestnik a duvody. Ostatni dokumenty popisuji, **co** aplikace dela, tenhle
|
||||
popisuje, **jak je postavena a proc tak**.
|
||||
|
||||
## Nez zacnete
|
||||
|
||||
| Poradi | Precist | Proc |
|
||||
| ------ | ---------------------------------------------------------------- | -------------------------------------------- |
|
||||
| 1 | `AGENTS.md` v korenu | pravidla AppFactory, plati nad vsim |
|
||||
| 2 | tenhle soubor | model a pravidla, ktera plati vsude |
|
||||
| 3 | [03-architektura-a-mapa-kodu.md](03-architektura-a-mapa-kodu.md) | kde co lezi |
|
||||
| 4 | [15-rejstrik-funkci.md](15-rejstrik-funkci.md) | ktera funkce je na co, at se nepisou dvakrat |
|
||||
| 5 | to, co se tyka ukolu | viz tabulka nize |
|
||||
|
||||
| Delam | Ctu |
|
||||
| -------------------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| sluzbu nebo konektor | [12-sluzby-a-konektory.md](12-sluzby-a-konektory.md), [21-realne-sluzby.md](21-realne-sluzby.md) |
|
||||
| skript sluzby | [11-skripty-konektoru.md](11-skripty-konektoru.md) |
|
||||
| krok automatizace | [05-dashboard-a-builder.md](05-dashboard-a-builder.md), [20-fronta-a-runtime.md](20-fronta-a-runtime.md) |
|
||||
| tickety a helpdesk | [06-tickety.md](06-tickety.md), [18-ticketovaci-system.md](18-ticketovaci-system.md) |
|
||||
| prava a firmy | [07-firmy-a-prava.md](07-firmy-a-prava.md), [17-nastaveni-a-prava.md](17-nastaveni-a-prava.md) |
|
||||
| uloziste | [14-databaze.md](14-databaze.md) |
|
||||
| texty a jazyky | [23-jazyky.md](23-jazyky.md) |
|
||||
| vzhled | [22-znacka-a-design.md](22-znacka-a-design.md) |
|
||||
|
||||
## Model, ktery je potreba mit v hlave
|
||||
|
||||
Ctyri pojmy. Plete se to a z te zamneny vznikaji nejhorsi chyby.
|
||||
|
||||
| Pojem | Co to je | Ciji je |
|
||||
| ------------ | ----------------------------------------------- | ------------ |
|
||||
| **Sluzba** | co umime: iDoklad, e-mail, MCP server, webhook | nase |
|
||||
| **Skript** | vykonna cast operace, obycejny JS ve `scripts/` | nase |
|
||||
| **Konektor** | pristupove udaje jedne firmy k jedne sluzbe | firmy |
|
||||
| **Krok** | jedno pouziti operace v automatizaci | automatizace |
|
||||
|
||||
Sluzba rika "iDoklad potrebuje `X-ClientId` a `X-ClientSecret`". Konektor rika
|
||||
"a tohle jsou nase". Skript rika `GET /issued-invoices/12` a **k udajum se
|
||||
nedostane** - runtime je doplni az do requestu.
|
||||
|
||||
Diky tomu volaji dve firmy tutez sluzbu kazda pod svym uctem a v kodu neni ani
|
||||
jeden pristupovy udaj.
|
||||
|
||||
## Pravidla, ktera plati vsude
|
||||
|
||||
**Filtr na firmu je povinny argument.** `listTickets(tenantIds)`,
|
||||
`getConnector(id, tenantIds)`, `listConnectors(tenantIds)`. Zapomenuty filtr tak
|
||||
neznamena "vse", ale nezkompiluje se. Cizi zaznam se chova jako neexistujici
|
||||
(`undefined`), ne jako chyba prava - z odpovedi nema byt poznat, ze existuje.
|
||||
|
||||
**Tajna hodnota se nikdy nevraci z API.** `toPublicConnector` je jedine misto,
|
||||
kde se konektor prevadi pro klienta, prave proto, aby se na to neslo zapomenout
|
||||
na druhem miste. Do logu jde vsechno pres `createRedactor`, a to **v obou
|
||||
tvarech** - `Bearer abc` i holé `abc`, protoze cizi sluzby vraceji v chybach
|
||||
jednou to a jednou ono.
|
||||
|
||||
**Zadna ticha selhani.** Kazdy `catch` loguje a uzivatel se o chybe dozvi.
|
||||
Chyba cizi sluzby neni chyba API: vraci se 200 s `ok: false` a **celym telem
|
||||
odpovedi**, protoze prave tam je napsane, co jí vadilo. "HTTP 403" samo o sobe
|
||||
nikoho nikam nedovede.
|
||||
|
||||
**Katalog je zdroj pravdy.** Co neni v `src/data/services.ts`, to nejde ulozit
|
||||
do stromu. Validace pri ukladani se pta katalogu, ne klienta.
|
||||
|
||||
**Ve strome je vsechno retezec.** Hodnota kroku je sablona (`{{subject}}`),
|
||||
takze i cislo je text. Prevod na skutecny typ se dela az pred volanim, u toho,
|
||||
kdo vi, jaky typ to ma byt.
|
||||
|
||||
**Prava se nedovozuji na klientovi.** Server vraci `GET /api/dashboard/access`
|
||||
s tim, co uzivatel smi. Dvoji vypocet se jednou rozejde.
|
||||
|
||||
**Prava plati za firmu, ne za cloveka.** `permissionsOf(user, tenantId)` ma
|
||||
firmu jako povinny argument. Clovek muze byt spravce v jedne firme a bezny
|
||||
uzivatel v druhe.
|
||||
|
||||
## Jak vznika operace, kterou clovek vybere v builderu
|
||||
|
||||
Tri cesty, kazda ma svuj duvod:
|
||||
|
||||
| Cesta | Kdy | Kde |
|
||||
| -------------------- | --------------------------------------- | ----------------------------- |
|
||||
| **Zapis v katalogu** | popis toho, co umime nebo budeme umet | `src/data/services.ts` |
|
||||
| **Skript** | volani cizi sluzby pres HTTP | `scripts/*.js` + manifest |
|
||||
| **Vnitrni krok** | sahá do naseho uloziste, nebo neni HTTP | `src/runtime/builtinSteps.ts` |
|
||||
|
||||
Runtime zkousi **nejdriv vnitrni krok, pak skript**. Kdyz operace nema ani
|
||||
jedno, je to zatim jen zapis v katalogu a krok to rekne narovinu misto toho, aby
|
||||
tise neudelal nic.
|
||||
|
||||
Vnitrni krok je pro zalozeni ticketu (nase uloziste), pro e-mail (SMTP neni HTTP)
|
||||
a pro nastroje MCP (JSON-RPC se sezenim). Skript ma jen `ctx.http` a to je
|
||||
zamer: skript, ktery umi sahnout do uloziste, uz neni skript, ale druha
|
||||
aplikace.
|
||||
|
||||
## Katalog, ktery se meni za behu
|
||||
|
||||
Sluzby jsou staticky zapis v modulu. Tri veci se do nej doplnuji az za behu
|
||||
a kazda jinak:
|
||||
|
||||
| Co | Odkud | Klic |
|
||||
| ------------------ | --------------------- | -------------------- |
|
||||
| operace ze skriptu | manifest skriptu | `setScriptActions` |
|
||||
| nabidky v polich | uloziste (lide, typy) | `withRuntimeOptions` |
|
||||
| nastroje MCP | cizi server | `setMcpOperations` |
|
||||
|
||||
Prvni dve jsou nase a spolecne vsem firmam. Treti je jina: **nastroj MCP patri
|
||||
jedne firme**, protoze ho vystavuje jeji server. Proto s sebou nese `tenantId`
|
||||
a `serviceCatalog(tenantId)` bez firmy nevrati zadny. Zapomenuty argument tak
|
||||
znamena "nic", ne "vsechno" - stejne pravidlo jako u filtru na firmu.
|
||||
|
||||
U MCP navic **ID operace nese ID konektoru** (`tool:con_a1b2:create_order`).
|
||||
Firma muze mit dva servery a na obou nastroj `search`; kdyby ID bylo jen
|
||||
`search`, krok by nemel jak rict, ktery z nich. U ostatnich sluzeb to nehrozi,
|
||||
tam je operace vlastnost sluzby, ne napojeni.
|
||||
|
||||
## Uloziste ma tri rezimy
|
||||
|
||||
| Rezim | Kdy | Prezije |
|
||||
| ---------- | ----------------------------------- | -------------------- |
|
||||
| `postgres` | je `DATABASE_URL` i `SECRETS_KEY` | vse |
|
||||
| `file` | neni databaze, ale je datova slozka | restart, ne redeploy |
|
||||
| `memory` | ani jedno | nic |
|
||||
|
||||
**Rozhodnuti je na jednom miste** (`connectorStore.ts`). Kdyby se rozlezlo po
|
||||
kodu, jedno misto by se zapomnelo a chovalo by se pak jinak nez zbytek.
|
||||
|
||||
Nasazeni bezi v rezimu `file`. Ma to dusledek, ktery je poznat az pri zatezi:
|
||||
**kazda zmena prepisuje celou kolekci** jako formatovany JSON. U ticketu, ktere
|
||||
nesou i log prubehu, to s poctem zaznamu roste. Az bude portal pomaly, tohle je
|
||||
prvni misto, kam se divat.
|
||||
|
||||
## Co je krehke
|
||||
|
||||
| Misto | Co hrozi |
|
||||
| ---------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| ID operaci a poli v katalogu | odkazuji se na ne ulozene stromy, prejmenovani je rozbije |
|
||||
| poradi v `bootstrapData` | tickety az po resitelich, nastroje MCP az po firmach |
|
||||
| overeni konektoru bez `verifyPath` | proxy vraci 200 s prazdnym telem i pro neexistujici aplikaci, takze test projde a nic to nerika |
|
||||
| migrace | nikdy se neupravuji zpetne, oprava je vzdy novy soubor |
|
||||
| BOM v JSONu | rozbije Node i Vite, zapisovat UTF-8 bez BOM |
|
||||
|
||||
## Kdyz neco pridavate
|
||||
|
||||
**Novou sluzbu** popiste v katalogu vcetne `credentials` a `verifyPath`. Bez
|
||||
`verifyPath` overeni konektoru nerika nic o udajich, jen ze neco odpovida.
|
||||
|
||||
**Novy endpoint** patri do `src/openapi.ts`. Neni to volitelne, vyzaduje to
|
||||
`AGENTS.md`, a nezdokumentovany endpoint neexistuje pro nikoho krome toho, kdo
|
||||
ho napsal.
|
||||
|
||||
**Novy text v portalu** patri do `web/src/i18n/cs.ts` a klic do `en.ts`.
|
||||
Anglictina je `Partial`, takze nemusi byt uplna - co chybi, spadne na cestinu.
|
||||
|
||||
**Novy sloupec** znamena novou migraci **a** doplneni obou uloziste,
|
||||
souborového i databazoveho. Rozhrani je jedno, implementace dve.
|
||||
|
||||
Na konci prace se aktualizuje [01-prehled-a-stav.md](01-prehled-a-stav.md)
|
||||
a [99-zmeny.md](99-zmeny.md).
|
||||
@@ -39,6 +39,7 @@ React aplikaci ze slozky `dist/public`.
|
||||
| Odesilani souboru ze skriptu | hotovo | `ctx.http.postForm`, obsah jako Base64 |
|
||||
| OpenAI pod vlastnim klicem | hotovo | dotaz, soubor, prepis zvuku, seznam modelu |
|
||||
| Konektory za firmu | hotovo | pristupove udaje v konektoru, overeni napojeni |
|
||||
| MCP servery firmy | hotovo | nacte nastroje ze serveru, kazdy je krok automatizace |
|
||||
| Transformace dat | hotovo | pravidla i sablona JSON, kroky si predavaji struktury |
|
||||
| Prace nad celym modelem | hotovo | ukazka tela, cesty v sablonach, smycka nad seznamem |
|
||||
| Vlastni skripty firmy | hotovo | prevod dat v JS, v logu vstup i vystup |
|
||||
@@ -122,6 +123,7 @@ pro frontu, beh kroku a rozpocet na 150 klientu, a
|
||||
|
||||
| Soubor | O cem |
|
||||
| ---------------------------------------------------------------- | ----------------------------------------------- |
|
||||
| [00-pro-programatory.md](00-pro-programatory.md) | rozcestnik a duvody rozhodnuti |
|
||||
| [02-appfactory-proxy.md](02-appfactory-proxy.md) | beh za reverse proxy, ROOT_PATH, health |
|
||||
| [03-architektura-a-mapa-kodu.md](03-architektura-a-mapa-kodu.md) | kde co je |
|
||||
| [04-api.md](04-api.md) | endpointy a to, co ze Swaggeru neni videt |
|
||||
@@ -141,4 +143,8 @@ pro frontu, beh kroku a rozpocet na 150 klientu, a
|
||||
| [18-ticketovaci-system.md](18-ticketovaci-system.md) | udalosti, externi ID, statistiky, pohledy |
|
||||
| [19-kapacita-200-firem.md](19-kapacita-200-firem.md) | zmereno, co zvladne soucasny stav |
|
||||
| [20-fronta-a-runtime.md](20-fronta-a-runtime.md) | fronta, worker, spoustece, ochrana proti smycce |
|
||||
| [21-realne-sluzby.md](21-realne-sluzby.md) | napojeni na bezici aplikace a e-mail |
|
||||
| [22-znacka-a-design.md](22-znacka-a-design.md) | znacka WorkNuke, tokeny, prvky |
|
||||
| [23-jazyky.md](23-jazyky.md) | prepinani jazyku a slovniky |
|
||||
| [24-mcp-konektory.md](24-mcp-konektory.md) | MCP servery firmy jako kroky |
|
||||
| [99-zmeny.md](99-zmeny.md) | zaznam zmen, nejnovejsi nahore |
|
||||
|
||||
@@ -54,13 +54,19 @@ Adresu lze prepsat na dvou urovnich:
|
||||
Nazev promenne vznikne z ID sluzby velkymi pismeny, pomlcka je podtrzitko:
|
||||
`openai` je `OPENAI_BASE_URL`, `sap-bo` je `SAP_BO_BASE_URL`.
|
||||
|
||||
Treti pripad je sluzba, ktera **nejde pres HTTP**: e-mail. Ma
|
||||
`transport: 'smtp'`, adresu serveru nese konektor mezi udaji a operaci nevykona
|
||||
skript, ale vnitrni krok. Podrobnosti v [21-realne-sluzby.md](21-realne-sluzby.md).
|
||||
Treti pripad jsou sluzby, ktere **nejdou pres HTTP tak jako zbytek**. Rika to
|
||||
pole `transport`:
|
||||
|
||||
Treti pripad je sluzba, ktera **nejde pres HTTP**: e-mail. Ma
|
||||
`transport: 'smtp'`, adresu serveru nese konektor mezi udaji a operaci nevykona
|
||||
skript, ale vnitrni krok. Podrobnosti v [21-realne-sluzby.md](21-realne-sluzby.md).
|
||||
| `transport` | Sluzba | Cim se lisi |
|
||||
| ----------- | ---------- | -------------------------------------------------------------- |
|
||||
| `http` | vetsina | vychozi, skript rekne cestu a runtime doplni adresu a hlavicky |
|
||||
| `smtp` | E-mail | neni to HTTP, operaci vykona vnitrni krok |
|
||||
| `mcp` | MCP server | JSON-RPC se sezenim, a hlavne **zadne operace v katalogu** |
|
||||
|
||||
U obou nevychozich nese adresu serveru **konektor mezi udaji**, ne pole "vlastni
|
||||
adresa sluzby": sluzba zadnou vlastni adresu nema, protoze kazda firma ma svuj
|
||||
server. Podrobnosti v [21-realne-sluzby.md](21-realne-sluzby.md)
|
||||
a [24-mcp-konektory.md](24-mcp-konektory.md).
|
||||
|
||||
## Pristupove udaje patri konektoru, ne prostredi
|
||||
|
||||
@@ -193,11 +199,11 @@ Tak je na tom Prepis hovoru: jeho jedine volani je prepis, ktery se uctuje.
|
||||
`verifyPath` smi nest i query (`/company?limit=1`), aby overeni nestahovalo
|
||||
cely seznam. Do hlasky se query nedava, odrizne se - muze v ni byt tajemstvi.
|
||||
|
||||
U sluzby s `transport: 'smtp'` se `verifyPath` nepouziva vubec: overeni se
|
||||
**prihlasi na posmovni server** a nic neodesle.
|
||||
U sluzeb, ktere nejdou pres HTTP, se `verifyPath` nepouziva vubec:
|
||||
|
||||
U sluzby s `transport: 'smtp'` se `verifyPath` nepouziva vubec: overeni se
|
||||
**prihlasi na posmovni server** a nic neodesle.
|
||||
- `smtp` se **prihlasi na posmovni server** a nic neodesle,
|
||||
- `mcp` si **rekne o seznam nastroju**, coz je jedina cteci operace, kterou
|
||||
protokol ma.
|
||||
|
||||
Neuspesne overeni **neni chyba API**. Vraci se 200 s `ok: false` a popisem,
|
||||
protoze vysledek "nefunguje to" je platna odpoved na otazku "funguje to?".
|
||||
@@ -293,18 +299,19 @@ Cte se zvlast pres `/connectors/:id/checks`.
|
||||
|
||||
## API
|
||||
|
||||
| Metoda | Cesta | Popis |
|
||||
| ------ | -------------------------------------- | ------------------------- |
|
||||
| GET | `/api/dashboard/services` | katalog pro builder |
|
||||
| GET | `/api/dashboard/connectors/services` | katalog ocima firmy |
|
||||
| GET | `/api/dashboard/connectors` | konektory firmy |
|
||||
| POST | `/api/dashboard/connectors` | zalozit |
|
||||
| GET | `/api/dashboard/connectors/:id` | detail |
|
||||
| PATCH | `/api/dashboard/connectors/:id` | upravit |
|
||||
| DELETE | `/api/dashboard/connectors/:id` | smazat |
|
||||
| POST | `/api/dashboard/connectors/:id/test` | overit napojeni |
|
||||
| GET | `/api/dashboard/connectors/:id/checks` | poslednich pet overeni |
|
||||
| GET | `/api/dashboard/connectors/egress-ip` | odchozi IP adresa portalu |
|
||||
| Metoda | Cesta | Popis |
|
||||
| ------ | ----------------------------------------- | --------------------------- |
|
||||
| GET | `/api/dashboard/services` | katalog pro builder |
|
||||
| GET | `/api/dashboard/connectors/services` | katalog ocima firmy |
|
||||
| GET | `/api/dashboard/connectors` | konektory firmy |
|
||||
| POST | `/api/dashboard/connectors` | zalozit |
|
||||
| GET | `/api/dashboard/connectors/:id` | detail |
|
||||
| PATCH | `/api/dashboard/connectors/:id` | upravit |
|
||||
| DELETE | `/api/dashboard/connectors/:id` | smazat |
|
||||
| POST | `/api/dashboard/connectors/:id/test` | overit napojeni |
|
||||
| GET | `/api/dashboard/connectors/:id/checks` | poslednich pet overeni |
|
||||
| POST | `/api/dashboard/connectors/:id/mcp/tools` | nacist nastroje MCP serveru |
|
||||
| GET | `/api/dashboard/connectors/egress-ip` | odchozi IP adresa portalu |
|
||||
|
||||
## Stranky portalu
|
||||
|
||||
|
||||
+146
-138
@@ -1,161 +1,169 @@
|
||||
# 24 - MCP konektory
|
||||
|
||||
Navrh, neni naprogramovane.
|
||||
Hotovo. Firma si zalozi napojeni na svuj MCP server, stiskne **Nacist nastroje**
|
||||
a jeho nastroje se objevi v builderu jako kroky automatizace.
|
||||
|
||||
Cil: firma vyplni udaje sveho MCP serveru a jeho nastroje muze pouzit model,
|
||||
ktery za ni neco udela.
|
||||
## Co MCP je
|
||||
|
||||
## Co MCP je a co neni
|
||||
Protokol, kterym se zjisti, **co protistrana umi**, misto aby se to muselo
|
||||
predem naprogramovat. Server vystavi nastroje, u kazdeho jmeno, popis a schema
|
||||
toho, co prijima a co vraci. Klient si o ne rekne (`tools/list`) a pak je vola
|
||||
(`tools/call`).
|
||||
|
||||
MCP je protokol **pro modely**. Server vystavuje nastroje s popisem a schematem
|
||||
vstupu a *model* si sam vybere, ktery zavolat a s jakymi argumenty. Smysl je
|
||||
v tom, ze se nastroj nemusi predem naprogramovat do postupu - model ho najde
|
||||
a pouzije podle toho, co je zrovna potreba.
|
||||
Bezne je klientem model - dostane nastroje jako sve schopnosti a sam si vybira,
|
||||
ktery zavolat. **My jsme klientem taky, jen si nastroj vybira clovek v
|
||||
builderu.** Prinos je tentyz: napojeni na cizi system vznikne bez radky kodu
|
||||
u nas.
|
||||
|
||||
**Neni to protokol pro vzdalene volani procedur.** Kdyz nastroj vybere clovek
|
||||
v builderu a vyplni mu pevna pole, MCP nedava nic navic proti HTTP konektoru,
|
||||
ktery uz mame. Jen pribude vrstva a s ni JSON-RPC obalka.
|
||||
## Jak to vypada
|
||||
|
||||
Z toho plyne jedina vec, na ktere cely navrh stoji:
|
||||
1. Konektory, Novy konektor, sluzba **MCP server**.
|
||||
2. Vyplni se adresa serveru a token.
|
||||
3. Tlacitko **Nacist nastroje**. Portal se serveru zepta, co nabizi.
|
||||
4. V builderu jsou nastroje jako kroky, s vlastnimi poli a vystupy.
|
||||
|
||||
> **MCP konektor neni zdroj kroku. Je to schopnost, kterou dostane krok
|
||||
> s modelem.**
|
||||
|
||||
V builderu se tedy neobjevi polozka `create_invoice`. Objevi se krok
|
||||
"Nechat model splnit ukol" a v nem se zaskrtne, ktera napojeni smi pouzit.
|
||||
|
||||
## Jak to vypada v kroku
|
||||
|
||||
```
|
||||
Krok: Nechat model splnit ukol
|
||||
Zadani: "Zaloz objednavku podle teto poptavky a vrat jeji cislo."
|
||||
Data: {{data}}
|
||||
Napojeni: [x] Interni sklad [ ] Firemni wiki
|
||||
Model: gpt-4o-mini
|
||||
```
|
||||
|
||||
Model dostane nastroje zaskrtnutych serveru, sam se rozhodne, ktere zavolat,
|
||||
a krok vrati vysledek plus **seznam toho, co model opravdu udelal**.
|
||||
|
||||
Ten seznam neni pridavek. Cely tenhle system stoji na tom, ze je v logu videt,
|
||||
co ktery krok provedl. Krok, ktery udela nekolik zapisu do ciziho systemu
|
||||
a rekne jen "hotovo", je cerna skrinka a do provozu nepatri.
|
||||
|
||||
## Dve cesty, jak to postavit
|
||||
|
||||
Rozhodnuti, ktere je potreba udelat vedome: lisi se tim, kudy tece token
|
||||
zakaznika.
|
||||
|
||||
### A) Server predame modelu
|
||||
|
||||
OpenAI Responses API umi vzit MCP server jako nastroj:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "mcp",
|
||||
"server_label": "interni-sklad",
|
||||
"server_url": "https://mcp.firma.cz",
|
||||
"headers": { "Authorization": "Bearer ..." },
|
||||
"allowed_tools": ["create_order", "get_stock"],
|
||||
"require_approval": "never"
|
||||
}
|
||||
```
|
||||
|
||||
Malo prace: konektor drzi adresu a token, krok je slozi do pozadavku.
|
||||
|
||||
Cena za to:
|
||||
|
||||
- **Token zakaznika jde do OpenAI** a OpenAI vola jeho server primo. To musi
|
||||
firma vedome odsouhlasit, ne se to dozvedet z dokumentace.
|
||||
- Server musi byt dostupny **z internetu a ze site OpenAI**, ne jen z nasi.
|
||||
Firemni server za VPN takhle nepouzijeme.
|
||||
- Volani nejdou pres nas, takze **v nasem logu je jen to, co OpenAI vrati**,
|
||||
a neplati na ne nase stropy ani redakce.
|
||||
|
||||
### B) MCP klientem jsme my
|
||||
|
||||
Sami se serveru zeptame na `tools/list`, nastroje predame modelu jako obycejne
|
||||
funkce (function calling), a kdyz si model o volani rekne, **zavolame ho my**
|
||||
a vysledek mu vratime.
|
||||
|
||||
Vic prace, ale:
|
||||
|
||||
- Token zustava u nas, stejne jako u kazdeho jineho konektoru.
|
||||
- Server staci, kdyz je dostupny **z nasi adresy** - plati na nej seznamy
|
||||
povolenych IP, ktere uz kvuli ostatnim sluzbam resime.
|
||||
- Kazde volani jde pres `ctx.http`, tedy pres nase stropy, timeouty, redakci
|
||||
a zapis do logu behu.
|
||||
- Funguje s jakymkoliv modelem, ktery umi function calling, ne jen s OpenAI.
|
||||
|
||||
**Doporucuju B.** Ne proto, ze je hezci, ale protoze zbytek systemu stoji na
|
||||
tom, ze pristupove udaje neopousti server a ze je v logu videt kazde volani.
|
||||
Varianta A obe tahle pravidla porusuje, a to u konektoru, ktery si zaklada
|
||||
zakaznik.
|
||||
|
||||
Varianta A ma smysl jako zkratka pro verejne MCP servery bez tajemstvi.
|
||||
Tlacitko **Nastroje** u konektoru pak ukaze, co server rekl: u kazdeho nastroje
|
||||
popis, jake parametry prijima (povinne s hvezdickou) a jake hodnoty vraci.
|
||||
|
||||
## Co si firma vyplni
|
||||
|
||||
| Pole | K cemu |
|
||||
| ----------------- | ----------------------------------------------------- |
|
||||
| Nazev | co clovek uvidi u kroku, napr. "Interni sklad" |
|
||||
| Adresa serveru | HTTPS adresa MCP endpointu |
|
||||
| Token | tajny, posila se jako `Authorization: Bearer` |
|
||||
| Vlastni hlavicka | pro servery, ktere chteji neco jineho nez Bearer |
|
||||
| Povolene nastroje | prazdne = vsechny. Jinak vycet, ktery model smi videt |
|
||||
| Pole | K cemu |
|
||||
| ------------------- | -------------------------------------------------- |
|
||||
| Adresa MCP serveru | cely endpoint, napr. `https://mcp.firma.cz/mcp` |
|
||||
| Token | posila se jako `Authorization: Bearer` |
|
||||
| API klic v hlavicce | pro servery, ktere misto tokenu chteji `X-API-Key` |
|
||||
|
||||
**Vycet povolenych nastroju je hlavni pojistka.** U bezneho kroku vybira
|
||||
operaci clovek, tady vybira model. Server muze vystavovat i nastroje, ktere do
|
||||
automatizace nepatri (mazani, sprava uctu), a model o nich nevi nic krome
|
||||
popisu, ktery si napsal jejich autor. Co neni ve vyctu, model vubec neuvidi.
|
||||
Adresa je **mezi udaji**, ne v poli "vlastni adresa sluzby". U ostatnich sluzeb
|
||||
je adresa vlastnost sluzby a konektor ji smi jen prepsat, tady je to naopak:
|
||||
sluzba zadnou adresu nema, protoze kazda firma ma svuj server. Stejne to ma
|
||||
SMTP.
|
||||
|
||||
## Schvalovani
|
||||
Vlastni jmeno hlavicky se zadat neda. Bud `Authorization: Bearer`, nebo
|
||||
`X-API-Key` - to jsou dva zpusoby, kterymi se autorizuje drtiva vetsina
|
||||
serveru. Zadat libovolnou hlavicku by znamenalo zmenu modelu pristupovych
|
||||
udaju, kde jmeno hlavicky urcuje sluzba, ne konektor.
|
||||
|
||||
MCP zna rezim, kdy volani ceka na schvaleni cloveka. V automatizaci, ktera bezi
|
||||
sama v noci, neni koho se zeptat, takze jsou dve poctive moznosti:
|
||||
## Nacteni nastroju
|
||||
|
||||
| Rezim | Kdy |
|
||||
| ------------------------- | ----------------------------------------------- |
|
||||
| Bez schvalovani | vychozi. Pojistkou je vycet povolenych nastroju |
|
||||
| Se schvalenim pres ticket | beh se zastavi, zalozi ticket a ceka na cloveka |
|
||||
`POST /api/dashboard/connectors/{id}/mcp/tools`
|
||||
|
||||
Druhy rezim je vic prace, ale zapada do produktu: **delegovani na cloveka uz
|
||||
umime** a je to presne ono - model dojde k mistu, kde si netroufa, a preda to
|
||||
dal. Do prvni faze bych to nedaval.
|
||||
Je to zaroven **overeni konektoru**, proto se zapisuje do historie: kdyz server
|
||||
odpovi seznamem, adresa i token sedi. Nic to nemeni, da se to spustit kdykoliv.
|
||||
Tlacitko "Overit" u MCP konektoru neni - delalo by presne tohle.
|
||||
|
||||
## Bezpecnost
|
||||
Dve pravidla, ktera nejsou zrejma:
|
||||
|
||||
- **Adresa serveru nesmi mirit do vnitrni site** (`isPrivateHost`), stejne jako
|
||||
u HTTP a SMTP. Vyplnuje ji firma.
|
||||
- **Odpoved nastroje jde do logu behu** a prochazi redakci. Co si server pise
|
||||
do odpovedi, neovlivnime.
|
||||
- **Strop na velikost odpovedi** uz existuje a je tu potreba: nastroj muze
|
||||
vratit cely dokument.
|
||||
- **Idempotence nefunguje.** MCP zadny takovy pojem nema, takze druhy pokus po
|
||||
timeoutu zavola nastroj podruhe. Krok s MCP se proto **neopakuje sam**.
|
||||
- **Nastroj je zakaznikuv.** Nevidime do nej a neruceme za to, co udela.
|
||||
V portalu to musi byt videt.
|
||||
- **Model muze zavolat vic nastroju za sebou.** Strop na pocet volani v jednom
|
||||
kroku je potreba, jinak jde spotreba i cas nahoru bez omezeni.
|
||||
- **Prazdny vysledek se ulozi.** Server, ktery uz nastroj nenabizi, ma zmizet
|
||||
i z katalogu.
|
||||
- **Chyba nemeni nic.** Vypadek serveru nesmi vymazat kroky z automatizaci,
|
||||
ktere uz nekdo postavil.
|
||||
|
||||
## Postup
|
||||
## Jak se z nastroje stane krok
|
||||
|
||||
| Faze | Co |
|
||||
| ---- | ------------------------------------------------------------------------ |
|
||||
| 1 | Sluzba `mcp`, pole konektoru, overeni pres `tools/list`, ulozeni seznamu |
|
||||
| 2 | Krok "Nechat model splnit ukol" s vyberem napojeni, varianta B |
|
||||
| 3 | Zaznam volanych nastroju do logu behu a strop na pocet volani |
|
||||
| 4 | Schvalovani pres ticket |
|
||||
Prevod dela `src/mcp/schema.ts`, prochazi se **prvni uroven** vstupniho
|
||||
schematu:
|
||||
|
||||
Prvni faze je uzitecna sama o sobe: firma si napojeni zalozi, overi a vidi,
|
||||
jake nastroje server nabizi, jeste nez se da pouzit v kroku.
|
||||
| Ve schematu | V builderu |
|
||||
| ----------------- | -------------------------------- |
|
||||
| `string` | radek textu |
|
||||
| `enum` | vyber z hodnot |
|
||||
| `boolean` | vyber Ano / Ne |
|
||||
| `number` | radek textu, prevede se na cislo |
|
||||
| `object`, `array` | pole na JSON |
|
||||
|
||||
## Co bych nedelal
|
||||
Zanoreny objekt zustava jedno pole s JSONem. Rozpadat ho na `adresa.ulice` by
|
||||
znamenalo vymyslet si jmena, ktera server nezna, a u seznamu by to neslo vubec.
|
||||
|
||||
- **Nedaval bych MCP nastroje do vyberu kroku.** To byla chyba prvni verze
|
||||
tohohle navrhu. Kdyz nastroj vybira clovek, staci HTTP konektor - MCP je tam
|
||||
jen vrstva navic.
|
||||
- **Nezpristupnoval bych `resources` a `prompts`.** Server je umi vedle
|
||||
nastroju, ale krok stromu ma neco udelat, ne cist dokumenty.
|
||||
- **Nedelal bych z nas MCP server.** Je to opacny smer a jine rozhodnuti:
|
||||
pustit cizi modely na nase tickety.
|
||||
Zpatky je to ten podstatny smer: ve strome je **vsechno retezec**, protoze je to
|
||||
sablona s `{{promennymi}}`, ale server ceka `{"limit": 10}`, ne `{"limit": "10"}`.
|
||||
Prevod na typy ze schematu se deje az pred volanim. Rada serveru na tom jinak
|
||||
spadne az uvnitr nastroje, kde uz neni poznat, co se stalo.
|
||||
|
||||
Nepovinne pole, ktere zustane prazdne, **se serveru vubec neposle**. Prazdny
|
||||
retezec neni totez jako nevyplneno - pretisknul by vychozi hodnotu serveru.
|
||||
|
||||
## Co krok vraci
|
||||
|
||||
Vzdy tri hodnoty, at uz nastroj deklaruje cokoliv:
|
||||
|
||||
| Vystup | Co je to |
|
||||
| ------------ | ----------------------------------------------------- |
|
||||
| `text` | textova cast odpovedi |
|
||||
| `isError` | nastroj rekl, ze se nepovedlo (neni to chyba spojeni) |
|
||||
| `structured` | strukturovana cast, kdyz ji nastroj ma |
|
||||
|
||||
Kdyz nastroj deklaruje `outputSchema`, jsou k tomu jeho vlastni pole rozbalena
|
||||
do vystupu, takze na ne jde postavit podminka bez psani cesty. Pri kolizi jmen
|
||||
vyhravaji ty tri spolecne: `text` znamena text odpovedi vzdycky, at uz si
|
||||
nastroj rika co chce. Vlastni pole toho jmena je porad v `structured`.
|
||||
|
||||
`outputSchema` je v MCP nepovinne a vetsina serveru ho nema. Pak je znamy jen
|
||||
text odpovedi. Neni to nedodelek u nas.
|
||||
|
||||
## Bezpecnost a limity
|
||||
|
||||
- **Adresa nesmi mirit do vnitrni site.** Tataz kontrola jako u HTTP a SMTP,
|
||||
vyplnuje ji firma.
|
||||
- **Token neopousti server.** Do prohlizece se nevraci a v logu je zredigovany
|
||||
vcetne tvaru bez slova `Bearer`.
|
||||
- **Cizi napojeni se chova jako neexistujici.** Krok si konektor nacita pres
|
||||
filtr na firmu, takze strom s cizim ID konektoru selze.
|
||||
- **Krok se neopakuje.** MCP nema idempotencni klic, takze druhy pokus po
|
||||
timeoutu by nastroj provedl podruhe - a jestli to znamena druhou objednavku,
|
||||
vi jen server, ktery neni nas.
|
||||
- Plati stejny timeout a strop na velikost odpovedi jako u skriptu
|
||||
(`SCRIPT_TIMEOUT_MS`, `SCRIPT_MAX_RESPONSE_BYTES`).
|
||||
- `tools/list` se strankuje nejvys dvacetkrat. Server, ktery vraci porad tentyz
|
||||
kurzor, by jinak cyklil donekonecna.
|
||||
|
||||
## Co se **nedela**
|
||||
|
||||
- **Nastroje se pri startu neobvolavaji.** Cte se to, co je ulozene
|
||||
u konektoru. Obvolavat servery vsech firem kvuli startu aplikace by
|
||||
znamenalo, ze jeden nedostupny server shodi katalog vsem.
|
||||
- **Zmena udaju nastroje nemaze.** Jina adresa muze vratit jiny seznam, ale
|
||||
dokud ho nekdo nenacte, jsou ty stare porad to jedine, co v ulozenych
|
||||
automatizacich drzi kroky nazivu.
|
||||
- **`resources` a `prompts` se nectou.** Server je umi vedle nastroju, ale krok
|
||||
stromu ma neco udelat, ne cist dokumenty.
|
||||
- **Nejsme MCP server.** Je to opacny smer a jine rozhodnuti: pustit cizi
|
||||
modely na nase tickety.
|
||||
|
||||
## Kde to je
|
||||
|
||||
| Cast | Soubor |
|
||||
| ------------------- | ------------------------------------------- |
|
||||
| Protokol | `src/mcp/client.ts` |
|
||||
| Prevod schemat | `src/mcp/schema.ts` |
|
||||
| Nastroje v katalogu | `src/data/mcpTools.ts` |
|
||||
| Sluzba `mcp` | `src/data/services.ts` |
|
||||
| Nacteni nastroju | `src/routes/connectors.ts` |
|
||||
| Vykonna cast kroku | `src/runtime/builtinSteps.ts`, `runMcpTool` |
|
||||
| Ulozeni u konektoru | `src/data/connectors/*`, migrace `004` |
|
||||
| Portal | `web/src/pages/dashboard/Connectors.tsx` |
|
||||
|
||||
## Co jeste chybi
|
||||
|
||||
| Chybi | Poznamka |
|
||||
| ---------------------------- | -------------------------------------------------------------------- |
|
||||
| Nastroje pro model | dnes vybira nastroj clovek. Predat je modelu je dalsi krok, viz nize |
|
||||
| stdio a starsi SSE transport | umi se jen Streamable HTTP, tedy to, co delaji verejne servery |
|
||||
| Schvalovani volani | server ho umi vyzadovat, my na to zatim neumime cekat |
|
||||
| Vlastni jmeno hlavicky | jen `Authorization` a `X-API-Key` |
|
||||
|
||||
### Nastroje pro model
|
||||
|
||||
Az bude krok "nechat model splnit ukol", muze dostat nastroje MCP serveru jako
|
||||
sve schopnosti a vybirat si sam. Dve cesty, lisi se tim, kudy tece token:
|
||||
|
||||
- **Server preda modelu OpenAI.** Malo prace (`{"type": "mcp", ...}` v Responses
|
||||
API), ale token jde do OpenAI, ta vola server firmy primo, server musi byt
|
||||
dostupny z jeji site a volani nejdou pres nas log.
|
||||
- **Klientem zustaneme my.** Nastroje se modelu predaji jako obycejne funkce
|
||||
a volame je my. Token zustava u nas, plati nase stropy a redakce, funguje to
|
||||
s jakymkoliv modelem - a hlavne uz je to postavene, tenhle dokument je presne
|
||||
o tom.
|
||||
|
||||
Druha cesta je uz z devadesati procent hotova. Prvni by znamenala poslat
|
||||
zakaznikuv token treti strane, coz je proti tomu, jak je postaveny zbytek
|
||||
systemu.
|
||||
|
||||
+56
-14
@@ -2,24 +2,66 @@
|
||||
|
||||
Nejnovejsi nahore.
|
||||
|
||||
## 2026-08-28 - navrh MCP konektoru
|
||||
## 2026-08-28 - MCP konektory hotove
|
||||
|
||||
Novy dokument [24-mcp-konektory.md](24-mcp-konektory.md). Neni to
|
||||
naprogramovane, je to navrh.
|
||||
Firma si zalozi napojeni na svuj MCP server, stiskne **Nacist nastroje** a jeho
|
||||
nastroje se objevi v builderu jako kroky. Popis
|
||||
v [24-mcp-konektory.md](24-mcp-konektory.md).
|
||||
|
||||
**Prvni verze navrhu byla postavena spatne** a je prepsana. Davala MCP nastroje
|
||||
do vyberu kroku, tedy nastroj vybiral clovek a vyplnil mu pevna pole. Tak MCP
|
||||
nedava nic navic proti HTTP konektoru, ktery uz mame - je to protokol pro
|
||||
**modely**, kde si nastroj vybira model podle toho, co je zrovna potreba.
|
||||
Navrh byl predtim dvakrat prepsany a stoji za to rict proc. Prvni verze davala
|
||||
nastroje do vyberu kroku, ale popisovala MCP jako obycejny katalog vzdalenych
|
||||
procedur - tak nedava nic navic proti HTTP konektoru. Druha verze to prehnala
|
||||
opacnym smerem a chtela nastroje predavat jen modelu. Vysledne zadani je
|
||||
uprostred: **klientem jsme my**, nastroj vybira clovek v builderu, a prinos je
|
||||
v tom, ze napojeni na cizi system vznikne bez radky kodu u nas.
|
||||
|
||||
Spravne zadani: MCP konektor **neni zdroj kroku, je to schopnost, kterou dostane
|
||||
krok s modelem**. V builderu se objevi krok "Nechat model splnit ukol" a v nem
|
||||
se zaskrtne, ktera napojeni smi pouzit.
|
||||
### Pribylo
|
||||
|
||||
Dokument popisuje dve cesty a lisi se tim, kudy tece token zakaznika: predat
|
||||
server modelu (OpenAI ho zavola sam), nebo byt MCP klientem my. Doporucena je
|
||||
druha, protoze zbytek systemu stoji na tom, ze udaje neopousti server a ze je
|
||||
v logu videt kazde volani.
|
||||
- **Sluzba `mcp`.** Jedina v katalogu, ktera nema zadne pevne operace - rekne je
|
||||
az server. Udaje jsou adresa serveru, token nebo klic v `X-API-Key`.
|
||||
- **`POST /connectors/:id/mcp/tools`.** Zepta se serveru na `tools/list` a ulozi
|
||||
vysledek. Je to zaroven overeni konektoru, proto tlacitko "Overit" u MCP neni.
|
||||
- **Klient protokolu** (`src/mcp/client.ts`): handshake, sezeni z hlavicky
|
||||
odpovedi, odpoved jako JSON i jako SSE stream, strankovani nastroju.
|
||||
- **Prevod schemat** (`src/mcp/schema.ts`). Ze schematu vzniknou pole kroku
|
||||
a zpatky se z vyplnenych retezcu udelaji argumenty ve spravnych typech.
|
||||
Ten druhy smer je ten podstatny: server ceka `{"limit": 10}`, ne
|
||||
`{"limit": "10"}`, a rada serveru na tom spadne az uvnitr nastroje.
|
||||
- **Nastroje u konektoru** (sloupec `mcp`, migrace `004`). Bez ulozeni by po
|
||||
restartu zmizely z katalogu kroky, ktere uzivatel uz ma ve stromech.
|
||||
- **Vnitrni krok `runMcpTool`.** Jedna obsluha pro vsechny nastroje vsech
|
||||
serveru - ktery to je, rika az ID operace `tool:<konektor>:<nastroj>`.
|
||||
|
||||
### Rozhodnuti, ktera stoji za zminku
|
||||
|
||||
- **Nastroj patri firme, ne katalogu.** `serviceCatalog(tenantId)` bez firmy
|
||||
nevrati zadny nastroj. Zapomenuty argument tak znamena "nic", ne "vsechno" -
|
||||
stejne pravidlo jako u filtru na firmu.
|
||||
- **ID operace nese ID konektoru.** Firma muze mit dva servery a na obou nastroj
|
||||
`search`.
|
||||
- **Krok se neopakuje.** MCP nema idempotencni klic, druhy pokus po timeoutu by
|
||||
nastroj provedl podruhe.
|
||||
- **Chyba nemaze nastroje.** Vypadek serveru nesmi vymazat kroky z hotovych
|
||||
automatizaci. Prazdny seznam se naopak ulozi.
|
||||
- **Servery se pri startu neobvolavaji.** Jeden nedostupny by shodil katalog
|
||||
vsem.
|
||||
|
||||
### Opraveno mimochodem
|
||||
|
||||
- `setStatus` v `connectors/postgres.ts` melo v `RETURNING` doslovny retezec
|
||||
`${COLUMNS}` misto dosazeni. V rezimu `file`, ve kterem bezi nasazeni, se to
|
||||
neprojevilo.
|
||||
- Dva odstavce v [12-sluzby-a-konektory.md](12-sluzby-a-konektory.md) byly
|
||||
dvakrat.
|
||||
|
||||
## 2026-08-28 - dokument pro programatory
|
||||
|
||||
Novy [00-pro-programatory.md](00-pro-programatory.md): rozcestnik, model ctyr
|
||||
pojmu (sluzba, skript, konektor, krok), pravidla, ktera plati vsude, tri cesty
|
||||
vzniku operace, tri rezimy uloziste a seznam mist, ktera jsou krehka.
|
||||
|
||||
Neni to kopie [03-architektura-a-mapa-kodu.md](03-architektura-a-mapa-kodu.md).
|
||||
Ta rika, kde co lezi, tenhle rika proc to tak je.
|
||||
|
||||
## 2026-08-28 - transformace maji svou kategorii, pribylo XML
|
||||
|
||||
|
||||
Reference in New Issue
Block a user