diff --git a/documentation/24-mcp-konektory.md b/documentation/24-mcp-konektory.md new file mode 100644 index 0000000..09a43e6 --- /dev/null +++ b/documentation/24-mcp-konektory.md @@ -0,0 +1,172 @@ +# 24 - MCP konektory + +Navrh, neni naprogramovane. + +Cil: firma si vyplni udaje sveho MCP serveru a jeho nastroje se objevi +v builderu jako kterakoliv jina operace. + +## Co je MCP z pohledu tohohle systemu + +MCP server je **katalog operaci, ktery se zepta az za behu**. Rekne "umim +`create_invoice`, `search_customer`, `send_report`", ke kazde da popis a schema +vstupu, a pak je umi vykonat. + +To je presne to, co u nas dela `src/data/services.ts` plus slozka `scripts/`. +Rozdil je v jedine veci, a ta rozhoduje o celem navrhu: + +| Dnes | MCP | +| ----------------------------------- | ----------------------------------------- | +| Operace jsou zname pri prekladu | Operace se zjisti az od serveru | +| Katalog je stejny pro vsechny firmy | Kazda firma ma jiny server, jine nastroje | +| Skript je nas, prosel code review | Nastroj je zakaznikuv, nevidime do nej | + +## Kde to narazi + +Retezec od builderu k behu je dnes tenhle: + +``` +StepPicker -> service.actions (co nabidnout) +ulozeni -> findOperation(...) (existuje ta operace?) +beh -> scriptIdFor(...) (kdo to vykona) +``` + +Vsechny tri se ptaji **statickeho katalogu**. U MCP zadny staticky katalog +neni: seznam operaci patri konektoru, ne sluzbe. Bez zmeny by slo ulozit jen +krok, ktery uz nekdo predem zapsal do kodu, coz je presny opak toho, o co jde. + +## Navrh: jedna sluzba, operace z konektoru + +**Ne sluzba na kazdy MCP server.** Sluzby jsou kod a zakaznik si je nezalozi. +Misto toho jedna sluzba `mcp` a kazdy server je **konektor** pod ni: + +``` +Sluzba "MCP server" definujeme my, jednou + | credentials: adresa, token, nazev + | + +-- Konektor "Interni sklad" zaklada si firma + | tools: create_order, get_stock, ... zjisteno od serveru + | + +-- Konektor "Firemni wiki" jiny server, jine nastroje +``` + +Krok stromu pak nese `serviceId: 'mcp'`, `operationId: ''` +a `connectorId`. Ten treti udaj je u MCP **povinny**, na rozdil od ostatnich +sluzeb: bez nej neni jasne, ktery server se pta, a dva konektory mohou mit +nastroj stejneho jmena. + +### Kudy se nastroje dostanou do builderu + +Katalog uz umi doplnit nabidku az za behu. `withRuntimeOptions` presne tohle +dela pro resitele, skupiny a typy ticketu - hodnoty, ktere v dobe prekladu +neexistuji. Nastroje MCP jsou tentyz pripad, jen misto polozek vyberu doplni +cele operace. + +Schema vstupu prijde jako JSON Schema a prevede se na `OperationField`, tedy +tvar, ktery builder uz umi vykreslit. Prevod je primocary u toho, co se +v praxi pouziva: + +| JSON Schema | `OperationField` | +| ----------------------- | -------------------- | +| `string` | `text` | +| `string` s `enum` | `choice` s `options` | +| `string` a dlouhy popis | `longtext` | +| `number`, `integer` | `text` s kontrolou | +| `boolean` | `choice` ano/ne | +| `object`, `array` | `json` | + +Co se neprevede, skonci jako `json`. Radsi pole, do ktereho clovek napise +strukturu rucne, nez pole, ktere tvari, ze rozumi necemu, cemu nerozumi. + +### Kdo to vykona + +Jeden skript `mcp.call-tool` pro vsechny nastroje. Nazev nastroje je vstup, +ne soubor. Psat skript na kazdy nastroj nejde - nevznikaji u nas. + +## Co si firma vyplni + +| Pole | K cemu | +| ----------------- | -------------------------------------------------- | +| Nazev | co clovek uvidi v builderu, 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 se smi volat | + +Posledni radek neni ozdoba. MCP server muze zpristupnit i nastroje, ktere do +automatizace nepatri (mazani, sprava uctu). Vycet je jednodussi nez vysvetlovat +lidem, ktere nastroje nepouzivat. + +## Jen HTTP, ne stdio + +MCP zna dva prenosy. `stdio` spousti server jako lokalni proces - to u nas +nepripada v uvahu: znamenalo by to pustit zakaznikuv program uvnitr naseho +containeru, a to je jina trida rizika nez zavolat cizi API. + +Zustava **Streamable HTTP**, tedy JSON-RPC pres POST. To `ctx.http` umi uz ted, +takze skript nepotrebuje zadny novy pristup k siti. + +Adresa serveru projde stejnou kontrolou jako u HTTP a SMTP: **nesmi mirit do +vnitrni site** (`isPrivateHost`). Vyplnuje ji firma, takze je to jedina zabrana +proti tomu, aby si nechala zavolat na neco uvnitr. + +## Overeni konektoru + +`tools/list`. Je to cteci volani, vyzaduje autorizaci a jeho vysledek se stejne +potrebuje - takze overeni a zjisteni nastroju je jedno volani, ne dve. + +Vysledek se ulozi ke konektoru a **necte se pri kazdem otevreni builderu**. +Seznam nastroju se meni radove pri nasazeni serveru, ne mezi dvema kliknutimi. +Obnovi se pri overeni konektoru a tlacitkem "Nacist nastroje znovu". + +## Co se stane, kdyz nastroj zmizi + +Ulozeny strom odkazuje na nastroj jmenem. Server se nasadi znovu, nastroj se +prejmenuje a krok ukazuje do prazdna. + +Nesmi to byt chyba ulozeni. Strom uz ulozeny je a firma za to nemuze: + +| Situace | Vysledek | +| ---------------------------------------- | ----------------------------------------- | +| Nastroj v ulozenem seznamu neni | **nedodelek**, jako chybejici konektor | +| Server je nedostupny pri ukladani stromu | ulozit, validovat proti ulozenemu seznamu | +| Nastroj chybi az pri behu | koncova chyba, neopakovat | + +Rozdil proti dnesku: u naseho skriptu je chybejici operace nase chyba, tady je +to bezna zmena na cizi strane. + +## Bezpecnost + +- **Do logu jde odpoved nastroje.** Prochazi stejnou redakci jako vsechno + ostatni, ale token do ni patri jen ten nas - co si server pise do odpovedi, + neovlivnime. Stoji za to pri prvnim nasazeni kouknout, co vraci. +- **Strop na velikost odpovedi** uz existuje (`SCRIPT_MAX_RESPONSE_BYTES`). + U MCP je potreba: nastroj muze vratit cely dokument. +- **Idempotence nefunguje.** Nas `Idempotency-Key` je hlavicka, ktere MCP + nerozumi. Druhy pokus po timeoutu tedy nastroj zavola podruhe. U ctecich + nastroju to nevadi, u zapisovych ano - proto se u kroku s MCP **neopakuje + automaticky**, dokud nebude jak rict, ze je nastroj bezpecny opakovat. +- **Nastroj je zakaznikuv.** Nevidime do nej a neruceme za to, co udela. To je + rozdil proti nasim skriptum a musi to byt videt i v portalu. + +## Postup + +| Faze | Co | +| ---- | -------------------------------------------------------------------------- | +| 1 | Sluzba `mcp`, pole konektoru, overeni pres `tools/list`, ulozeni seznamu | +| 2 | Nastroje do katalogu pres `withRuntimeOptions`, prevod JSON Schema na pole | +| 3 | Skript `mcp.call-tool` a vykonani ve strome | +| 4 | Vycet povolenych nastroju, tlacitko na obnoveni seznamu | + +Prvni faze je uzitecna sama o sobe: firma si napojeni zalozi a overi, i kdyz +se jeste neda pouzit v kroku. + +## Co bych nedelal + +- **Nezpristupnoval bych MCP zdroje a prompty.** Server umi vedle nastroju + i `resources` a `prompts`. Do stromu kroku patri akce, ne cteni dokumentu - + a bez toho je model o polovinu jednodussi. +- **Nedelal bych z nas MCP server.** Zajimava vec, ale je to opacny smer: + pustit cizi modely na nase tickety je jine rozhodnuti nez zavolat cizi + nastroj. +- **Nespoustel bych nastroje bez konektoru.** Zadny "rychly test adresou" - + napojeni je vlastnost firmy a ma jednu cestu. diff --git a/documentation/99-zmeny.md b/documentation/99-zmeny.md index ff4e8c6..b5aae8c 100644 --- a/documentation/99-zmeny.md +++ b/documentation/99-zmeny.md @@ -2,6 +2,20 @@ Nejnovejsi nahore. +## 2026-08-28 - navrh MCP konektoru + +Novy dokument [24-mcp-konektory.md](24-mcp-konektory.md). Neni to +naprogramovane, je to navrh. + +Podstata: MCP server je katalog operaci, ktery se zepta az za behu, kdezto nas +katalog je znamy pri prekladu. Retezec `service.actions` -> `findOperation` +-> `scriptIdFor` se dnes cely pta statickeho katalogu, takze by slo pouzit jen +nastroj, ktery uz nekdo predem zapsal do kodu - presny opak toho, o co jde. + +Navrh je **jedna sluzba `mcp` a kazdy server jako konektor pod ni**, s nastroji +doplnenymi do katalogu pres `withRuntimeOptions`, tedy tim samym zpusobem, jakym +uz se doplnuji resitele a typy ticketu. Jen HTTP, ne stdio. + ## 2026-08-28 - transformace maji svou kategorii, pribylo XML ### Odstraneno