MCP vs REST: kiedy co wygrywa dla integracji agentów AI
Traktowanie MCP i REST jako alternatyw to zła rama. Siedzą na różnych warstwach: REST to transport plus konwencje, MCP to typowany protokół zaprojektowany pod konsumenta LLM. Realna decyzja to z którą powierzchnią rozmawia każdy konsument i jak dwie powierzchnie dzielą backend. Ten artykuł podaje framework, którego używam przy wycenie integracji AI dla projektów WordPress i WooCommerce.
Artykuł osadzony jest w filarze budowa serwera MCP.
TL;DR
- MCP i REST są komplementarne, nie alternatywne.
- REST wygrywa dla deterministycznych klientów z hardkodowanym zestawem akcji i dokumentacją OpenAPI.
- MCP wygrywa dla agentów LLM potrzebujących discovery narzędzi w runtime oraz typowanych schematów z adnotacjami zachowania dla akcji mutujących.
- Default produkcyjny to REST jako system of record, MCP jako powierzchnia agenta z przodu.
- Ten sam backend, dwie powierzchnie, jedna prawda.
Czym jest MCP, a czym REST API
REST. Styl architektoniczny z dysertacji Roya Fieldinga z 2000 roku (źródło dysertacji), zwykle wyrażany przez HTTP z czasownikami i URL-ami zasobów. WordPress udostępnia REST API pod /wp-json/wp/v2/ (handbook REST API WordPressa); WooCommerce rozszerza go pod /wp-json/wc/v3/. Dokumentacja to zwykle OpenAPI (specyfikacja OpenAPI), a SDK są generowane z schematu w build-time.
MCP. Protokół oparty na JSON-RPC 2.0, ogłoszony przez Anthropic 25 listopada 2024 (ogłoszenie Anthropic) do łączenia hostów LLM (Claude Desktop, IDE, własne runtime’y agentów) z danymi i narzędziami. Trzy prymitywy: tools (wywoływalne funkcje), resources (odczytywalne dokumenty), prompts (szablony serwerowe). Discovery dzieje się w runtime przez tools/list. Od rewizji 2026-07-28 protokół nie ma już sesji: każde żądanie niesie wersję protokołu i możliwości klienta, a klient pobiera listę ponownie, gdy kopia w cache wygaśnie albo przyjdzie powiadomienie o zmianie.
Z dystansu kształty wyglądają podobnie. Pod obciążeniem szybko się rozjeżdżają.
Macierz wyboru MCP czy REST API
Sześć czynników, które oceniam, zanim wybiorę powierzchnię dla danej akcji:
| Czynnik | Sprzyja REST | Sprzyja MCP |
|---|---|---|
| Typ konsumenta | Deterministyczny klient web/partnera | Agent LLM |
| Discovery możliwości | Build-time przez OpenAPI | Runtime przez tools/list |
| Kształt akcji | Stały, dobrze znany | Swobodna intencja |
| Bezpieczeństwo mutacji | Semantyka metod HTTP (RFC 9110) | inputSchema + adnotacje readOnlyHint, destructiveHint, idempotentHint (tylko wskazówki) |
| Uwierzytelnianie | Tokeny bearer, OAuth | To samo plus tagowanie scope’ów per narzędzie |
| Cache | Nagłówki HTTP | ttlMs i cacheScope na listach; tools/call bez wskazówki cache |
Macierz mówi mi, który protokół jest preferowany dla jednej akcji, a nie dla całego API. Większość projektów ląduje rozdzielona.
Kiedy REST API sprawdza się lepiej niż MCP
Sklep pobierający stronę kategorii. Hardkodowany przeciw /wp-json/wp/v2/categories?slug=widgets. Kształt znany, nagłówki cache działają, CDN może cache’ować po URL-u.
Integracja ERP partnera synchronizująca magazyn dziennie. Zespół partnera czyta OpenAPI, generuje typowane SDK, planuje cron na 03:00 UTC. Chcą stabilnych URL-i, przewidywalnych kształtów odpowiedzi i kodów statusu HTTP. MCP dodałby złożoność bez wartości.
Publiczny anonimowy ruch odczytu. Crawler SEO uderzający w strony produktów, agregator porównywarek pobierający feedy. REST plus rate limiting obsługuje ten przypadek najbardziej dojrzałą infrastrukturą.
Dostarczanie webhooków. Gdy zamówienie zmienia status, webhook WooCommerce wysyła zdarzenie do endpointa partnera. Endpoint partnera to odbiorca HTTP. MCP to zły kształt, bo agent nie jest w pętli; odbiorca to system deterministyczny.
Kiedy MCP sprawdza się lepiej niż REST
Agent LLM działający na swobodną intencję użytkownika. “Znajdź mi wodoodporną kurtkę poniżej 800 zł, która dojedzie do Warszawy.” Agent z góry nie wie, jaką kombinację filtrów zastosować; musi introspektować dostępne narzędzia, czytać opisy, decydować. REST daje mu parametry query rozrzucone po kilku endpointach i żadnego sygnału, który zastosować.
Akcje mutujące, gdzie idempotencja ma znaczenie. Tworzenie zamówienia z LLM-a jest najgłośniejszym przykładem. Narzędzie MCP order.intent z typowanym schematem wejścia, obowiązkowym parametrem idempotency_key i destructiveHint: false mówi agentowi i klientowi, co wywołanie zrobi, zanim się wykona. Protokół nie gwarantuje idempotencji: to handler musi odrzucić drugie zamówienie z tym samym kluczem. Różnica wobec swobodnego POST /wp-json/wc/v3/orders polega na kontrakcie, który model potrafi przeczytać.
Powierzchnia narzędzi ewoluująca często. Dodanie nowego filtra wyszukiwania lub nowego typu produktu oznacza wypuszczenie nowego narzędzia MCP z polami description i inputSchema. Serwer wysyła notifications/tools/list_changed klientom, którzy otworzyli subscriptions/listen, a agent podchwytuje narzędzie przy następnym tools/list bez zmian kodu po stronie agenta. Przy REST każda zmiana to skoordynowane wydanie SDK.
Wieloetapowe przepływy agenta. “Sprawdź, czy SKU AC-101 jest na stanie; jeśli nie, zaproponuj trzy alternatywy; jeśli jest, zaproponuj zamówienie.” Każdy krok to jedno wywołanie narzędzia; agent je komponuje. Przy REST agent musi zakuć kształt przepływu w prompcie.
MCP i REST w sklepie WooCommerce
Dla typowego projektu WooCommerce rysuję granicę tak:
| Akcja | Konsument | Powierzchnia |
|---|---|---|
| Publiczne przeglądanie katalogu | Klient web, crawlery | REST |
| Render strony produktu | Klient web | REST |
| Sync magazynu (B2B) | ERP partnera | REST + OpenAPI |
| Dostarczanie webhooków | Endpointy partnerów | REST |
| Agent: szukaj produktu | LLM | MCP |
| Agent: status zamówienia | LLM | MCP |
| Agent: zaproponuj zamówienie | LLM | MCP |
| Agent: anuluj zamówienie | LLM | MCP |
| Operacje admina | Admin WordPressa | REST + auth ciasteczkowy |
Handlery narzędzi serwera MCP wołają te same endpointy /wp-json/wc/v3/, których używają konsumenci REST. Jedno źródło prawdy dla warstwy danych, dwie powierzchnie dla dwóch typów konsumenta.
Uwierzytelnianie i scope’y OAuth w MCP i REST API
REST API WordPressa ma trzy udokumentowane ścieżki (uwierzytelnianie w REST API). Uwierzytelnianie ciasteczkiem służy kodowi działającemu na samej stronie i wymaga nonce’a akcji wp_rest, wysyłanego w nagłówku X-WP-Nonce; bez nonce’a żądanie wykonuje się jako anonimowy użytkownik, nawet przy aktywnej sesji. Application Passwords są w core od WordPressa 5.6 i działają z HTTP Basic, wyłącznie przez HTTPS. OAuth 1.0a i JSON Web Tokens dochodzą przez wtyczki. Doszlifowanie uprawnień dzieje się per trasa, w capabilities użytkownika i w permission_callback każdego endpointa.
Autoryzacja w MCP jest opcjonalna i dotyczy transportów HTTP; przy stdio poświadczenia pochodzą ze środowiska. Gdy jest używana, serwer MCP jest resource serverem OAuth 2.1, musi publikować Protected Resource Metadata (RFC 9728) i przyjmuje tylko tokeny wydane dla siebie: klient wskazuje serwer w parametrze resource (RFC 8707), a serwer odrzuca tokeny z inną audiencją. Serwer nie może też przyjmować ani przekazywać dalej innych tokenów, więc do WordPressa uwierzytelnia się własnymi poświadczeniami, na przykład Application Password użytkownika z ograniczoną rolą.
Scope’y działają jak w każdym API z OAuth, z dwiema regułami przydatnymi dla agentów. Serwer może zwrócić w tools/list tylko te narzędzia, na które pozwalają scope’y tokena. A gdy wywołanie potrzebuje więcej, odpowiada HTTP 403 z error="insufficient_scope" i wymaganymi scope’ami w nagłówku WWW-Authenticate, żeby klient poprosił o nową autoryzację z poszerzonym zestawem. Użytkownik nadaje agentowi orders:read; agent w ogóle nie widzi order.cancel, a jeśli spróbuje je wywołać, dostaje 403, zanim uruchomi się handler. OpenAPI opisuje to samo przez securitySchemes i security per operacja (specyfikacja OpenAPI), ale w praktyce wiele API REST dokumentuje jeden globalny scope i zostawia drobniejszą granulację aplikacji.
Konkretnie dla integracji agentów mapowanie scope’ów per narzędzie jest realnym ergonomicznym zyskiem, pasującym też do wymagań RODO o minimalizację danych. Pod spodem mechanizm to ten sam OAuth, który zna REST, ale kontrakt jest czytelniejszy zarówno dla użytkownika, jak i dla agenta.
Czym różni się cache odpowiedzi MCP od cache HTTP w REST
REST ma dekady infrastruktury cache HTTP: nagłówki Cache-Control, rewalidacja ETag, reguły Vary, cache na CDN-ie, w przeglądarce, w pośrednich proxy. Odpowiedź GET /wp-json/wc/v3/products?stock_status=instock z Cache-Control: public, max-age=60 cache’uje się na edge bez dodatkowej pracy.
W MCP rewizja 2026-07-28 wprowadziła część tego (cache w MCP). Wyniki tools/list, prompts/list, resources/list, resources/templates/list i resources/read muszą nieść ttlMs, działające jak max-age, oraz cacheScope z wartościami public i private, analogicznymi do tych z Cache-Control. Wyniki tools/call, czyli większość ruchu agenta, nie są na tej liście. Jadą jako payloady JSON-RPC w żądaniach POST i nagłówki cache HTTP ich nie dotyczą. Cache wywołań musi się dziać na poziomie aplikacji, w handlerze narzędzia, przeciw jawnemu kluczowi wywiedzionemu z wejścia. To jest OK, gdy handlery serwera MCP same cache’ują wywołanie REST w górę (co robię na produkcji), ale oznacza, że warstwa cache to twój problem do zaprojektowania.
To najsilniejszy argument za zostawieniem publicznego ruchu odczytu na REST, a do MCP kierowaniem tylko ruchu agenta. Infrastruktura cache HTTP jest zbyt cenna, by ją oddać dla powierzchni publicznej.
Adnotacje narzędzi MCP a idempotentne metody HTTP
W REST bezpieczeństwo operacji siedzi w samej metodzie. RFC 9110 definiuje GET, HEAD, OPTIONS i TRACE jako metody bezpieczne, a PUT, DELETE i metody bezpieczne jako idempotentne: wiele identycznych żądań ma ten sam zamierzony skutek co jedno. POST idempotentny nie jest. Proxy, crawler czy biblioteka ponawiania decyduje, co wolno powtórzyć, na podstawie samej metody, bez czytania treści żądania.
MCP wysyła wszystko jako tools/call w POST, więc metoda nic nie mówi. Ta informacja przechodzi do definicji narzędzia. Schemat specyfikacji definiuje cztery logiczne adnotacje w ToolAnnotations:
| Adnotacja | Znaczenie | Wartość domyślna |
|---|---|---|
readOnlyHint | narzędzie nie zmienia swojego otoczenia | false |
destructiveHint | może wykonywać zmiany niszczące, a nie tylko addytywne | true |
idempotentHint | powtórzenie wywołania z tymi samymi argumentami nie ma dodatkowego skutku | false |
openWorldHint | działa na otwartym zbiorze zewnętrznych bytów, jak wyszukiwarka internetowa | true |
Wartości domyślne są pesymistyczne: narzędzie bez adnotacji traktuje się jako zdolne do zapisu, do niszczenia danych i nieidempotentne. Specyfikacja zastrzega, że wszystkie te właściwości są wskazówkami, które nie gwarantują wiernego opisu zachowania, i że klient nie powinien podejmować decyzji na podstawie adnotacji z serwerów, którym nie ufa. Strona tools zaleca też człowieka w pętli, który może odrzucić wywołanie, oraz prośby o potwierdzenie przy operacjach wrażliwych.
W sklepie WooCommerce wygląda to tak: product.search dostaje readOnlyHint: true, order.cancel dostaje destructiveHint: true, a idempotencję order.intent zapewnia handler kluczem sprawdzanym po stronie serwera, nie adnotacja. Adnotacja pomaga klientowi zdecydować, kiedy poprosić o potwierdzenie. Nie zastępuje obowiązków serwera, które wymienia specyfikacja: walidacji wszystkich wejść, kontroli dostępu, limitowania liczby wywołań i sanityzacji wyjść.
Jak MCP zgłasza błędy w porównaniu z kodami statusu HTTP
API REST komunikuje błędy kodem statusu: 400 dla źle zbudowanego żądania, 401 bez ważnego uwierzytelnienia, 403 bez uprawnień, 404 dla nieistniejącej trasy. Specyfikacja tools rozdziela dwa poziomy. Błędy protokołu (nieznane narzędzie, żądanie niezgodne ze schematem tools/call, awaria serwera) przychodzą jako zwykłe błędy JSON-RPC, na przykład z kodem -32602. Błędy wykonania (awaria API w górę, data w złym formacie, naruszona reguła biznesowa) przychodzą w wyniku z isError: true i komunikatem tekstowym.
Specyfikacja zaleca, by klienci przekazywali błędy wykonania modelowi, bo niosą informację pozwalającą poprawić argumenty i spróbować ponownie. W serwerze MCP opakowującym REST API WordPressa błąd walidacji 400 zwrócony przez WordPressa powinien stać się wynikiem z isError: true, który nazywa brakujący parametr, a nie błędem protokołu, którego model nie potrafi naprawić.
Wykrywanie endpointów w REST API WordPressa a tools/list w MCP
REST WordPressa też opisuje sam siebie, tylko inaczej. Strony serwisu wysyłają nagłówek Link z rel="https://api.w.org/" wskazujący korzeń API, a korzeń pod /wp-json/ zwraca obiekt z dostępnymi namespaces (wp/v2, wc/v3 i przestrzenie wtyczek), trasami oraz kluczem authentication z obsługiwanymi metodami (discovery w REST API). Żądanie OPTIONS do trasy zwraca jej schemat, zapisany w podzbiorze JSON Schema draft 4 (schemat w REST API).
Różnica tkwi w tym, kto czyta. Indeks WordPressa jest robiony pod programistę albo generator SDK: wymienia wszystkie zarejestrowane trasy, a każda przyjmuje parametry globalne, takie jak _fields (odpowiedzi częściowe, z zagnieżdżonymi właściwościami od WordPressa 5.3), _embed (powiązane zasoby w tej samej odpowiedzi) i _envelope (parametry globalne). Kolekcje stronicują przez per_page do 100 i zwracają sumy w nagłówkach X-WP-Total oraz X-WP-TotalPages (paginacja). Wszystko to dobrze służy zaprogramowanemu klientowi, ale model, który dostanie cały indeks, zużywa kontekst na wybór spośród tras, z których nigdy nie skorzysta.
tools/list w MCP zwraca tylko to, co serwer postanowił wystawić, a każde narzędzie ma description, inputSchema (domyślnie JSON Schema 2020-12) i opcjonalnie outputSchema. Specyfikacja pozwala, by lista zależała od scope’ów tokena, i prosi o deterministyczną kolejność, żeby klient mógł ją trzymać w cache, a model korzystał z cache promptów. Serwer MCP dla WordPressa to w praktyce wyselekcjonowany wycinek indeksu /wp-json/, z opisami pisanymi dla modelu, a nie dla programisty.
WordPress 6.9 dodał element pośredni, Abilities API. Wtyczka rejestruje ability z input_schema, output_schema, opcjonalnym permission_callback i show_in_rest w metadanych. To natywny sposób opisywania jednostek funkcjonalności ze schematem, czyli dokładnie taki kontrakt, jakiego serwer MCP potrzebuje dla każdego narzędzia.
Co zmieniło się w MCP 2026-07-28 dla proxy i load balancerów HTTP
Rewizje z 2025 roku miały handshake initialize, sesje identyfikowane nagłówkiem Mcp-Session-Id i strumień SSE otwierany przez GET. Przy kilku serwerach za load balancerem sesja na połączenie wymusza kierowanie tego samego klienta do tego samego serwera albo współdzielenie stanu między serwerami, a bezstanowy REST tego problemu nie ma. Rewizja 2026-07-28 usunęła wszystkie trzy elementy. Każde żądanie niesie wersję protokołu i możliwości klienta w _meta. Kto potrzebuje stanu między wywołaniami, na przykład koszyka, zwraca jawny identyfikator z jednego narzędzia i przyjmuje go jako argument w kolejnych wywołaniach.
Transport Streamable HTTP zaczął też kopiować metadane do nagłówków. MCP-Protocol-Version i Mcp-Method są obowiązkowe w każdym POST, Mcp-Name także przy tools/call, resources/read i prompts/get, a narzędzie może oznaczyć parametry przez x-mcp-header, żeby wystawić je jako Mcp-Param-{nazwa}. WAF albo gateway może dzięki temu routować lub limitować ruch per narzędzie bez czytania treści JSON. Jeśli nagłówek nie zgadza się z treścią, serwer odpowiada 400 z błędem HeaderMismatch (-32020). Specyfikacja odradza oznaczanie w ten sposób parametrów wrażliwych, bo nagłówki widzą pośrednicy.
Dla kogoś, kto już utrzymuje REST API za CDN-em, obie powierzchnie zbliżają się operacyjnie: te same reguły routingu i rate limitingu po nagłówkach obsłużą jedną i drugą. Cache HTTP nadal nie dotyczy tools/call, bo każde wywołanie to POST.
Jak połączyć MCP i REST na jednym backendzie WordPressa
Domyślna architektura, którą wdrażam dla stron WordPress i WooCommerce z ambicjami agenta AI:
┌──────────────────┐
│ WordPress core │
│ + WooCommerce │
│ (origin REST) │
└────────┬─────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌───────▼────────┐ ┌────▼─────┐ ┌──────▼──────┐
│ Publiczne REST │ │ Webhook │ │ Serwer MCP │
│ (cache na CDN) │ │ delivery │ │ (Workers) │
└───────┬────────┘ └────┬─────┘ └──────┬──────┘
│ │ │
┌───────▼────────┐ ┌────▼─────┐ ┌──────▼──────┐
│ Sklep, feedy │ │ Endpointy│ │ Agent LLM │
│ cenowe, public │ │ partn. │ │ (Claude, │
│ API │ │ │ │ ChatGPT, │
│ │ │ │ │ własny) │
└────────────────┘ └──────────┘ └─────────────┘Ten sam origin WordPressa. Trzy powierzchnie, trzy profile konsumenta. Handlery serwera MCP wołają te same endpointy REST, które cache’uje powierzchnia publiczna; dostarczanie webhooków dzieli z logiką inwalidacji serwera MCP te same hooki zdarzeń WordPressa.
Granica między MCP a REST to decyzja wdrożeniowa, a nie kodowa. Warstwa danych (baza WooCommerce, endpointy REST) jest dzielona. Warstwa prezentacji (typowane narzędzia vs zasoby JSON) jest rozdzielana.
Najczęstsze błędy przy wyborze MCP lub REST
Próba, by MCP robiło robotę REST. Cache’owanie publicznych stron katalogu przez MCP jest złe. Użyj REST plus CDN.
Próba, by REST robiło robotę MCP. Dokumentowanie powierzchni akcji przyjaznej LLM w OpenAPI plus oczekiwanie, że agent “sobie poradzi”, daje kruche wyniki. Agentom lepiej idzie z discovery narzędzi MCP.
Dwie równoległe warstwy danych. Jeśli handlery MCP reimplementują logikę biznesową, zamiast wołać origin REST, każde upgrade’owanie WordPressa psuje obie powierzchnie. Trzymaj warstwę danych w WordPressie; trzymaj powierzchnie protokołu cienkie.
Zapomnienie o koszcie. Serwer MCP to dodatkowa jednostka wdrożeniowa, dodatkowa strategia auth, dodatkowa rzecz do monitorowania. Nie wdrażaj go, jeśli twoim jedynym konsumentem jest integracja ERP partnera; wdroż OpenAPI i nazwij to skończonym.
Powiązane tematy
Ten artykuł omawia decyzję na poziomie protokołu. Przebieg implementacji opisuje budowa serwera MCP dla WooCommerce. Strategię uwierzytelniania pokazują wzorce uwierzytelniania MCP. Projekt typowanych narzędzi opisuje pisanie typowanych narzędzi katalogu z Zod dla MCP. Ścieżkę migracji z istniejącego API opisuje migracja API WordPress do MCP. Strona usługi to budowa serwera MCP.
Wycena indywidualna, bo właściwy kształt zależy od tego, których konsumentów obsługujesz i które akcje wymagają kontraktów klasy agent.







