# MCP server

> Jak server mluví, proč nemá handshake ani sezení, co dělá zápisový nástroj při zavolání a rejstřík všech nástrojů i s jejich oprávněními.

- Sekce: Pro vývojáře
- Stránka: https://shopzi.cz/dokumentace/vyvojari/mcp-server
- Ověřeno: 2026-10-20

---

MCP server obchodu poslouchá na `/api/mcp`, tedy **na doméně vašeho obchodu**. Ověřuje se týmž API
klíčem jako REST API a nabídne asistentovi jen ty nástroje, na které klíč dosáhne. Klíč musí platit
pro server MCP: klíč omezený jen na REST API dostane `403 key_surface_mismatch`.

## Transport [#transport]

Server je postavený proti revizi protokolu **2026-07-28**, a to je ta informace, kvůli které se
napojení nejčastěji nepovede. Revize **zrušila zahajovací výměnu** (`initialize`), sezení i
identifikátor sezení, takže:

* **první volání může být rovnou `tools/list`.** Žádný handshake se nečeká;
* **stav se nikde nedrží.** Každý požadavek se popisuje sám, což je taky důvod, proč se nemusí
  trefit do téže instance serveru;
* **jede se jen přes `POST`.** `GET` býval SSE stream a `DELETE` ukončoval sezení; obojí odpoví
  `405 method_not_allowed` s hlavičkou `Allow: POST`.

Klienta starší revize z roku 2025, který zahajovací výměnu posílá, server obslouží také, a to
bezstavově: na `initialize` odpoví a sezení stejně nevznikne. Která revize je která, se pozná
z požadavku: klient revize 2026-07-28 nese verzi protokolu v `_meta`, požadavek bez ní se obsluhuje
jako starší revize.

Klient musí poslat `Accept: application/json, text/event-stream`. Odpověď může přijít jako obyčejný
JSON i jako proud událostí a klient, který umí jen jedno, si na tom vyláme zuby.

Server je pro **klienty, ne pro webové stránky**. Požadavek s hlavičkou `Origin` dostane
`403 origin_not_allowed` dřív, než se vůbec ověří klíč, a protože prohlížečového klienta MCP
nepodporujeme, odmítne se každý původ. Klient v terminálu nebo v editoru hlavičku `Origin`
neposílá, takže se ho to netýká.

```bash
curl -s https://muj-eshop.cz/api/mcp \
  -H "Authorization: Bearer $SHOPZI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

### Zrušení volání [#zruseni-volani]

Revize je bezstavová, a to má na zrušení přímý dopad. `notifications/cancelled` poslat **můžete**
a server ji přijme bez chyby, ale **nic jí nezastaví**: bezstavový přenos znamená, že notifikace
dorazí do jiné instance než ta, ve které běží rušená práce, a žádná sběrnice mezi nimi není.

Co **funguje**, je zavřít spojení. Když klient požadavek přeruší, server to pozná a zápis odmítne
kódem `forbidden` s českou větou „Volání bylo zrušeno dřív, než se stihlo zapsat. V obchodě se nic
nezměnilo.“ Kontrola je první brána každého zápisu, dřív než oprávnění i stav obchodu, takže do dat
obchodu se nezapíše nic; do stropu volání klíče se takové volání započítá jako každé jiné.

Není to záruka atomicity a nepředstírá ji: mezi kontrolou a potvrzením zápisu je krátké okno.
Spolehlivě to řeší běžný případ, kdy klient odpadl dávno předtím, než na jeho požadavek došla řada.

## Co asistent uvidí [#co-asistent-uvidi]

Seznam nástrojů se filtruje **podle oprávnění klíče**. Nástroj, na který klíč nedosáhne, se do
`tools/list` vůbec nedostane, takže si o něj model nemůže říct: neví, že existuje. Rozsah klíče je
tedy první a nejsilnější obrana, ne poslední.

Každý nástroj s sebou nese anotace, podle kterých se hostitel rozhoduje, kdy se zeptat člověka:

* `readOnlyHint` říká, že nástroj jen čte;
* `destructiveHint` říká, že umí přepsat nebo smazat, co už existuje;
* `openWorldHint` říká, že sahá mimo data obchodu, na veřejný internet;
* `idempotentHint` je u všech nástrojů `false`, protože idempotence je vlastnost **volání**
  (posílá se `idempotencyKey`), ne nástroje.

Klíč idempotence patří **jedné změně**. Totéž volání se stejným klíčem vrátí původní výsledek
a nezapíše podruhé; stejný klíč u jiné změny (jiný nástroj, jiná položka, založení místo úpravy)
server odmítne chybou `invalid_input`, místo aby vrátil výsledek té první a druhou tiše vynechal.
Pro každou zamýšlenou změnu proto posílejte nový klíč.

Čtení objednávek, produktů, zásob a dokladů sdílí čtecí vrstvu s REST API, takže časy v jejich
výsledcích mají tentýž tvar: ISO 8601 v UTC se zónou `Z` a s mikrosekundami, například
`2026-09-01T08:14:02.118204Z`. Datum bez času (DUZP, splatnost) má tvar `RRRR-MM-DD`.

Peníze přicházejí stejně jako v REST API, jako celé číslo v haléřích v poli končícím na `_minor`.
Čtecí nástroje k němu navíc přidávají tutéž částku jako hotový český text pod jménem bez `_minor`,
hned vedle:

```json
{ "price_minor": 649900, "price": "6 499,00 Kč", "currency_code": "CZK" }
```

Text je pro model, aby obchodníkovi řekl částku přesně a nepřepočítával ji; mezery v něm jsou
nezlomitelné (U+00A0). Kdo výsledek zpracovává strojově, ať čte celé číslo: to je smlouva, text se
může změnit s formátem. REST API ho neposílá.

## Co se stane při zápisu [#co-se-stane-pri-zapisu]

Přes MCP se **opravdu zapisuje**, v mezích oprávnění klíče. Nikdo z nás změnu neschvaluje a nic
nečeká ve frontě u SHOPZI; co se má potvrdit, potvrzuje člověk z obchodu.

Chování se liší podle toho, co nástroj dělá:

* **Jediný zápis, na který se server neptá, je založení úkolu** (`shopzi_manage_task` s operací
  `create`). Varování u všeho je varování u ničeho, a úkol na nástěnce je to jediné, co nic
  nepřepíše, nesáhne ven a nic nestojí. Úprava a smazání úkolu, přidání článku, založení produktu
  i naskladnění se PTAJÍ: patří k nástrojům, které přepisují obsah obchodu, i když se to zvenku
  tváří jako pouhé přidání.
* **Nástroj, který přepisuje nebo maže**, se napřed zeptá. V prvním kole se v datech obchodu nic
  nezmění. Souhlas je vždycky svázaný s konkrétními argumenty, takže se mezi otázkou a provedením
  nedá vyměnit, co se má stát.
* **Nástroj, který utrácí kredity obchodu**, se zeptá taky, i když jen přidává. Týká se to
  generování obrázků a videí, hledání na webu a hromadné AI úpravy produktů. Anotace
  `destructiveHint` tuhle vlastnost vyjádřit neumí, a mlčky utracená peněženka je horší vada než
  odmítnuté volání. Otázka nese **cenu v kreditech a zůstatek po akci**, tedy stejnou částku, jaká
  se strhne.
* **Nástroj, který může strhnout peníze z karty**, se zeptá vždycky. Je to jen navýšení tarifu
  (`shopzi_manage_subscription`) a otázka nese **přesnou částku ze Stripe**. Ve zkušebním období
  se nestrhne nic a otázka to říká; podrobnosti jsou v oddílu **Předplatné z terminálu** níž.

### Čtyři způsoby, jak se server zeptá [#ctyri-zpusoby-jak-se-server-zepta]

První z nich na klientovi vůbec nezáleží, zbylé tři ano: rozhoduje o nich to, co váš klient
v `_meta` požadavku deklaruje ve schopnosti `elicitation`.

1. **Schválení, které už čeká.** Než server sáhne po čemkoli dalším, podívá se, jestli pro tentýž
   klíč, nástroj a otisk argumentů neleží schválení, které člověk v administraci už odklikl a které
   se ještě nepoužilo. Když ano, spotřebuje ho a změnu provede rovnou, bez ptaní; `idempotencyKey`
   si přitom vynutí na `mcp-approval:<id>`, aby se jedno schválení neprovedlo dvakrát. Tohle je
   běžný konec cesty číslo 3 a 4: člověk schválí v prohlížeči, klient zavolá znovu a projde tudy.
2. **Formulář** (`elicitation: {}` nebo `{ "form": {} }`). Server místo provedení odpoví vloženým
   dotazem (`resultType: "input_required"`) pod klíčem `potvrzeni`: věta, co se stane (u placené
   akce i s cenou), a jediné zaškrtávací pole `potvrdit` s popiskem „Ano, provést“. Klient ho ukáže
   člověku a druhé kolo s odpovědí `action: "accept"` a `potvrdit: true` změnu spustí. Souhlas je
   podepsaný, patří k týmž argumentům a platí patnáct minut.
3. **Odkaz v elicitaci** (klient deklaruje jen `{ "url": {} }`). Server založí schválení a vrátí
   pod klíčem `schvaleni` elicitaci s `mode: "url"`, která vede na stránku schválení v administraci
   obchodu (`/administrace/schvaleni/<id>` na doméně obchodu; kdo ji otevře, musí se přihlásit).
   Druhé kolo s `action: "accept"` změnu provede, jen když ji tam člověk mezitím schválil. Když se pořád čeká,
   přijde `approval_pending` s tímtéž odkazem; když ji člověk zamítl v administraci nebo odpověděl
   v klientovi jinak než `accept`, přijde `confirmation_declined` a čekající schválení se zruší;
   když schválení mezitím vypršelo nebo už bylo použité, přijde `confirmation_required` a dalším
   voláním vznikne nové. `requestState` tohoto kola platí hodinu, stejně jako schválení, takže
   člověk má na přihlášení a rozhodnutí stejný čas.
4. **Odkaz v odmítnutí** (klient elicitaci neumí vůbec). Nástroj odmítne s kódem
   `approval_required` a odkazem v `_meta["cz.shopzi/approvalUrl"]` (odkaz je i v české větě).
   Po schválení v administraci zavolejte nástroj znovu **se stejnými argumenty**; dokud se čeká,
   přijde `approval_pending` a nové schválení nevznikne.

Výsledek volání, které prošlo potvrzením, to o sobě říká: v `_meta["cz.shopzi/confirmation"]`
nese `{ "confirmedBy": "human", "via": "form" }` (dialog v klientovi) nebo `"via": "approval"`
(schválení v administraci) a v `content` je navíc česká věta pro model, u placené akce i s cenou
a zůstatkem kreditů, které člověk v dialogu viděl. Dotaz totiž ukazuje klient člověku a model ho
nevidí; bez téhle věty by asistent obchodníkovi tvrdil, že se změna uložila bez potvrzení.
Nepotvrzené volání (třeba založení úkolu) klíč nenese.

Schválení v administraci smí rozhodnout jen přihlášený vlastník nebo manažer obchodu, účet podpory
SHOPZI nikdy. Navýšení tarifu smí schválit jen vlastník, a to s druhým ověřením (heslo nebo kód
z e-mailu). Jedno schválení platí **60 minut** a na **jedno provedení**, patří tomu klíči, který
o ně požádal, a tomu nástroji a argumentům, na které se ptal. `idempotencyKey` se do otisku
argumentů nepočítá, takže vlastní klíč při opakování nevadí; server ho při provedení stejně nahradí
klíčem `mcp-approval:<id>`, aby se jedno schválení nedalo provést dvakrát. Na jednom klíči může
na schválení čekat nejvýš 20 akcí a za klouzavou hodinu jich klíč založí nejvýš 30, bez ohledu na
to, jak skončily; obojí odmítne s kódem `conflict` a českou větou, na co počkat. O novém schválení
se vlastníci a manažeři dozvědí upozorněním ve zvonku v administraci a počet čekajících změn ukazuje
i karta **Externí přístup** v **Nastavení → API a MCP**. Jak schválení vypadá
z pohledu obchodníka, popisuje
[Schválení změn z AI asistenta](/dokumentace/nastaveni/schvaleni-zmen-agenta).

> **Schvalovací karta patří Agentovi v administraci** Obrazovka s hodnotou Nyní vedle Nově je součást panelu Agenta uvnitř obchodu, ne MCP. Kdo staví klienta, ať s ní nepočítá: přes MCP se ptáme vloženým dotazem podle protokolu, a jak ho zobrazit, je věc klienta.

## Vrácení změn [#vraceni-zmen]

Zápisové oprávnění existuje skoro vždycky jen tam, kde umíme změnu **vrátit**. Nástroj si před
zápisem uloží předchozí hodnoty a v odpovědi vrátí identifikátor změny, kterým ji nástroj
`shopzi_undo_change` zase odčiní.

Proto k prvnímu zápisovému oprávnění zaškrtněte i **vrácení změn agenta**: bez něj asistent obchod
změní, ale už to nikdo nedokáže vzít zpět. Formulář ta dvě zaškrtávátka nespojuje, takže je to na
vás; rychlé volby se zápisem (Objednávky a sklad, Obsah a marketing, Vše) ho obsahují samy.

Co vrátit nejde, na to zápisové oprávnění většinou vůbec není: rozeslaná kampaň, vystavený doklad,
vrácení peněz zákazníkovi a nebezpečná zóna. Zbytek jsou zápisy, které provést jdou, ale jejich
vrácení nástroj odmítne s vysvětlením, a proto se na ně napřed ptá. Patří mezi ně hlavně:

* **změna stavu objednávky a označení objednávky za zaplacenou** (zákazníkovi odešel e-mail,
  u zaplacení se navíc zapsala tržba),
* **založení a posun zásilky** (u dopravce s napojením je zásilka objednaná doopravdy),
* **opětovné odeslání vystavené faktury** (`resend_invoice`; zákazníkovi odešel e-mail, doklad se
  nezměnil) a **rozhodnutí o velkoobchodní žádosti** (vrácení vrátí stav žádosti, e-mail
  zákazníkovi ne),
* **schválení položek vratky** (`approve_return`; nevrací se, ale dokud k vratce není dobropis,
  přepíše ho nové schválení),
* **založení vratky, naskladnění z vratky a zpětná zásilka** (vratka dostala číslo z řady, pohyb ve
  skladu je skutečný a Zásilkovna zákazníkovi sama napsala),
* **smazání souboru z Médií nebo fotky produktu** (soubor je pryč z úložiště),
* **odebrání variant, přidání os variant a převod na jednoduchý produkt** (`remove_variants`,
  `set_variant_axes`, `collapse_to_simple`; odebraná varianta jde přidat jen jako nová, bez
  historie cen, a proto nástroj odmítne variantu se zásobou, na objednávce nebo v balíčku),
* **generování obrázku nebo videa a hledání na webu** (kredity se strhávají při zadání),
* **hromadná AI úprava produktů** a **úklid ukázkových produktů**,
* **zápisy feedů dodavatelů** (`shopzi_manage_supply` se zdroji `feed_subscription`,
  `pricing_rule`, `feed_approval`, `feed_access`, `feed_lock`, `own_feed`
  a `feed_supplier_order`): odběr se pozastavuje, pravidlo maže a rozhodnutí ve frontě je
  rozhodnutí, nic z toho se nevrací snímkem. Schválení dropship objednávky ve frontě i její nové
  odeslání ji pošle dodavateli e-mailem a dodavatel podle ní pošle zboží zákazníkovi. Míru
  automatizace odběru asistent smí jen snížit, zvýšit ji může jen člověk v administraci,
* **tři kroky nastavení obchodu**: připojení a ověření domény, žádost o Comgate a spuštění obchodu;
  vlastník o nich dostane e-mail, viz oddíl **Nastavení obchodu z terminálu** níž,
* **navýšení tarifu**, které mimo zkušební období strhne peníze z karty (oddíl **Předplatné
  z terminálu**).

Hranice vede uvnitř oblastí, ne kolem nich, a to je na ní to podstatné:

* **Feed** se nastavit dá (kanály, mapování kategorií i výjimky u položek). Co nejde, je
  **vygenerovat ho znovu**: ten soubor si srovnávač stáhne a zpátky se nevezme.
* **Přesměrování adres** (`shopzi_update_settings`, sekce `redirects`) se založit, přesměrovat
  jinam a zapnout dá a vrací se. Smazat, vypnout ani změnit zdrojovou adresu nejde: všechny tři
  pošlou adresu, kterou zná vyhledávač, na 404.
* **Faktura** se vystavit nedá, ale už vystavenou jde poslat znovu (`resend_invoice`) a u faktury
  bez objednávky zapsat zaplacení (`set_invoice_paid`, vrací se), stejně jako v detailu faktury
  v administraci.
* **Stav platby** u objednávky posunout jde, a to dvěma cestami, které se liší přísností.
  Párování podle bankovního výpisu (`match_payment_by_vs`) potvrdí platbu jen tehdy, když sedí
  **na haléř i na variabilní symbol**; cokoli nejednoznačného jde k ručnímu posouzení. Přímé
  označení (`set_payment_status`) žádný výpis nevyžaduje, jen se na ně nástroj napřed zeptá.
  Označení platby za přijatou pošle zákazníkovi potvrzení, zapíše tržbu a **u objednávky placené
  kartou nebo na dobírku vystaví daňový doklad**; vzít zpět to nejde. Platební bránu ani bankovní
  spojení nástroj nezapíše a fakturační identitu jen podle IČO ověřeného v ARES (sekce `company`
  níž), nikdy z textu, který napíše model.

Podrobný soupis hranic je v článku
[Co Agent umí v obchodě změnit](/dokumentace/zaciname/agent-co-umi-zmenit).

## Měsíční strop kreditů klíče [#mesicni-strop-kreditu-klice]

Každý klíč má **měsíční strop kreditů**: nový klíč dostane **2 000 kreditů**, pokud mu vlastník při
vytvoření nenastaví jiný. Než se provede volání, které kredity utrácí, server jeho cenu **napřed
započítá** do stropu klíče; když by ho překročila, nástroj odmítne s kódem `credit_cap_exceeded`
a nestrhne se nic. Strop se počítá po kalendářních měsících českého času a obnoví se **prvního dne
dalšího měsíce**. Strop nastavený na nulu utrácení klíči vypíná úplně a nový měsíc na tom nic
nezmění.

Nástroj, který nakonec odmítne sám, započtenou cenu vrátí; opakované doručení už hotového volání
(stejný klíč idempotence) se do stropu nepočítá podruhé. Cena naopak zůstane započtená, když
nástroj práci udělal a jen jeho odpověď se nevešla do limitu velikosti, a když skončil vnitřní
chybou: tam se nedá poznat, jestli se kredity stihly utratit.

Strop platí pro každý klíč zvlášť, takže kredity obchodu vyčerpané být nemusí. **Strop klíče upraví
vlastník obchodu** v **Nastavení → API a MCP** ikonou **Upravit klíč** v řádku
klíče (pole **Měsíční strop kreditů**), s druhým ověřením jako u vydání klíče. Kolik kreditů klíče
za období utratily, ukazuje tamtéž část **Využití**. Když strop nejde přečíst, server utrácení
odmítne, místo aby ho pustil bez kontroly.

## Záznam o voláních [#zaznam-o-volanich]

Záznam o voláních serveru MCP najde vlastník nebo manažer obchodu
v **Nastavení → API a MCP** v části **Protokol volání** (filtr **Plocha**
na **Server MCP**), denní součty na klíč v části **Využití**. Obchod si o každém volání ukládá
záznam **bez obsahu**: čas, jméno nástroje, výsledek a strojový kód odmítnutí, stavový kód, dobu
zpracování, kredity započtené do stropu klíče, klíč, IP adresu, jméno klienta z `clientInfo` (když
chybí, z hlavičky `User-Agent`) a revizi protokolu. Argumenty nástroje, jeho výsledek ani text
odmítnutí se neukládají nikde.

* **Každé volání nástroje je právě jeden záznam**, i to, které se jen zeptá (`confirmation_asked`),
  čeká na schválení v administraci (`approval_pending`, u nově založeného schválení s kódem
  `approval_required`), narazí na strop kreditů klíče (`credit_cap`) nebo na strop volání klíče
  (`rate_limited`). Potvrzená změna jsou proto dva záznamy: otázka a provedení.
* Záznam vznikne i za volání nástroje, na který klíč nedosáhne (`insufficient_scope`), za nástroj,
  který neexistuje, za požadavek, který neprošel ověřením klíče, a za našeptávání hodnot
  (`completion/complete`), které se počítá i do stropu volání klíče.
* `tools/list`, `prompts/list`, `prompts/get`, `ping`, `server/discover` a notifikace se
  nezapisují.

Neúspěšných volání se zapíše jen omezený počet, stejně jako u REST API: bez platného klíče nejvýš
60 za hodinu na obchod, s platným klíčem nejvýš 1 000 za kalendářní den na klíč a plochu. Nad tyto
počty zůstávají jen denní součty na klíč. Otázka a čekání na schválení se mezi neúspěšná volání
nepočítají. Záznamy mažeme po 30 dnech, denní součty na klíč po 90 dnech.

## Nastavení obchodu z terminálu [#nastaveni-obchodu-z-terminalu]

Obchod se dá z klienta nastavit od firmy až po spuštění. Co vidí průvodce v administraci, vrátí
`shopzi_get_settings&#x60; se sekcí **`setup`**: stav kroků průvodce (u povinných i to, jestli je
potvrzují data), co brání spuštění, závěs webu, vlastní domény i s DNS záznamy a úkoly, které se
dělají jen v prohlížeči.

Zápis jde přes `shopzi_update_settings`, sekci v `resource` a hodnoty v poli `setup`:

| Sekce             | Co pošlete                                                                                      | Co se stane                                                                                                                                                                                                                       |
| ----------------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `company`         | `ico`                                                                                           | Název, adresa a DIČ se doplní z ARES. Neznámé IČO ani výpadek ARES nic nezapíšou. Plátcovství DPH se nemění, potvrzuje ho člověk v prohlížeči (`open_task: "vat_payer"`).                                                         |
| `contact`         | `email`, `phone`                                                                                | Změní kontakt obchodu, přes MCP nejvýš třikrát za 24 hodin (pak `conflict`). O změně e-mailu dostanou zprávu vlastníci a původní adresa, pokud ji za posledních 24 hodin nenastavil přístupový klíč. Zpráva nenese žádnou adresu. |
| `legal`           | `documents` (`terms`, `gdpr`, `refund`, `withdrawal`, `delivery`, `cookies`), `withdrawal_days` | Dokumenty ze šablony s údaji firmy, lhůta aspoň 14 dnů. Bez nastavené firmy odmítne kódem `conflict`, protože by v dokumentech zůstaly hranaté závorky. Volný text dokumentu nástroj nepíše.                                      |
| `domain`          | `action` (`connect`, `verify`), `domain`                                                        | Připojí doménu (DNS záznamy jsou ve výsledku v `after`), nebo ji ověří. Po ověření se obchod na doménu přestěhuje, pokud ještě neběží na jiné vlastní doméně.                                                                     |
| `comgate_request` | nic                                                                                             | Odešle žádost o aktivaci Comgate s údaji firmy z ARES. Bránu nezapíná.                                                                                                                                                            |
| `launch`          | nic                                                                                             | Spustí obchod se stejnými podmínkami jako průvodce: rozhodnuté povinné kroky a IČO ověřené v ARES.                                                                                                                                |

Firma, kontakt a dokumenty se vrací přes `shopzi_undo_change`. **Doménu, žádost o Comgate
a spuštění vrátit nejde**: vrácení odmítne s vysvětlením a vlastník obchodu dostane o každé z těch
změn e-mail. Povinný krok průvodce (`resource: "onboarding"`) jde odškrtnout jen tehdy, když ho
potvrzují data; přeskočit ho jde.

### Předávka do prohlížeče [#predavka-do-prohlizece]

Plátcovství DPH, číslo účtu, propojení se Stripe, přístupové údaje ke Comgate, SMTP a dopravcům,
vlastní úprava právních dokumentů a nákup domény terminálem ani modelem neprojdou. Pošlete
`shopzi_get_settings` se sekcí `setup` a `open_task` (`vat_payer`, `bank_account`,
`stripe_connect`, `comgate_credentials`, `smtp`, `carrier_credentials`, `legal_edit`,
`domain_purchase`):

* klient, který deklaruje `elicitation.url`, dostane úkol jako **elicitaci s odkazem** na přesnou
  obrazovku administrace; opakované kolo pak vrátí běžný výsledek,
* ostatní klienti dostanou výsledek rovnou a absolutní odkaz najdou u úkolu v `browser_tasks`.

U úkolu se hlásí jen stav `done` nebo `pending`, nikdy hodnota: číslo účtu ani heslo se neposílá.

## Předplatné z terminálu [#predplatne-z-terminalu]

Stav předplatného vrátí `shopzi_get_settings&#x60; se sekcí **`billing`** (stačí oprávnění ke čtení
nastavení): tarif a periodu, příští obnovu, naplánovanou změnu, využití proti limitům tarifu
(produkty, úložiště, týmové účty, feedy, marketingové rozesílky), zůstatky kreditů a balíčky,
posledních pět faktur od SHOPZI a odkazy do administrace. Faktury vystavuje SHOPZI (WEBZI s.r.o.,
neplátce DPH) vlastní řadou SZ za tarif, kredity i doménu, nečtou se ze Stripe. U faktury je číslo
(`number`), datum vystavení, za co (`description`), částka v haléřích (i jako hotový text `amount`)
s měnou, stav (vždy `paid`, faktura se vystavuje až po zaplacení) a `emailed`, jestli odešla
vlastníkovi e-mailem. **Odkaz na PDF se nevrací**, fakturu si obchodník stáhne
v Nastavení → Předplatné. Když faktury zrovna nejde načíst, přijde `invoices: null` a zbytek sekce
normálně. Měna tarifu (`plan.currency`) je měna předplatného, a když žádné neběží, měna
ceníku; ceníková cena (`plan.price_minor`, jako text `plan.price`) přijde jen v téže měně, jinak
`null`.

Zápis jde přes `shopzi_manage_subscription` s oprávněním `billing:write`. Z předvoleb ho zaškrtává
jen **Vše** a má ho i první klíč obchodu založeného z terminálu.

| Operace               | Co pošlete                                                                                                          | Co se stane                                                                                                                                                                                                                                                                                                                                                                              |
| --------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `upgrade` bez `quote` | `plan` (`start` je Basic, `growth` Standard, `scale` Business, `pro` Enterprise) a `interval` (`monthly`, `annual`) | Ověří, že navýšení jde, a vrátí přesnou částku ze Stripe v `quote` a větu pro člověka. Nic se nestrhne a na nic se neptá.                                                                                                                                                                                                                                                                |
| `upgrade` s `quote`   | totéž a `quote` z předchozího kroku beze změny                                                                      | Zeptá se člověka a po potvrzení provede změnu. Mimo zkušební období zní otázka „Nyní se strhne X Kč, dál Y Kč měsíčně. WEBZI s.r.o. není plátcem DPH.“ a rozdíl se strhne z karty uložené u SHOPZI. Ve zkušebním období se nestrhne nic: otázka říká „Teď se nestrhne nic, zkušební období běží dál. Od \<datum> zaplatíte …“ a mění se jen částka od první platby, jejíž datum zůstává. |
| `credit_pack_link`    | volitelně `package` (id balíčku ze sekce `billing`)                                                                 | Vrátí odkaz do administrace na nákup kreditů. Nic neúčtuje; platí se až po přihlášení v prohlížeči.                                                                                                                                                                                                                                                                                      |

Pravidla navýšení:

* **Jen nahoru.** Vyšší tarif ve stejné periodě, nebo z měsíční na roční platbu u stejného či
  vyššího tarifu. Nižší tarif, stejný tarif i přechod z roční na měsíční platbu odmítne kódem
  `invalid_input`. Snížit ani zrušit předplatné tudy nejde vůbec.
* **Jen běžící předplatné s kartou.** Ve zkušebním období to jde také, pokud je karta uložená: nic
  se nestrhne, vymění se jen položka předplatného a datum první platby zůstává, kde bylo. Tarif
  tarif Free, jednorázová licence, předplatné ve vymáhání platby nebo nastavené ke zrušení a naplánovaná
  změna tarifu odmítnou kódem `conflict` s větou, co udělat v administraci. Stejně skončí obchod bez
  karty uložené u SHOPZI.
* **Přesná částka, žádný odhad.** Nabídka platí 90 minut. Před otázkou i těsně před platbou server
  spočítá náhled znovu ke stejnému okamžiku; když se liší třeba o haléř, nic nestrhne a odmítne
  kódem `quote_changed` i s novou částkou. `recurringMinor` v nabídce (věta „dál Y Kč“) je další
  pravidelná platba, jak ji spočítá Stripe, tedy i se slevou předplatného, ne ceníková cena.
* **Nejvýš jedna změna za 24 hodin** přes MCP. Zámek se bere až při provedení, tedy po potvrzení
  částky, takže odmítnutí kódem `plan_change_limited` může přijít i po potvrzení; nic se pak
  nestrhne. Čas, od kdy půjde znovu, je v `_meta["cz.shopzi/retryAt"]`. V administraci jde tarif
  změnit hned.
* **Zamítnutá karta** odmítne kódem `payment_declined`: tarif zůstane, nic se nestrhne a zámek
  24 hodin se uvolní, takže po výměně karty jde navýšení zkusit znovu. Uvolní se i tehdy, když
  volání selže dřív, než změna do Stripe vůbec odešla. Když spojení spadne během změny nebo po ní
  a nejde zjistit, jestli se platba strhla, zámek zůstane a provoz SHOPZI dostane upozornění.
* **Kdo potvrzuje.** Klient s elicitací formulářem se zeptá sám. Klient bez elicitace dostane
  `approval_required` a navýšení v administraci smí schválit **jen vlastník obchodu s druhým
  ověřením**, manažer ani účet podpory SHOPZI ne.
* **Opakování nestrhne podruhé.** Druhé doručení téhož potvrzeného kola, nové volání se stejným
  `idempotencyKey` i opakované volání po schválení v prohlížeči nebo přes elicitaci URL vrátí
  původní výsledek s `replayed: true`.
* **Po navýšení** dostanou vlastníci obchodu e-mail a v administraci upozornění, deník změn má
  záznam a `shopzi_undo_change` ho vrátit odmítne: vyšší tarif od té chvíle platí, a běželo-li
  obchodu placené období, platba z karty už proběhla. `charged_minor` s `currency` je stržená
  částka přesně z faktury Stripe; když ji Stripe v odpovědi neuvede, jsou obě `null`, věta pro
  člověka to řekne a z nabídky se nic nedoplňuje. Snížit tarif jde v administraci, a to od konce
  zaplaceného období.

Jak to celé vypadá z pohledu obchodníka, popisuje článek
[Navýšení tarifu z AI asistenta](/dokumentace/nastaveni/navyseni-tarifu-z-asistenta).

## Rejstřík nástrojů [#rejstrik-nastroju]

Nástrojů je 40, z toho 19 jen ke
čtení a 21 zápisových. Tabulka se generuje z rejstříku, ze
kterého odpovídá i sám server:

| Nástroj | Co dělá | Oblast | Oprávnění | Režim |
| --- | --- | --- | --- | --- |
| `shopzi_get_product` | Detail produktu | Katalog | `products:read` | čtení |
| `shopzi_list_catalog` | Katalog: kategorie, dodavatelé, vlastnosti, ceníky | Katalog | `products:read` | čtení |
| `shopzi_search_products` | Vyhledat produkty | Katalog | `products:read` | čtení |
| `shopzi_manage_category` | Založit, upravit, přesunout, přeskládat nebo smazat kategorii | Katalog | `products:write` | zápis, napřed se zeptá |
| `shopzi_manage_product` | Založit, upravit, archivovat nebo zařadit produkt | Katalog | `products:write` | zápis, napřed se zeptá |
| `shopzi_save_catalog_entity` | Spravovat dodavatele a vlastnosti produktů | Katalog | `products:write` | zápis, napřed se zeptá |
| `shopzi_get_order` | Detail objednávky | Objednávky a vratky | `orders:read` | čtení |
| `shopzi_list_returns` | Vratky a reklamace | Objednávky a vratky | `orders:read` | čtení |
| `shopzi_search_orders` | Objednávky (seznam, hledání a štítky Zásilkovny) | Objednávky a vratky | `orders:read` | čtení |
| `shopzi_manage_order` | Objednávka: stav, platba, nacenění, zásilky a vratky | Objednávky a vratky | `orders:write` | zápis, napřed se zeptá |
| `shopzi_list_inventory` | Sklad: pohyby, inventury, dodavatelé, nákup | Sklad a nákup | `stock:read` | čtení |
| `shopzi_stock_report` | Stav skladu | Sklad a nákup | `stock:read` | čtení |
| `shopzi_adjust_stock` | Naskladnit, opravit nebo odepsat zásobu | Sklad a nákup | `stock:write` | zápis, napřed se zeptá |
| `shopzi_manage_supply` | Dodavatelé, objednávky zboží a inventury | Sklad a nákup | `stock:write` | zápis, napřed se zeptá |
| `shopzi_get_content` | Detail stránky, článku nebo obrázku z Médií | Obsah a média | `content:read` | čtení |
| `shopzi_list_content` | Obsah: stránky, blog, sekce, média a fotky produktu | Obsah a média | `content:read` | čtení |
| `shopzi_generate_media` | Vygenerovat obrázek nebo video | Obsah a média | `content:write` | zápis, stojí kredity, napřed se zeptá |
| `shopzi_manage_content` | Založit, upravit nebo smazat stránku, článek, rubriku, soubor a fotky produktu, přepočítat úložiště | Obsah a média | `content:write` | zápis, napřed se zeptá |
| `shopzi_save_page_blocks` | Uložit bloky stránky | Obsah a média | `content:write` | zápis, napřed se zeptá |
| `shopzi_save_storefront_layout` | Upravit hlavičku a patičku obchodu | Obsah a média | `content:write` | zápis, napřed se zeptá |
| `shopzi_list_marketing` | Slevy, feedy, kampaně, okna a segmenty | Marketing | `marketing:read` | čtení |
| `shopzi_save_discount_code` | Založit, upravit, smazat nebo hromadně přepnout slevový kód | Marketing | `marketing:write` | zápis, napřed se zeptá |
| `shopzi_save_marketing_entity` | Okno, kampaň, segment a nastavení feedů do srovnávačů | Marketing | `marketing:write` | zápis, napřed se zeptá |
| `shopzi_list_customers` | Zákazníci, skupiny, recenze, zprávy a žádosti GDPR | Zákazníci a hodnocení | `customers:read` | čtení |
| `shopzi_manage_customer` | Založit zákazníka, rozhodnout o velkoobchodu nebo oštítkovat | Zákazníci a hodnocení | `customers:write` | zápis, napřed se zeptá |
| `shopzi_moderate_review` | Moderovat recenzi | Zákazníci a hodnocení | `customers:write` | zápis, napřed se zeptá |
| `shopzi_get_settings` | Nastavení obchodu | Nastavení a vyhledávání | `settings:read` | čtení |
| `shopzi_manage_search` | Vyhledávání: synonyma, přesměrování, připnutí a fasety | Nastavení a vyhledávání | `settings:write` | zápis, napřed se zeptá |
| `shopzi_update_settings` | Upravit nastavení obchodu | Nastavení a vyhledávání | `settings:write` | zápis, napřed se zeptá |
| `shopzi_update_appearance` | Upravit vzhled obchodu | Vzhled | `appearance:write` | zápis, napřed se zeptá |
| `shopzi_save_shipping_method` | Založit nebo upravit metodu dopravy | Doprava | `shipping:write` | zápis, napřed se zeptá |
| `shopzi_list_tasks` | Úkoly | Úkoly | `tasks:read` | čtení |
| `shopzi_manage_task` | Založit, upravit nebo smazat úkol | Úkoly | `tasks:write` | zápis, zeptá se podle operace |
| `shopzi_get_analytics` | Statistiky: návštěvnost, SEO, tržby, prodeje a hledání | Statistiky | `analytics:read` | čtení |
| `shopzi_list_documents` | Vydané doklady | Doklady | `documents:read` | čtení |
| `shopzi_list_changes` | Změny provedené agentem | Vrácení změn | `undo:write` | čtení |
| `shopzi_undo_change` | Vrátit změnu agenta | Vrácení změn | `undo:write` | zápis, napřed se zeptá |
| `shopzi_docs` | Dokumentace SHOPZI | Dokumentace | `docs:read` | čtení |
| `shopzi_web_search` | Hledání na webu (externí zdroje) | Hledání na webu | `web:read` | čtení, stojí kredity, napřed se zeptá |
| `shopzi_manage_subscription` | Navýšit tarif nebo podat odkaz na nákup kreditů | billing | `billing:write` | zápis, zeptá se podle operace |

Sloupec **Režim** říká, jestli se server před provedením zeptá, a počítá se týmž pravidlem jako
potvrzování samo (oddíl **Co se stane při zápisu** výš): „napřed se zeptá“ znamená každé volání,
„stojí kredity“ nástroj, který kredity strhává při každém volání (hledání na webu, generování
obrázků a videí), a „zeptá se podle operace“ nástroj, u kterého se některé operace neptají.
Takové jsou dva: `shopzi_manage_task` se neptá na založení úkolu a `shopzi_manage_subscription` se
neptá na spočítání nabídky navýšení tarifu (`upgrade` bez `quote`) ani na odkaz na nákup kreditů.

Popisy nástrojů, vstupní a výstupní schémata a výčty rozlišovačů dostane klient v odpovědi na
`tools/list`. Tady jsou schválně vynechané: dohromady mají desítky tisíc znaků a to, co potřebuje
vývojář před připojením, je, co existuje a co to chce za oprávnění. Parametry každého nástroje
popisuje reference MCP, tedy stránky od [MCP: katalog produktů](/dokumentace/vyvojari/mcp-katalog)
po [MCP: úkoly a vrácení změn](/dokumentace/vyvojari/mcp-ukoly-a-zmeny).

Několik nástrojů, které stojí za zmínku zvlášť: `shopzi_docs` čte obě dokumentace SHOPZI,
uživatelskou i tuhle pro vývojáře, a data obchodu neotevírá vůbec; `shopzi_web_search` je jediný,
který sahá na veřejný internet, každé hledání stojí kredity a funguje jen tehdy, když má obchod
hledání na webu zapnuté v Nastavení → AI; a `shopzi_undo_change` je protiváha ke všem zápisovým.

`shopzi_get_content` s `resource: "media"` a `mediaUrl` (adresa `/media/…&#x60; z knihovny Médií) vrátí
údaje o souboru a za textovým blokem i blok **`image`** (`mimeType: image/jpeg`), aby model viděl, co
na obrázku je. Obrázek je zmenšený na delší hranu 1 024 px a na jedno volání je jeden. Soubor, který
prohlédnout nejde (jiný formát než JPEG, PNG, WebP, GIF nebo AVIF, tedy i SVG, PDF a video, nebo
soubor nad 15 MB), přijde bez bloku `image`, s `viewable: false` a důvodem v `not_viewable_reason`.
Adresu server ověřuje proti obchodu klíče: adresa mimo veřejnou knihovnu Médií (jiný server,
důvěrný dokument) skončí odmítnutím `invalid_input` a soubor, který v knihovně tohohle obchodu
není, odmítnutím `not_found`.

Připojení konkrétního klienta popisuje článek
[Připojení asistenta k obchodu](/dokumentace/vyvojari/pripojeni-asistenta). Marketingový přehled
i s ukázkou odpovědi na `tools/list` je na stránce [MCP](/mcp).
