MCP EasyWeb podle skutecne specifikace: auth v2 s klicem zarizeni

Predchozi verze posilala na /login jen jmeno, heslo a nazev zarizeni. Server na
to odpovidal 400 Bad Request na cokoliv, i na spravne udaje, protoze cekal neco
uplne jineho.

EasyWeb ma auth v2: token se nevydava proti uctu, ale proti zarizeni, a to je
par klicu ECDSA P-256. Jmeno a heslo se pouziji jedinkrat, pri registraci klice,
a soucasti registrace je podpis, kterym zarizeni dokazuje, ze privatni klic
k poslanemu verejnemu opravdu ma. Od te chvile se podepisuje kazde volani, ktere
s tokeny hybe.

Overeno proti bezicimu serveru: se spravnym telem uz /login nevraci 400, ale 401
s neplatnymi udaji. Ucty z jejich testovaciho settings.json na verejnych
instancich neplati, takze dal se bez skutecnych udaju nedostanu.

Prihlaseni:
- src/mcp/easyweb/crypto.ts - klice, podpisy, otisky. Podpis musi byt P1363,
  tedy hole r||s, 64 bajtu. Node podepisuje ve vychozim nastaveni do DER a ten
  by protistrana neuznala
- src/mcp/easyweb/device.ts - klic se vyrobi jednou a prezije restart, uklada se
  mezi udaje konektoru, ktere uz jsou zasifrovane. Novy priznak `managed` na
  poli sluzby znamena, ze ho vyplnuje portal a ve formulari se nezobrazuje
- src/mcp/easyweb/session.ts - tri tokeny, retez s ustupy (platny pristupovy,
  obnova obnovovacim, obnova zarizenim, cele prihlaseni), jedno prihlaseni
  naraz na konektor, tokeny jen v pameti

Ta posledni pravidla nejsou opatrnost navic: tokeny jsou jednorazove, druhe
pouziti server odmita kodem 409 a umi zarizeni zablokovat.

Transport:
- server si sam vybira, jestli odpovi JSON telem nebo SSE streamem, a streamem
  odpovida i na obycejna volani. Klient nabizi obojí a cte stream po kouscich -
  u dlouhych uloh ho server sam nezavira
- handshake plati na token, ne na volani
- odmitnute sezeni prijde jako chyba -32008 uvnitr uspesne odpovedi
- seznamy se skladaji pres vsechny stranky, bez toho je videt jen prvni
- odpoved se rozbaluje rekurzivne (structuredContent, contents, content, JSON
  zapsany jako text)

Dlouho bezici nastroje se spousti jako uloha a ceka se na ni dotazovanim. Limit
kroku se pri tom posouva z patnacti sekund na deset minut.

Nedodelane: trvaly kanal notifikaci (GET SSE), nahravani souboru po castech
a hlidani zmen kontraktu podle verze serveru.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
JiriUhlir
2026-08-28 10:58:24 +02:00
co-authored by Claude Opus 5
parent d881dab30d
commit 4d156d2837
18 changed files with 1514 additions and 404 deletions
+4
View File
@@ -67,6 +67,10 @@ do stromu. Validace pri ukladani se pta katalogu, ne klienta.
takze i cislo je text. Prevod na skutecny typ se dela az pred volanim, u toho,
kdo vi, jaky typ to ma byt.
**Nektera pole konektoru vyplnuje portal, ne clovek.** Maji priznak `managed`,
ve formulari se nezobrazuji a zapisuji se zvlast, aby zapis neshodil vysledek
overeni. Dnes je to klic zarizeni u MCP EasyWebu.
**Prava se nedovozuji na klientovi.** Server vraci `GET /api/dashboard/access`
s tim, co uzivatel smi. Dvoji vypocet se jednou rozejde.
+1 -1
View File
@@ -39,7 +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 | dve sluzby: obecna podle specifikace a MCP EasyWebu |
| MCP servery firmy | hotovo | obecna sluzba a MCP EasyWebu vcetne klice zarizeni |
| 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 |
+193 -90
View File
@@ -37,12 +37,12 @@ sluzbu, ne duvod zavrit dvere ostatnim.
Rozdily jsou na jednom miste v `src/mcp/dialect.ts`:
| Vlastnost | MCP server | MCP EasyWeb |
| ------------------------- | ------------ | ------------ |
| prihlaseni | OAuth 2.1 | vlastni |
| verze protokolu | `2025-06-18` | `2025-11-25` |
| odpoved jako SSE stream | ano | ne |
| hlavicka `Mcp-Session-Id` | ano | ne |
| Vlastnost | MCP server | MCP EasyWeb |
| ------------------------- | ------------ | ---------------------- |
| prihlaseni | OAuth 2.1 | klic zarizeni, podpisy |
| verze protokolu | `2025-06-18` | `2025-11-25` |
| odpoved jako SSE stream | ano | ano, i na bezne volani |
| hlavicka `Mcp-Session-Id` | ano | ne, sezeni je u tokenu |
Verze protokolu neni kosmetika: EasyWeb si po handshaku kontroluje, ze hlavicka
`MCP-Protocol-Version` sedi na jeho konstantu, a jinou odmitne.
@@ -85,23 +85,10 @@ OAuth. Kdyby slo jen jedno, cast serveru by nesla napojit vubec.
| ------------------ | ---------------------------------------------------- |
| Adresa MCP serveru | endpoint, napr. `https://web.firmy.cz/centaur/mcp` |
| Jmeno | uzivatel, pod kterym se portal hlasi |
| Heslo | portal si za nej sam vyzvedne pristup |
| Heslo | pouzije se **jednou**, na registraci zarizeni |
| Nazev zarizeni | pod timhle nazvem je prihlaseni videt v logu serveru |
| Otisk zarizeni | podle nej server pozna totez zarizeni |
Token se nezadava a zadavat nejde. **Zakaznik dostane adresu, jmeno a heslo**,
token vydava az server a ma omezenou zivotnost.
Prihlasovaci adresy si portal odvodi z adresy serveru sam:
| Endpoint | K cemu |
| ----------------------------- | -------------------------------- |
| `{server}/login` | HTTP Basic, vrati trojici tokenu |
| `{server}/renew-access-token` | obnova pristupoveho tokenu |
Otisk zarizeni se doplnuje z ID konektoru (`worknuke-con_abc123`), aby server
poznal, ze jde porad o totez zarizeni, a aby si dve napojeni tehoz portalu
nesahala do sezeni.
Token se nezadava a zadavat nejde. Zakaznik dostane adresu, jmeno a heslo.
### Adresa se u EasyWebu srovnava
@@ -110,51 +97,124 @@ Vlepena prihlasovaci cesta se odrizne a chybejici `/mcp` se doplni, takze
cestu prisny - i `/mcp/login/` s lomitkem na konci vraci 404.
**U obecne sluzby se adresa nemeni.** Cizi server muze mit endpoint kdekoliv
a "opravit" mu adresu podle naseho odhadu znamena rozbit napojeni, ktere by
jinak fungovalo.
a opravovat mu ji podle naseho odhadu znamena rozbit napojeni, ktere by jinak
fungovalo.
### Kdyz server odpovi 400
## Prihlaseni k EasyWebu
`400 Bad Request` z `/login` **neni chyba pozadavku u nas**. Server ho ma jako
"malformed authorization request" a odpovida jim i na udaje, ktere neuzna.
Overeno proti bezicimu serveru: spatne heslo, prazdne heslo i neznamy ucet
vraceji tutez odpoved jako udaje spravne, telo je vzdycky jen `Bad Request`
v HTML. Rozlisit se to zvenku neda, takze to hlaska rika narovinu misto toho,
aby posilala cloveka hledat chybu v adrese.
Nejspecifictejsi cast celeho napojeni. Stoji za to ji precist celou, protoze
**chybny postup umi zablokovat ucet**.
Rozdil oproti chybejicimu prihlaseni je videt: `/login` **bez** hlavicky
`Authorization` vraci 401, s ni uz 400.
### Token patri zarizeni, ne uctu
## Prihlaseni a zivotnost tokenu
Server nevydava token proti jmenu a heslu, ale proti **zarizeni**. Zarizeni je
pár klicu ECDSA P-256. Jmeno a heslo se pouziji jedinkrat, kdyz se klic
registruje. Od te chvile je identitou klic a kazde volani, ktere s tokeny hybe,
se jim podepisuje.
Cely zivotni cyklus resi `src/mcp/auth.ts`. **Token je kratkodoby, jeho
zivotnost urcuje server a hlidat ji je prace portalu.**
| Co | Kde zije | Prezije restart |
| --------------------- | --------------------------------- | --------------- |
| klic zarizeni a otisk | mezi udaji konektoru, zasifrovane | ano |
| pristupovy token | pamet procesu | ne |
| obnovovaci token | pamet procesu | ne |
| token zarizeni | pamet procesu | ne |
| Situace | Co portal udela |
| -------------------------------- | ---------------------------------------------- |
| token plati | pouzije ho |
| do vyprseni zbyva min nez minuta | vymeni ho driv, nez vyprsi behem volani |
| server vydal obnovovaci token | obnovi jim, je to levnejsi nez cele prihlaseni |
| obnova neprojde | prihlasi se cele znovu |
| server token odmitne pres 401 | zahodi ho a zkusi to **jednou** znovu |
Klic **musi** prezit restart, jinak by se pri kazdem startu registrovalo nove
zarizeni. Tokeny naopak prezit **nesmi**: po restartu uz neplati a jejich
pouziti vypada jako pokus o zneuziti.
Kdy token vyprsi, se zjistuje ze tri zdroju v tomhle poradi: `expires_in`
v sekundach, datum v odpovedi, a nakonec **`exp` z tela samotneho tokenu**.
To posledni je pro servery, ktere zivotnost nikam nepisou, ale vydavaji JWT -
a je to presne pripad EasyWebu. Kdyz neni ani jedno, pocita se s peti minutami,
tedy odhaduje se dolu.
Klic se uklada mezi udaje konektoru, protoze ty uz se ukladaji zasifrovane
a tohle je privatni klic. Pole ma priznak `managed`, takze ho ve formulari
nikdo nevidi ani nevyplnuje - portal si ho vyrobi sam pri prvnim prihlaseni.
### Podpisy
| Kde | Radky podpisu, spojene novym radkem |
| --------------- | ------------------------------------------------------------------------ |
| registrace | `CELEBRUM-MCP-KEY-REGISTRATION-V1`, jmeno, otisk, otisk klice, nonce |
| obnova pristupu | `CELEBRUM-MCP-POP-V1`, `renew-access`, hash tokenu, nonce, ID pozadavku |
| obnova zarizeni | `CELEBRUM-MCP-POP-V1`, `renew-refresh`, hash tokenu, nonce, ID pozadavku |
Podpis musi byt v tvaru **P1363**, tedy holé `r || s`, 64 bajtu. Node podepisuje
ve vychozim nastaveni do DER a ten by protistrana neuznala. Vsechno kolem toho
je v `src/mcp/easyweb/crypto.ts`.
### Retez s ustupy
`ensureAccess` jde odshora dolu, kazdy dalsi clanek je drazsi:
1. pristupovy token jeste plati (rezerva 90 sekund) - pouzije se
2. obnova obnovovacim tokenem
3. obnova tokenem zarizeni
4. cele prihlaseni jmenem a heslem
Na 401 a 409 se pokracuje dalsim clankem, jina chyba probublá ven. **409 znamena,
ze token uz nekdo spotreboval** - tokeny jsou jednorazove a po kazde obnove ten
predchozi neplati. Obnovovaci token se pri kazde obnove pristupu meni, takze se
musi ulozit oba.
Proto plati **jedno prihlaseni naraz na konektor**. Dve soubezne automatizace
nad tymz napojenim by jinak spustily dve obnovy, druha by pracovala se
spotrebovanym tokenem a server by zarizeni zablokoval. Resi to jedna sdilena
rozdelana operace: druhy volajici pocka na vysledek prvniho.
### Kdyz server odpovi 400 nebo 401
| Kod | Co to znamena |
| --- | ----------------------------------------------------------- |
| 400 | telo neni v poradku, typicky chybi podpis nebo verejny klic |
| 401 | telo je v poradku, ale server neuznal jmeno a heslo |
Overeno proti bezicimu serveru: **bez podpisu vraci 400 na cokoliv**, i na
spravne jmeno a heslo, a telo odpovedi je jen `Bad Request` v HTML. Se spravnym
telem a neplatnym uctem vraci 401. Rozdil mezi tim je to jedine, podle ceho jde
zvenku poznat, jestli je chyba v napojeni, nebo v uctu.
## Zivotnost tokenu
U obecne sluzby resi tokeny `src/mcp/auth.ts`, u EasyWebu
`src/mcp/easyweb/session.ts`. Spolecne plati, ze **token je kratkodoby, jeho
zivotnost urcuje server a hlidat ji je prace portalu**.
| Situace | Co portal udela |
| --------------------------------- | ------------------------------------------ |
| token plati | pouzije ho |
| do vyprseni zbyva min nez rezerva | vymeni ho driv, nez vyprsi behem volani |
| server vydal obnovovaci token | obnovi jim, je to levnejsi nez prihlaseni |
| obnova neprojde | jde o clanek niz, nakonec cele prihlaseni |
| server odmitne token nebo sezeni | prihlasi se znovu a **jednou** to zopakuje |
Kdy token vyprsi, se cte z `exp` v tele JWT. EasyWeb zivotnost jinam nepise
a pristupovy token plati zhruba pul hodiny. U obecne sluzby se driv zkusi
`expires_in` a datum v odpovedi.
Odmitnuty token je na odebrana opravneni: jeste neexpiroval, ale uz neplati.
Druhy pokus uz se nedela, to uz nejsou udaje, ktere by sedely.
**Token se drzi jen v pameti.** Po restartu se o novy rekne znovu. Do souboru
ani do tabulky nepatri: ulozit kratkodoby token je vsechna rizika ulozeni bez
jakekoliv vyhody. Kes drzi otisk udaju, takze zmena hesla ulozeny token
zneplatni.
Server to rekne bud kodem 401, nebo chybou `-32008` **uvnitr uspesne odpovedi**.
To druhe by bez zvlastniho osetreni vypadalo jako chyba volani a krok by skoncil
misto toho, aby se prihlasil znovu.
Zpusob prihlaseni se pise do hlasky u konektoru. Uzivatel vyplnil udaje a ma
vedet, jak s nimi portal nalozil, nez zacne hledat chybu jinde.
## Handshake plati na token
`initialize` a po nem `notifications/initialized` se posilaji **jednou na
token**, ne pred kazdym volanim. Server drzi sezeni u tokenu, takze po jeho
vymene se to musi zopakovat, jinak odpovi, ze relace neni inicializovana.
## Odpoved muze byt stream
Server si sam vybira, jestli odpovi JSON telem, nebo SSE streamem, a **streamem
odpovida i na obycejna volani**. Klient proto nabizi obojí a umi obojí precist.
Cte se **po kouscich a konci se u prvni skutecne odpovedi**. Server stream
u dlouhych uloh sam nezavira a posila do nej tlukot srdce, takze cekani na
konec by skoncilo az timeoutem. Konce radku prichazi jako CRLF a bloky se
poznaji podle dvou novych radku, takze se to nejdriv srovna.
Stream, ktery skonci bez odpovedi, **neni chyba**. Server to obcas udela
a pro krok je to prazdny vysledek.
## Nacteni nastroju
`POST /api/dashboard/connectors/{id}/mcp/tools`
@@ -220,43 +280,80 @@ nastroj s parametrem `cursorColor` by jinak zacal delat neco jineho, nez co ma.
V odpovedi se prijima `nextCursor`, `next_cursor` i `cursor`, bez ohledu na
velikost pismen.
Strop je **20 stranek na krok**. Rozbity server muze vracet porad tentyz kurzor
Strop je **20 stranek na krok**. Seznamy samotne (nastroje, zdroje, prompty)
se strankuji taky a skladaji se vzdycky - bez toho je videt jen prvni stranka,
tedy asi dvacet polozek, a vypada to jako uplny seznam. Rozbity server muze vracet porad tentyz kurzor
a bez stropu by krok bezel, dokud ho nezastavi timeout. Kdyz se strop vycerpa
a server porad nabizi dalsi, rekne se to v souhrnu kroku - tichy vysledek by
vypadal jako uplny.
## Co krok vraci
Vzdy tri hodnoty, at uz nastroj deklaruje cokoliv:
Vzdy ctyri hodnoty, at uz nastroj deklaruje cokoliv:
| Vystup | Co je to |
| ------------ | ----------------------------------------------------- |
| `text` | textova cast odpovedi |
| `data` | rozbaleny obsah, at uz je to objekt, seznam nebo text |
| `structured` | strukturovana cast, kdyz ji odpoved ma |
| `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`.
vyhravaji ty 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.
### Rozbaleni
MCP vraci obsah zabaleny na vic zpusobu a nekdy vic vrstev pres sebe:
```
{ "content": [ { "type": "text", "text": "{\"records\": [...]}" } ] }
{ "structuredContent": { "records": [...] } }
{ "contents": [ ... ] }
```
Bez rozbaleni by v kroku skoncil JSON zapsany jako text a v podmince by se s nim
nedalo nic delat. Rozbaluje se proto rekurzivne, prednost ma `structuredContent`
- to je cast, kterou sam server oznacil za strukturovanou.
## Nastroje, ktere bezi dlouho
Nektere nastroje se nedaji zavolat rovnou. Server u nich obycejne volani odmitne
a ceka, ze se spusti jako **uloha**: krok si o ni rekne, dostane jeji ID a pak
ceka na vysledek.
Cekame **dotazovanim** (`tasks/list`, pak `tasks/get`), protoze stav odtud je to
jedine, co je vzdycky pravda. Notifikace o prubehu chodi nejvys jednou a mohou
se minout.
Dve veci, ktere se snadno prehlednou:
- **Dokoncena uloha ze seznamu mizi.** "Neni v seznamu" tedy neznamena "bezi".
Po nekolika marnych kolech se prejde na primy dotaz, ktery zna i ulohy, ktere
uz ze seznamu vypadly.
- **Limit kroku se posouva.** Bezne volani ma na odpoved patnact sekund, uloha
deset minut. Kdyby platil ten kratky, kazda uloha by skoncila timeoutem.
Kdyz uloha nedobehne ani do deseti minut, **neni to chyba**: na serveru bezi dal
a krok to rekne misto toho, aby predstiral selhani.
## Bezpecnost a limity
- **Adresa nesmi mirit do vnitrni site.** Tataz kontrola jako u HTTP a SMTP,
vyplnuje ji firma.
- **Heslo ani token neopousti server.** Heslo se z API nevraci vubec, token
nikde nevznika jinde nez v pameti procesu. V logu jsou zredigovane oboje.
- **Heslo ani token neopousti server.** Heslo se z API nevraci vubec, tokeny
nikde nevznikaji jinde nez v pameti procesu. V logu jsou zredigovane oboje.
- **Klic zarizeni je ulozeny zasifrovane** mezi udaji konektoru, stejne jako
ostatni tajne hodnoty.
- **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, stejne jako volani nastroje.
- Plati stejny strop na velikost odpovedi jako u skriptu
(`SCRIPT_MAX_RESPONSE_BYTES`), a to i u streamu, kde se pocita prubezne.
- Seznamy se strankuji nejvys stokrat, volani nastroje dvacetkrat.
## Co se **nedela**
@@ -271,42 +368,48 @@ text odpovedi. Neni to nedodelek u nas.
## Kde to je
| Cast | Soubor |
| ------------------- | ------------------------------------------- |
| Rozdily serveru | `src/mcp/dialect.ts` |
| Protokol | `src/mcp/client.ts` |
| Prihlaseni a tokeny | `src/mcp/auth.ts` |
| Prevod schemat | `src/mcp/schema.ts` |
| Nastroje v katalogu | `src/data/mcpTools.ts` |
| Obe sluzby | `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` |
| Cast | Soubor |
| -------------------- | ------------------------------------------- |
| Rozdily serveru | `src/mcp/dialect.ts` |
| Protokol | `src/mcp/client.ts` |
| Prihlaseni obecne | `src/mcp/auth.ts` |
| Klice EasyWebu | `src/mcp/easyweb/crypto.ts` |
| Zarizeni u konektoru | `src/mcp/easyweb/device.ts` |
| Tokeny EasyWebu | `src/mcp/easyweb/session.ts` |
| Prevod schemat | `src/mcp/schema.ts` |
| Nastroje v katalogu | `src/data/mcpTools.ts` |
| Obe sluzby | `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 |
| -------------------------- | ----------------------------------------------------------------------- |
| Zdroje a prompty | server je umi vedle nastroju, viz nize |
| Nastroje pro model | dnes vybira nastroj clovek |
| stdio transport | umi se jen HTTP, tedy to, co delaji servery dostupne po siti |
| Prihlaseni s presmerovanim | authorization code vyzaduje cloveka v prohlizeci, napojeni bezi bez nej |
| Chybi | Poznamka |
| ---------------------------- | ----------------------------------------------------------------------- |
| Zdroje a prompty | server je umi vedle nastroju, viz nize |
| Trvaly kanal notifikaci | GET SSE. Prubeh uloh se zatim zjistuje dotazovanim |
| Nahravani souboru po castech | `POST {server}/upload`, potreba u nastroju, ktere berou obrazky |
| Hlidani zmen na serveru | verze serveru a diff seznamu, tedy upozorneni, ze se kontrakty zmenily |
| Nastroje pro model | dnes vybira nastroj clovek |
| stdio transport | umi se jen HTTP, tedy to, co delaji servery dostupne po siti |
| Prihlaseni s presmerovanim | authorization code vyzaduje cloveka v prohlizeci, napojeni bezi bez nej |
### Zdroje a prompty
MCP server vedle nastroju vystavuje **zdroje** (`resources/list`,
`resources/read`) a **prompty** (`prompts/list`, `prompts/get`). U EasyWebu to
neni okrajova vec: cislaky jako seznam entit, metadata entity nebo seznam
chybovych kodu jsou prave zdroje, ne nastroje.
neni okrajova vec: seznam entit, schema entity, chybove kody i samotne
objednavky se ctou jako zdroje, ne jako nastroje.
Do kroku automatizace se to hodi - "precti zdroj a pouzij hodnotu" je totez co
ciselnik. Neni to udelane, protoze zdroje maji URI sablonu misto schematu
argumentu, takze prevod na pole kroku je jina uloha nez u nastroju. Zdroje umi
navic vlastni strankovani po cislech stranek, ne kurzorem.
ciselnik. Neni to udelane, protoze zdroj ma URI sablonu misto schematu
argumentu, takze prevod na pole kroku je jina uloha nez u nastroju. Navic se
u nich query sklada rucne: datumy jsou ISO s dvojteckami a bezne kodovani by je
prepsalo tak, ze by filtr tise nefungoval.
### Nastroje pro model
Az bude krok "nechat model splnit ukol", muze dostat nastroje serveru jako sve
schopnosti a vybirat si sam. Cely klient uz na to je, chybi to napojeni na
model.
schopnosti a vybirat si sam. Cely klient uz na to je, chybi napojeni na model.
+65
View File
@@ -2,6 +2,71 @@
Nejnovejsi nahore.
## 2026-08-28 - MCP EasyWeb podle skutecne specifikace (auth v2)
Predchozi verze posilala na `/login` jen jmeno, heslo a nazev zarizeni. Server
na to odpovidal `400 Bad Request` na cokoliv, i na spravne udaje, protoze
**cekal neco uplne jineho**.
EasyWeb ma auth v2: token se nevydava proti uctu, ale proti **zarizeni**, a to
je pár klicu ECDSA P-256. Jmeno a heslo se pouziji jedinkrat, kdyz se klic
registruje, a soucasti registrace je podpis, kterym zarizeni dokazuje, ze
privatni klic k poslanemu verejnemu opravdu ma. Od te chvile se podepisuje
kazde volani, ktere s tokeny hybe.
Overeno proti bezicimu serveru: se spravnym telem uz `/login` nevraci 400, ale
401 s neplatnymi udaji. Ucty z jejich testovaciho `settings.json` na verejnych
instancich neplati, takze dal se bez skutecnych udaju nedostanu.
### Prihlaseni
- `src/mcp/easyweb/crypto.ts` - klice, podpisy, otisky. Podpis musi byt
**P1363**, tedy holé `r || s`, 64 bajtu. Node podepisuje ve vychozim
nastaveni do DER a ten by protistrana neuznala.
- `src/mcp/easyweb/device.ts` - klic zarizeni se vyrobi jednou a **prezije
restart**: uklada se mezi udaje konektoru, ktere uz jsou zasifrovane.
Pole ma novy priznak `managed`, takze ho ve formulari nikdo nevidi.
- `src/mcp/easyweb/session.ts` - tri tokeny, retez s ustupy
(platny pristupovy, obnova obnovovacim, obnova zarizenim, cele prihlaseni),
**jedno prihlaseni naraz na konektor**, tokeny **jen v pameti**.
Ta posledni tri pravidla nejsou opatrnost navic: tokeny jsou jednorazove, druhe
pouziti server odmita kodem 409 a **umi zarizeni zablokovat**. Dve soubezne
automatizace nad tymz napojenim by bez jedne sdilene rozdelane operace spustily
dve obnovy a druha by pracovala se spotrebovanym tokenem.
### Transport
- **Server si sam vybira, jestli odpovi JSON telem, nebo SSE streamem**, a
streamem odpovida i na obycejna volani. Klient proto nabizi obojí a cte
stream **po kouscich** - u dlouhych uloh ho server sam nezavira a posila do
nej tlukot srdce, takze cekani na konec by skoncilo az timeoutem.
- Handshake plati **na token**, ne na volani. Server drzi sezeni u tokenu.
- Odmitnute sezeni prijde jako chyba `-32008` **uvnitr uspesne odpovedi**. Bez
zvlastniho osetreni by to vypadalo jako chyba volani a krok by skoncil misto
toho, aby se prihlasil znovu.
- Seznamy se skladaji pres vsechny stranky. Bez toho je videt jen prvni, tedy
asi dvacet nastroju, a vypada to jako uplny seznam.
- Odpoved se rozbaluje rekurzivne (`structuredContent`, `contents`, `content`,
JSON zapsany jako text). Jinak by v kroku skoncil JSON jako retezec, se
kterym uz se v podmince nic nesvede.
### Dlouho bezici nastroje
Nastroj, ktery server odmitne spustit rovnou, se spusti jako **uloha** a ceka se
na ni dotazovanim. Stav z `tasks/list` a `tasks/get` je to jedine, co je vzdycky
pravda - notifikace o prubehu chodi nejvys jednou. Dokoncena uloha ze seznamu
mizi, takze po nekolika marnych kolech se prejde na primy dotaz.
Limit kroku se pri tom posouva z patnacti sekund na deset minut. Kdyz uloha
nedobehne ani tak, neni to chyba: na serveru bezi dal a krok to rekne.
### Co z toho zbylo nedodelane
Trvaly kanal notifikaci (GET SSE), nahravani souboru po castech a hlidani zmen
kontraktu podle verze serveru. Vsechno je v
[24-mcp-konektory.md](24-mcp-konektory.md) v seznamu toho, co chybi.
## 2026-08-28 - dve MCP sluzby: obecna a EasyWeb, strankovani nastroju
MCP je standard, ale **prihlaseni k nemu ne**. Oficialni specifikace stoji na