1. Dlaczego w ogóle potrzebny jest osobny protokół
W tym module wreszcie wyjaśnimy, czym jest MCP (Model Context Protocol) i jak wpisuje się w stos ChatGPT App. Zacznijmy od ustalenia miejsca MCP w architekturze, porównajmy go z „typowym REST” i omówmy podstawowe byty protokołu: tools, resources i prompts.
Wyobraź sobie, że tworzysz zwykły serwis webowy. Zgodnie z tradycją wystawiasz REST API: masz /api/gifts, /api/users, /api/orders, każdy z własnym formatem wejścia i wyjścia, własnymi kodami błędów i autoryzacją. To znajome, ale jest jeden niuans: każdemu klientowi musisz tłumaczyć, co i jak zaimplementowałeś. Dokumentacja, OpenAPI, przykłady, SDK — to wszystko jest potrzebne, bo format API wymyśliłeś sam.
Z ChatGPT App sytuacja się komplikuje. Twoim klientem jest nie tylko frontend, ale także sam model. On potrzebuje:
- dowiedzieć się, jakie operacje są w ogóle dostępne;
- zrozumieć, jakie argumenty są potrzebne każdej operacji;
- wywoływać te operacje w trakcie dialogu, czasem wielokrotnie, czasem z różnymi parametrami;
- interpretować ustrukturyzowaną odpowiedź i decydować, co pokazać użytkownikowi, a co wykorzystać wyłącznie jako kontekst do kolejnej wypowiedzi.
Jeśli każdy deweloper będzie wymyślał własny format API, model trafi do piekła integracji: pod każdą App potrzebny będzie niestandardowy klient, masa „obudowy” i krucha logika. Problem rozwiązuje pomysł protokołu.
MCP (Model Context Protocol) to otwarta specyfikacja standardowego sposobu, w jaki klient LLM (ChatGPT, wtyczka IDE, agent itp.) komunikuje się z Twoim serwerem narzędzi i danych. Określa wspólny język, w którym serwer ogłasza swoje narzędzia, zasoby i prompty, a klient — wywołuje je i odbiera wyniki.
Intuicyjnie MCP to port USB‑C dla świata AI: jeśli tworzysz „pendrive” (serwis, bazę danych, CRM, silnik wyszukiwania), musisz zaimplementować jeden standardowy wtyk. Wtedy każdy „laptop” (ChatGPT, inny agent, IDE) może się z Tobą połączyć bez niestandardowego kabla.
2. Widok z lotu ptaka: gdzie MCP jest w architekturze ChatGPT App
Aby utrwalić obraz, przypomnijmy sobie znaną już architekturę, ale teraz z wyraźną warstwą MCP.
Aktualny obraz mentalny już widziałeś: użytkownik rozmawia z ChatGPT, wewnątrz dialogu renderuje się widget (Apps SDK), a gdzieś na zewnątrz żyje Twój backend. Teraz dodajmy MCP i ułóżmy wszystko warstwowo.
Oto uproszczony schemat:
Użytkownik
↓ (język naturalny)
ChatGPT (model + UI)
↓ (wywołania narzędzi przez MCP)
Klient MCP wewnątrz ChatGPT
↓ (JSON-RPC, MCP)
Twój MCP-serwer (backend)
↓
Twoja baza danych / zewnętrzne API / kolejki
Pod „MCP-klientem wewnątrz ChatGPT” rozumiemy tu wewnętrzną część platformy, która rozmawia z Twoim MCP-serwerem zgodnie z protokołem: wykonuje discovery, wywołuje narzędzia i czyta zasoby.
Z punktu widzenia Apps SDK minimalna ChatGPT App składa się z trzech komponentów. Pierwszy — MCP-serwer, który ogłasza narzędzia i zwraca ustrukturyzowane dane. Drugi — pakiet UI (widget), który renderuje się w ChatGPT i czyta te dane poprzez window.openai. Trzeci — sam model, który decyduje, kiedy wywołać jakie narzędzie i jak odpowiedzieć użytkownikowi.
Ważne jest, aby dostrzec następujące. We wszystkich poprzednich modułach dużo pracowałeś na poziomie Apps SDK i widgetu, czyli w górnej części schematu. Teraz schodzimy na poziom MCP-serwera — to Twój oficjalny „język komunikacji” z ChatGPT i innymi klientami, którzy zdecydują się użyć Twojej App.
3. MCP kontra „typowy REST”: na czym polega różnica
Na powyższym schemacie ustaliliśmy, gdzie MCP znajduje się w architekturze ChatGPT App. Teraz czas ostrożnie porównać podejścia „własny REST” i MCP, aby było jasne, dlaczego w kontekście ChatGPT Apps to drugie niemal zawsze wygrywa.
W podejściu REST projektujesz endpointy, formaty żądań i odpowiedzi tak, jak jest Tobie wygodnie. Klient, aby z Tobą pracować, musi znać URL‑e, metody, schematy i kody błędów. Czasem pomaga OpenAPI, czasem po prostu wrzucasz przykład żądania do README. Model sam z siebie nic z tego nie rozumie: potrzebuje warstwy kodu, która zamieni „dobierz prezent dla mamy na 50. urodziny” na konkretne żądanie HTTP, a potem z powrotem — odpowiedź JSON na dane przydatne w dialogu.
W MCP jest inaczej. Sam protokół określa:
- jak klient może poznać listę Twoich narzędzi;
- jak opisać argumenty i wyniki przez JSON Schema;
- jak opisać zasoby i prompty;
- jak wygląda wywołanie narzędzia i odpowiedź na nie.
Dzięki temu ChatGPT i inni klienci MCP mogą automatycznie:
- wykonać discovery — dowiedzieć się, jakie masz tools/resources/prompts;
- zbudować wewnętrzny schemat parametrów dla każdego narzędzia;
- wywoływać je bez niestandardowej, twardo zakodowanej logiki klienta;
- keszować metadane i używać ich do wyszukiwania oraz rankingu aplikacji.
Różnicę można streścić w krótkiej tabeli.
| Pytanie | Własny REST / gRPC | MCP |
|---|---|---|
| Skąd klient wie, co potrafisz? | Z dokumentacji, README, OpenAPI | Przez standardowe metody discovery (lista tools/resources) |
| Kto opisuje parametry? | Ty, dowolnie (JSON, FormData, cokolwiek) | JSON Schema w polach narzędzia |
| Jak model wywołuje funkcje? | Przez Twój niestandardowy kod kliencki | Bezpośrednio przez prymitywy MCP |
| Ile „obudowy” ma klient? | Dużo i dla każdego serwisu inna | Jeden wspólny protokół dla wszystkich serwerów MCP |
| Wsparcie przez wielu klientów | Trzeba pisać SDK dla każdego klienta | MCP-serwer jest samodokumentujący się, klient może współdzielić logikę |
Emocjonalnie: REST to „każdy sobie”, MCP to „umowa między uczestnikami ekosystemu, jak rozmawiać z modelem i danymi”.
4. Podstawowe byty MCP: tools, resources, prompts
Nazwijmy teraz trzech głównych bohaterów MCP: narzędzia, zasoby i prompty.
Tools: działania, do których już przywykłeś
Z tools zetknąłeś się już w Module 4: opisywaliśmy narzędzie, nadawaliśmy mu nazwę, opis i JSON Schema argumentów, a potem model wywoływał je poprzez callTool. Na poziomie MCP narzędzie to operacja serwerowa z jasnym kontraktem:
- nazwa i opis (dla modelu i pod UX/discovery);
- JSON Schema dla argumentów;
- JSON Schema lub opis struktury wyniku;
- dodatkowe metadane (np. powiązanie z konkretnym komponentem UI w Apps SDK).
Serwer MCP musi przynajmniej umieć odpowiedzieć na „żądanie listy narzędzi” i obsłużyć „wywołanie narzędzia”, zwracając ustrukturyzowany wynik.
W naszej aplikacji szkoleniowej — asystencie do prezentów — mamy, powiedzmy, narzędzie suggest_gifts, które przyjmuje wiek, płeć, budżet i parę preferencji, a zwraca listę rekomendowanych prezentów.
Przykładowy szkic TypeScript takiego narzędzia w kodzie serwera MCP może wyglądać np. tak (pseudokod/stub):
// Pseudokod, nie końcowe API SDK
const suggestGiftsTool = defineTool({
name: "suggest_gifts",
description: "Dobiera pomysły na prezenty na podstawie parametrów odbiorcy",
inputSchema: z.object({
age: z.number(),
relation: z.enum(["friend", "partner", "parent"]),
budgetUsd: z.number(),
}),
handler: async (input) => {
// TODO: Twoja logika biznesowa
return { items: [] };
},
});
Prawdziwe sygnatury omówimy w kolejnych lekcjach, tu ważna jest idea: narzędzie to nie tylko REST-endpoint, to element protokołu z zadeklarowanym schematem.
Zasoby (resources): dane dostępne po ID/URI
Zasoby (resources) w MCP to sposób opisu dostępnych danych: plików, katalogów, rekordów DB, stron wiki, a nawet wyników indeksów wyszukiwania. Klient może:
- pobrać listę zasobów;
- odczytać konkretny zasób po ID/URI;
- czasem — wykonać po nich wyszukiwanie.
W odróżnieniu od tools, które „coś robią”, resources zwykle „coś przechowują”. Na przykład w Gift‑App możesz przedstawić katalog produktów jako zasób gift_catalog, do którego model się odwołuje, aby poznać dostępne kategorie, filtry, przedziały cenowe itd.
W kodzie może to wyglądać koncepcyjnie tak:
const giftCatalogResource = defineResource({
uri: "catalog://gifts",
description: "Katalog prezentów dostępnych do rekomendacji",
read: async () => {
// Zwracamy strukturę katalogu
return { categories: [], priceRanges: [] };
},
});
Na razie nie wchodzimy w format wiadomości MCP, ale pamiętaj: zasoby to adresowalne byty, do których serwer MCP może się odwołać, a klient — odczytać i użyć jako część kontekstu.
Prompts: gotowe podpowiedzi
Prompts w kontekście MCP to szablony zapytań lub instrukcji, które serwer może udostępnić klientowi. Przykładowo możesz zadeklarować prompt gift_followup, który opisuje, jak model ma doprecyzować u użytkownika szczegóły dotyczące obdarowywanego, zanim wywoła narzędzie.
Typowy przykład w duchu protokołu: serwer daje nazwę promptu, jego przeznaczenie, czasem parametry. Klient może poprosić o listę promptów, wybrać potrzebny i wstawić do zapytania do modelu.
Po co to ChatGPT App? Po pierwsze, to jednolity sposób na ponowne użycie złożonych podpowiedzi między klientami. Po drugie, MCP czyni takie prompty jawnymi i „kontraktowymi”, a nie ukrytymi w przypadkowych miejscach kodu.
Capabilities: deklaracja tego, co w ogóle wspierasz
Wreszcie jest czwarty element — capabilities. To po prostu deklaracja: serwer mówi, które z bytów obsługuje (tools, resources, prompts, notyfikacje itd.) i jakie dokładnie metody implementuje. Dla klienta to sposób, by nie zgadywać, co można robić, a czego nie, i elegancko dostosować swoje zachowanie do możliwości serwera.
W praktyce ChatGPT, podłączając się do Twojego MCP-serwera, najpierw wykonuje „uścisk dłoni”, pobiera listę capabilities, a dopiero potem pyta: „OK, pokaż swoje narzędzia i zasoby”.
5. Jak MCP wpasowuje się w Twoją obecną App
Brzmi to nieco abstrakcyjnie, ale tak naprawdę już zetknąłeś się z MCP poprzez Apps SDK. Warto zacząć od zrozumienia, jak to wszystko łączy się z tym, co już napisałeś w ramach Apps SDK. Powiążmy dopiero co wprowadzone byty z tym, jak aktualnie działa Twój szablon App.
Przypomnijmy łańcuch, który już zaimplementowałeś w szablonie:
- Widget przez window.openai lub gotowe hooki wywołuje callTool z nazwą narzędzia i argumentami.
- Apps SDK wewnątrz ChatGPT zamienia to na wywołanie części serwerowej App.
- Serwer wykonuje narzędzie i zwraca ToolOutput, zawierający structuredContent, content i _meta.
- Widget odbiera ToolOutput i rysuje UI.
Sekret tkwi w tym, że kroki 2–3 realizowane są jako dialog przez MCP. Twój szablon Next.js zawiera endpoint (zwykle app/mcp/route.ts lub podobny), który właśnie jest MCP-serwerem. On:
- rejestruje Twoje narzędzia;
- opisuje je przez JSON Schema;
- implementuje handlery;
- odpowiada ChatGPT na żądania MCP list tools i call tool.
Czyli faktycznie już teraz, używając szablonu, pracujesz z MCP, tylko „automatycznie”: większość protokołowej magii jest ukryta w SDK.
Moduł 6 jest po to, by przestać traktować MCP jak „magiczną czarną skrzynkę” i zacząć świadomie go projektować:
- dodawać i wersjonować narzędzia;
- używać resources i prompts, a nie tylko tools;
- czytać i rozumieć logi MCP;
- w razie potrzeby uruchamiać osobne MCP-serwery poza szablonem Next.js (np. serwis Pythona do pracy z modelem ML lub osobny serwis dostępu do bazy korporacyjnej).
6. MCP oczami różnych ról: product vs deweloper
Warto osobno sformułować, co daje MCP product managerowi, a co — inżynierowi.
MCP dla productu
Z perspektywy produktu MCP to sposób, by Twój serwis stał się „podłączalnym modułem” dla całego zoo klientów: ChatGPT, inni klienci LLM, wtyczki IDE, własne agentowe rozwiązania. Raz opisując możliwości serwera jako zestaw tools/resources/prompts, pozwalasz każdemu klientowi:
- automatycznie wykryć Twój serwis;
- zrozumieć, jakie zadania rozwiązuje;
- bezpiecznie wywoływać potrzebne operacje.
W przypadku ChatGPT App to także zwiększa szansę wyboru Twojej aplikacji: model używa metadanych o Twoich narzędziach, aby decydować, kiedy proponować użytkownikowi Twoją App i jak ją poprawnie przedstawić.
W skrócie: MCP czyni Twój serwis standardowym „klockiem” ekosystemu, a nie niestandardową integracją dla jednego–dwóch klientów.
MCP dla dewelopera
Z punktu widzenia inżyniera MCP to kontrakt i protokół. Odpowiada na pytania:
- W jakim formacie mam zadeklarować narzędzie?
- Jak opisać argumenty i zwrócić wynik?
- Jak klient zrozumie, że wspieram zasoby i prompty?
- Jaki JSON w ogóle będzie krążył po sieci?
Kiedy masz taki protokół, łatwiej jest:
- pisać serwery w różnych językach (są oficjalne SDK dla TypeScript i Pythona);
- debugować aplikację przez MCP Inspector lub podobne narzędzia;
- dzielić odpowiedzialność między zespoły: jeden zespół buduje MCP-serwer z danymi i narzędziami, drugi — widget na Apps SDK, trzeci — może tworzyć własnych agentów na tym samym MCP-serwerze.
7. Mała praktyczna perspektywa: nasz pierwszy MCP-serwer
W tej lekcji celowo nie wchodzimy w szczegóły formatu wiadomości i implementacji serwera — to materiał kolejnych tematów. Aby jednak zawczasu wiedzieć, do czego zmierzamy, warto zobaczyć ogólną strukturę minimalnego MCP-serwera w TypeScript.
W praktyce oficjalna biblioteka TypeScript MCP daje prymitywy do tworzenia serwera, rejestrowania tools/resources/prompts i uruchamiania transportu (zwykle HTTP lub SSE).
Przykładowy pseudokod może wyglądać tak:
// To przykład koncepcyjny, API SDK omówimy później
import { createServer } from "@modelcontextprotocol/sdk";
const server = createServer({
name: "gift-genius",
version: "1.0.0",
});
// Rejestrujemy narzędzie
server.tool("suggest_gifts", {
description: "Dobiera prezenty według preferencji odbiorcy",
inputSchema: {/* ... */},
handler: async (input) => {
// Twoja logika
return { items: [] };
},
});
// Uruchamiamy transport (np. HTTP)
server.listen(3001);
Ważne: nigdzie nie ma tu wzmianki o ChatGPT, Apps SDK ani Twoim konkretnym froncie. MCP-serwer jest samodzielny. Po prostu umie odpowiadać na żądania MCP. ChatGPT App to tylko jeden z typów klientów, którzy mogą z takiego serwera korzystać.
W ramach kursu będziemy trzymać się szablonu Next.js, gdzie MCP-serwer żyje jako część projektu, ale to nie jedyna opcja.
8. MCP w ekosystemie: Apps SDK, Agents SDK i ACP
Aby nie postrzegać MCP jako „funkcji tylko dla Apps SDK”, warto zobaczyć go w szerszym obrazie.
Po pierwsze, Apps SDK wprost opiera się na MCP jako na standardowym moście między ChatGPT a zewnętrznymi serwisami. Oficjalna dokumentacja podkreśla: Apps SDK współpracuje z dowolnymi MCP-serwerami. Sam protokół pozwala opisywać narzędzia, zwracać ustrukturyzowane dane i wskazywać komponent do renderowania w UI.
Po drugie, Agents SDK, który omówisz w osobnym module, także potrafi podłączać się do MCP-serwerów. To znaczy, że ten sam MCP-serwer z logiką biznesową może być używany:
- wewnątrz ChatGPT jako część Twojej App;
- wewnątrz autonomicznego agenta działającego np. w tle Twojego produktu lub w trybie wsadowym.
Po trzecie, ACP (Agentic Commerce Protocol), który będzie potrzebny do zakupów i Instant Checkout, logicznie buduje się na podejściu MCP: model i agenci wywołują narzędzia commerce, także opisane przez zestandaryzowane kontrakty.
W ten sposób MCP staje się fundamentem, na którym powstają UI (Apps SDK), scenariusze agentowe (Agents SDK) i handel (ACP). Jeśli pewnie czujesz MCP, wszystko inne staje się prostsze i bardziej przewidywalne.
Uwaga: Formalnie ACP nie zależy od MCP jako specyfikacji, ale w realnej implementacji narzędzia ACP najpewniej będą wywoływane przez model właśnie przez interfejsy MCP. Jedno podejście bardzo ładnie nakłada się na drugie, więc nie trzeba będzie długo czekać.
9. Małe ćwiczenia „w głowie” przed praktyką
Zanim w kolejnej lekcji zanurzymy się w format wiadomości MCP, warto przerobić kilka ćwiczeń myślowych. Pomogą „przełączyć” myślenie z „typowego REST” na „protokół + kontrakt”.
Wyobraź sobie, że do Twojej Gift‑App chce podłączyć się nie tylko ChatGPT, ale też wtyczka IDE dla VS Code i wewnętrzny asystent korporacyjny w Slacku. Opisz jednym zdaniem, co wszyscy muszą wiedzieć o Twoim serwisie. Najpewniej odpowiedź będzie brzmieć mniej więcej: „Mamy narzędzie suggest_gifts z takimi parametrami oraz katalog prezentów dostępny przez taki zasób”. Właśnie to MCP formalizuje.
Spróbuj też sformułować w dwóch zdaniach:
- czym jest MCP dla productu Twojej App (podpowiedź: standardowy sposób „spakowania” funkcjonalności dla różnych klientów);
- czym jest MCP dla dewelopera (podpowiedź: protokół JSON‑RPC z jasnymi prymitywami tools/resources/prompts).
Jeśli potrafisz to zrobić bez zająknięcia — jesteś już w połowie drogi do pewnej pracy z MCP.
Jeśli streścić wszystko w jednym zdaniu: MCP to nie kolejny nakładkowy API, lecz podstawowy kontrakt między Twoją logiką a klientami LLM. W następnych lekcjach zajrzymy do wnętrza protokołu: omówimy format wiadomości MCP, handshake/capabilities i nauczymy się podglądać ruch przez inspektory, aby te zasady były nie abstrakcją, lecz narzędziem pracy.
10. Typowe błędy i mity wokół MCP
Błąd nr 1: uznawanie MCP za „kolejną warstwę API nad moim REST”.
Czasem kusi: „Mam już REST, to dołożę cienki adapter, który zamieni wywołania MCP na REST i odwrotnie, i po sprawie”. Formalnie można tak zrobić, ale wtedy często zaczynasz „przepychać” osobliwości starego API do MCP: dziwne typy, nieustrukturyzowane odpowiedzi, brak jawnych schematów. Z czasem adapter puchnie, a zysk z MCP maleje. Lepiej traktować MCP jako główny kontrakt, a stary REST — jako szczegół implementacyjny, jeśli nadal jest potrzebny.
Błąd nr 2: myślenie, że MCP jest „tylko dla ChatGPT Apps”.
MCP to ogólny, otwarty protokół dla dowolnych klientów LLM: ChatGPT, wtyczki IDE, autonomiczni agenci. Jeśli projektujesz MCP-serwer tylko pod jedną App, ograniczasz się na przyszłość. Znacznie korzystniej od razu myśleć: „tego serwera użyją też inni klienci” i projektować narzędzia oraz zasoby odrobinę bardziej uniwersalnie.
Błąd nr 3: ignorowanie JSON Schema i opisywanie argumentów „ustnie”.
Nawet jeśli SDK pozwala czasem przekazać „dowolny JSON”, nie zaniedbuj opisywania schematów argumentów i wyników. Od tego bezpośrednio zależy zdolność modelu do poprawnego wywoływania narzędzia, jakość autouzupełniania i discovery oraz wygoda debugowania przez inspektory. Nieopisane lub słabo opisane argumenty to prosta droga do zagadkowych błędów tool‑call.
Błąd nr 4: traktowanie MCP jako „magicznego transportu” i nieuwzględnianie logów.
Dopóki wszystko działa, wydaje się, że MCP to jakaś niewidzialna rzecz, o której nie trzeba myśleć. Problem w tym, że gdy coś się psuje, bez zrozumienia struktury MCP długo będziesz się zastanawiać: „to Apps SDK? model? mój backend?”. Nawyk zaglądania w wiadomości i logi MCP na wczesnym etapie uchroni przed godzinami bezowocnych prób.
Błąd nr 5: próba projektowania złożonego workflow wyłącznie przez REST, ignorując prymitywy MCP.
Kiedy pojawiają się wieloetapowe scenariusze (szukanie prezentu → doprecyzowanie preferencji → wybór → złożenie zamówienia), kusi, by „zrobić jeden wielki endpoint REST”. W kontekście ChatGPT Apps to często pogarsza sterowalność: model słabiej rozumie kroki pośrednie, a klient MCP traci możliwość współużywania zasobów i promptów. Znacznie lepiej rozbić funkcjonalność na kilka dobrze opisanych tools/resources, a logikę spinać systemowymi promptami i poprawnymi opisami.
GO TO FULL VERSION