Strona główna / Artykuły

MCP 2026-07-28: Jak specyfikacja bez stanu zmienia projekt serwerów zdalnych

Specyfikacja MCP 2026-07-28 przechodzi w tryb bezstanowy: brak sesji ani procedury nawiązywania połączenia, a także MRTR, zadania oraz wskazówki dotyczące pamięci cache. Jakie zmiany dotyczą serwerów zdalnych i jak je migrować.

Wydawca: REACTAPP.TOP23 min czytania5381 słów

Źródła: MCP Just Changed Its Architecture: Why the 2026 Specification Makes MCP Truly Cloud-Native

Punkt zwrotny dla MCP

Wersja 2026-07-28 Protokołu Kontekstu Modelu to wydarzenie o znaczniejszym znaczeniu niż zwykłe aktualizacje wersji. Podważa ona jedno z podstawowych założeń MCP, mianowicie to, że serwer zdalny jest zorganizowany wokół sesji protokołowej powiązanej z połączeniem. MCP przeszła od modelu dwukierunkowego z pamięcią stanu do projektu opartego na zapytaniach i odpowiedziach bez pamięci stanu, który funkcjonuje jak zwykła rozproszona infrastruktura HTTP. Ogłoszenie kandydata na wersję końcową określiło to jako największą aktualizację od wprowadzenia protokołu, a ostateczna specyfikacja została opublikowana 28 lipca 2026 roku.

MCP z przechowywaniem stanu nie był niezdolny do działania. Problem polegał na tym, że stan na poziomie protokołu stwarzał ograniczenia operacyjne, które utrudniają funkcjonowanie na nowoczesnych platformach chmurowych. Rozmieszczenie oprogramowania w chmurze zdalnie mogło wymagać pamiętania identyfikatora sesji, przypięcia tej sesji do konkretnego backendu, koordynacji stanu pomiędzy różnymi kopiami oraz utrzymywania aktywnych mechanizmów komunikacji przy interakcjach, które w rzeczywistości polegały jedynie na zwykłych żądaniach i odpowiedziach. W małej skali jest to do zarządzania. W dużych skali powoduje te same problemy, z którymi od lat borykają się systemy internetowe wykorzystujące sesje trwałe.

W nowym projekcie sesja protokołowa została usunięta, a mechanizm wymiany sygnałów initialize i initialized również zlikwidowany. Każda prośba zawiera niezbędne metadane klienta, a serwery stają się dostępne dzięki wyraźnemu procesowi wykrywania. Interakcje między serwerem a klientem zostały przearanżowane jako wielokrotne żądania typu Round-Trip, nagłówki HTTP przenoszą metadane routingu, klienci otrzymują wskazówki dotyczące cache’owania w odpowiedziach na listy i zasoby, długotrwałe zadania przenoszone są do rozszerzenia Tasks, zarządzanie cyklem życia rozszerzeń zostało sformalizowane, a wprowadzona została bardziej rygorystyczna polityka wycofywania funkcji. W rezultacie powstał rdzeń MCP, który doskonale pasuje do zwykłych balanserów obciążenia, bramek, firewalli aplikacji internetowych oraz implementacji typu serverless lub autoscaled.

Jeden model mentalny pomaga. Stary zdalny MCP funkcjonował jak rozproszony protokół połączeń konwersacyjnych, natomiast nowa wersja działa jak API HTTP, którego zachowanie zależne od stanu jest wyraźnie określone w warstwie aplikacji lub rozszerzeń.

Dlaczego MCP oparte na sesjach okazało się niewystarczające

Wyrażenie „MCP zależne od stanu przestało działać” wymaga uważnego przeczytania, ponieważ takie MCP nie przestało nagle funkcjonować. Stało się tak, że stan zarządzany przez protokół coraz mniej pasował do infrastruktury, w której rozmieszczane były serwery MCP.

W starszym modelu klient rozpoczynał komunikację żądaniem initialize, a serwer odpowiadał wartością Mcp-Session-Id, którą każde późniejsze żądanie musiało zawierać. To łączyło logicznego klienta z sesją po stronie serwera. Przykład przed i po przedstawiony przez samych utrzymujących system wyraźnie pokazuje tę różnicę: w starym podejściu konieczne było żądanie inicjalizacji, po którym następowało faktyczne wezwanie narzędzia, natomiast protokół z 2026 roku umożliwia bezpośrednie wysłanie wezwania narzędzia jako jednego samodzielnego żądania.

Konsekwencje operacyjne są ważniejsze niż zaoszczędzony żądanie HTTP. Wyobraźmy sobie usługę MCP z ośmioma replikami za load balancerem. Przy użyciu sesji, pierwsze żądanie tworzy sesję na instancji A, a drugie musi ponownie dotrzeć do instancji A, chyba że stan sesji jest udostępniany. To zmusza do wyboru między dwiema strategiami: routingiem „sticky”, dzięki któremu ten sam klient cały czas kontaktuje się z tą samą instancją, lub wspólnym magazynem sesji, do którego może uzyskać dostęp każda instancja. Obie te metody powiązują zachowanie protokołu z topologią implementacji.

Routing „sticky” kosztuje nas elastyczność, ponieważ load balancer nie może już kierować każdym żądaniem do tej zdrowej instancji, która ma wolne zasoby. Jeden węzeł może być przeciążony, podczas gdy inny pozostaje bezczynny, ponieważ sesje są przywiązane do określonych instancji, a przechodzenie na awaryjny tryb staje się trudniejsze, gdy oryginalny stan znajduje się na węźle, który zniknął.

Zachowywanie sesji w wspólnym magazynie rozwiązuje część problemu, ale jednocześnie wprowadza problemy związane z systemami rozproszonymi. Każda sesja staje się rekordem, który musi być tworzony, replikowany, wygaszany, usuwany, a także pozostawać dostępny przez cały czas. W takim przypadku serwer MCP jest aplikacją zawierającą podsystem zarządzania stanem sesji rozmieszczony na różnych maszynach. Wersja kandydująca do wydania wskazuje, że sesje „przyklejone” do użytkownika oraz wspólne magazyny stanowią infrastrukturę, której nie jest już potrzeba na poziomie protokołu po zniknięciu sesji.

Kubernetes, platformy kontenerów z funkcją automatycznego skalowania, funkcje chmurowe oraz środowiska bezserwerowe jeszcze bardziej uwidaczniają ten problem. Prośba może trafić do podu A, który może zniknąć podczas skalowania, a następna prośba dotrze do podu F. Dla usługi HTTP bez stanu jest to zupełnie normalne, ale utrudnia to działanie protokołu, którego poprawność zakłada, że stan związany z połączeniem pozostaje dostępny.

Stary protokół miał drugi koncepcyjny problem. Wykorzystywał model dwukierunkowy, w którym serwery mogły wysyłać żądania do klienta. Procesy takie jak wywoływanie, pobieranie próbek oraz wyświetlanie drzewa struktury polegały na tym wzorcu, który był sensowny, dopóki istniał trwały kanał komunikacji. Trwałe strumienie dwukierunkowe obciążają infrastrukturę, ponieważ firewalle, proxy’y, bramy, mechanizmy automatycznego skalowania, środowiska bezserwerowe oraz zbiory połączeń mają każdy swoje własne limity czasowe i cykle życia. Utrzymywanie otwartego strumienia tylko po to, by serwer mógł później zadać pytanie, jest zasadniczo inne od zwykłych żądań i odpowiedzi w protokole HTTP.

Rozwijający, który przetestował to samodzielnie, podaje konkretny przykład korzyści. Określił nowy protokół bezstanowy jako znacznie łatwiejszy do wdrożenia zarówno po stronie klienta, jak i serwera, i podkreślił, że aplikacje nie muszą już śledzić identyfikatorów sesji po stronie serwera ani kierować sesji z powrotem na jeden komputer. Następnie stworzył eksplorator bezstanowego MCP oraz wydał nową integrację Datasette MCP.

Zatem wniosek nie brzmi, że stan jest zły. Ukryty stan protokołu jest kosztowny, natomiast wyraźny stan aplikacji jest łatwy do zarządzania.

Sesja i procedura nawiązywania połączenia zniknęły

Pierwszą zmianą, którą ludzie zauważają, jest to, że sesja protokołu już nie istnieje. W 2026-07-28 zniknęła wymiana danych pomiędzy initialize a notifications/initialized, a także nagłówek Mcp-Session-Id. Każda prośba zawiera teraz wersję protokołu oraz możliwości klienta w sekcji _meta. Klient, który chce wcześniej dowiedzieć się czegoś o serwerze, może wywołać funkcję server/discover. Ostateczny rejestr zmian klasyfikuje obie te usunięcia – sesji oraz procedury nawiązywania połączenia – jako istotne zmiany.

Wcześniej proces polegał na nawiązaniu połączenia, a następnie na faktycznym wywołaniu:

Client
  |
  | initialize
  v
MCP Server
  |
  | Mcp-Session-Id = ABC
  v
Client
  |
  | tools/call + Mcp-Session-Id: ABC
  v
Same logical server session

Teraz połączenie może nastąpić bezpośrednio:

Client
  |
  | tools/call
  | protocol version
  | capabilities
  | client metadata
  v
Load Balancer
  |
  +----> MCP Instance A
  |
  +----> MCP Instance B
  |
  +----> MCP Instance C

Prośba zawiera teraz cały kontekst, którego warstwa protokołu potrzebuje, aby ją zrozumieć. Ponadto Streamable HTTP kopiuje kluczowe metadane do nagłówków, na przykład w tej prośbie:

POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
Content-Type: application/json

Ciało wiadomości pozostaje źródłem prawdy, natomiast opakowanie HTTP dostarcza metadanych, które mogą być wykorzystane przez pośredniki. Specyfikacja wymaga, aby pośredniki i mechanizmy transmisji odrzucały niespójne kombinacje nagłówków i ciała wiadomości w odpowiednich sytuacjach.

Usunięcie sesji nie oznacza, że aplikacje nie mogą mieć stanu. Stan aplikacji staje się po prostu wyraźną częścią modelu danych. Na przykład proces zakupowy może zwrócić identyfikator koszyka:

{
  "basket_id": "bsk_8f2a..."
}

a następne wezwanie narzędzia przekaże ten uchwyt z powrotem wraz z przedmiotem:

{
  "basket_id": "bsk_8f2a...",
  "item_id": "SKU-123"
}

Po stronie serwera identyfikator jest wyszukiwany w Redis, PostgreSQL, DynamoDB, Cosmos DB, magazynie obiektów lub dowolnym odpowiednim systemie. Transport MCP przestaje kontrolować ten stan. Twórcy zalecają wyraźne identyfikatory takie jak basket_id i browser_id jako sposób zastąpienia ukrytego stanu protokołu.

To oznacza rozdzielenie architektoniczne, pokazane tutaj:

MCP protocol state
        |
        v
       NONEApplication state
        |
        v
Explicit IDs + external state store


Long-running task state
        |
        v
Tasks extension + durable task store

Można powiedzieć, że to najważniejsza koncepcja w całej tej wersji.

Metadane i odkrywanie na żądanie

Jeśli ręka podanie nie ma miejsca, jak serwer może dowiedzieć się, jaką wersję protokołu oraz jakie funkcje obsługuje klient? Odpowiedzią są metadane na żądanie. Rezerwowane pola _meta znajdują się w przestrzeni nazw io.modelcontextprotocol/*, a wersja protokołu oraz możliwości klienta są dołączane do każdego żądania, bez konieczności jednorazowej negocjacji, którą połączenie potem pamięta. Gdy klient decyduje się na identyfikację, jego tożsamość również jest przekazywana jako metadane na żądanie, a serwery mogą umieścić swoje informacje w metadanych wyniku. Żądanie koncepcyjnie wygląda w ten sposób:

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "search",
    "arguments": {
      "query": "MCP stateless architecture"
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {
        "extensions": {
          "io.modelcontextprotocol/tasks": {}
        }
      },
      "io.modelcontextprotocol/clientInfo": {
        "name": "my-agent",
        "version": "3.2.0"
      }
    }
  }
}

Gdy informacje na wstępie są przydatne, serwer implementuje server/discover. Ostateczny plik changelog sprawia, że staje się to obowiązkowym RPC dla serwerów, dzięki czemu klienci mogą sprawdzić obsługiwane wersje protokołu, możliwości oraz tożsamość serwera przed podjęciem jakichkolwiek działań. Jest to przydatne, gdy klient musi dostosować swoje zachowanie na podstawie tego, co obsługuje serwer.

Istnieje tu subtelna różnica. Klienci mogą zdecydować się nie wywoływać server/discover, ale serwery muszą je dostarczać. Dlatego MCP nie wymaga już procesu odkrywania w celu nawiązania sesji, a nadal oferuje formalny sposób na proaktywne sprawdzanie możliwości. Taka architektura przypomina dojrzałe API HTTP, w których każda prośba może być interpretowana niezależnie, a opcjonalne punkty końcowe do odkrywania lub metadane dostarczają bardziej szczegółowych informacji.

Ładowanie rotacyjne i skalowanie do zera

Tutaj projekt przynosi najwyraźniejsze korzyści w architekturze chmurowej. Bez sesji protokołowych punkt końcowy MCP może działać za zwykłym balansem obciążeń przy użyciu prostego routingu typu round-robin. Oficjalne ogłoszenie przedstawia to jako zamierzony cel: kilka instancji MCP, routing typu round-robin oraz brak wspólnego magazynu sesji protokołowych.

Weźmy trzy repliki za balansem obciążeń:

                  +------------------+
                  |  Load Balancer   |
                  +---------+--------+
                            |
               +------------+------------+
               |            |            |
               v            v            v
           MCP Pod A    MCP Pod B    MCP Pod C

Zapytanie 1 może trafić do A, zapytanie 2 do C, a zapytanie 3 do B. Żadna zasada protokołu nie wymaga, aby wszystkie trzy dotarły do tej samej instancji, co jest dokładnie tym, czego pragną systemy typu cloud-native.

Załóżmy, że horizontalny skalator podów postanowi, że w ciągu nocy potrzebna jest tylko jedna replika. Dwie instancje mogą zniknąć. Gdy później przyjdzie zapytanie, nowa instancja może zostać uruchomiona i natychmiast je obsłużyć, ponieważ nie musi najpierw odbudowywać sesji protokołowej. Architektura wygląda wtedy w ten sposób:

Sam serwis MCP jest bezstanowy, a stan biznesowy pozostaje trwały poza nim.

Istnieje jednak jedna zastrzeżenie. Bezstanowy MCP nie sprawia automatycznie, że każde zastosowanie MCP skaluje się do zera. Jeśli aplikacja przechowuje koszyk, przepływ pracy, rozmowę, transakcję lub zadanie wyłącznie w pamięci procesu, po prostu odtworzyła problem ukrytego stanu na wyższym poziomie.

Aby rzeczywiście osiągnąć skalowanie do zera, wszystko, co musi przetrwać wyłączenie instancji, musi znajdować się w trwałej infrastrukturze. Jednym z możliwych rozwiązań w produkcji jest wykorzystanie Redis do krótkotrwałej koordynacji, PostgreSQL lub zarządzanej bazy danych NoSQL do przechowywania trwałego stanu aplikacji, a także magazynu obiektów do przechowywania dużych plików. Autoryzacja również odbywa się poza procesem, za pomocą systemu autoryzacji OAuth lub OIDC, a nie na podstawie danych z pamięci lokalnej.

Kompromis jest oczywisty. Protokół umożliwia infrastrukturę bezstanową, a projektant aplikacji jest teraz odpowiedzialny za decydowanie o tym, który stan ma przetrwać, gdzie się znajduje, jak jest autoryzowany, jak długo pozostaje oraz jak jest usuwany. To zdrowsza granica w projektowaniu systemów.

Samodzielne zarządzanie stanem

Jawnie określone identyfikatory mogą być najbardziej znaczącym rezultatem tego modelu. Weźmy na przykład agenta zakupowego opartego na sztucznej inteligencji, któremu polecono zamówić 100 kart graficznych, uzyskać zatwierdzenie i złożyć zamówienie. Projekt oparty na sesjach mógłby łatwo ukryć taki proces w stanie sesji MCP. Nowa architektura skłania do rozwiązania bardziej widocznego, w którym tworzenie żądania zwraca identyfikator:

create_purchase_request()
        |
        v
purchase_request_id = pr_123
        |
        v
request_approval(pr_123)
        |
        v
approval_id = appr_789
        |
        v
submit_purchase(pr_123, appr_789)

Stan nie jest już domyślnie zawarty w sesji HTTP. Jest to dane domeny, co jest bardzo korzystne, ponieważ dane te można zabezpieczyć, audytować, wersjonować, replikować i wyszukiwać niezależnie. Rekord stanu mógłby koncepcyjnie wyglądać w ten sposób:

{
  "purchase_request_id": "pr_123",
  "user_id": "user_42",
  "status": "awaiting_approval",
  "items": [
    {
      "sku": "GPU-H100",
      "quantity": 100
    }
  ],
  "created_at": "2026-08-21T08:00:00Z"
}

Serwer MCP po prostu rozwiązuje identyfikator i weryfikuje uprawnienia. Poprawia się również możliwość obserwacji. Zamiast informacji „sesja ABC wykonała jakąś czynność”, system może zgłosić, że wniosek o zakup pr_123 przeniesiono z stanu draft do approved – co ma rzeczywiste znaczenie biznesowe.

Zabezpieczenia stają się również łatwiejsze do zrozumienia. Nieprzejrzysty identyfikator sam w sobie nigdy nie stanowi wystarczających uprawnień, a serwer musi nadal potwierdzić, że autoryzowany użytkownik ma prawo edytować stan związany z tym identyfikatorem. Rozszerzenie Tasks traktuje identyfikatory zadań w ten sam sposób: serwery powinny generować identyfikatory trudne do odgadnięcia, a pominięcie elementu tasks/list jest celowym wyborem z punktu widzenia prywatności, ponieważ nikt nie może wyliczyć identyfikatorów zadań innych osób.

Wielokrotne żądania typu round-trip

Usuwanie trwałych żądań od serwera do klienta stwarza kolejny podstawowy problem. Rozważmy taką właśnie wywołanie narzędzia:

delete_customer_data(customer_id=123)

Serwer nie może bezpiecznie usunąć niczego, dopóki użytkownik nie potwierdzi tego poprzez komunikat w stylu „Usunąć 48 rekordów?”. Model starszy może utrzymywać kanał otwarty i prosić klienta o dodatkowe dane. Projekt bez stanu nie może polegać na trwale otwartej połączeniu, a mechanizmy Multi Round-Trip Requests, czyli MRTR, zostały stworzone, aby pokryć tę lukę.

MRTR obejmuje pojedynczą operację logiczną, która wymaga kilku wymian danych bez konieczności utrzymywania trwałego połączenia lub sesji po stronie serwera. Podczas oczekiwania na potwierdzenie, wyjaśnienia lub pobranie próbek nic nie utrzymuje połączenia HTTP otwartego ani nie korzysta ze stanu trwałego połączenia. Zamiast tego interakcja składa się z serii oddzielnych żądań HTTP połączonych ze sobą za pomocą stanu kontynuacji. Klient najpierw wysyła żądanie wykonania określonej akcji, na przykład tools/call w celu użycia narzędzia do usuwania danych. Serwer pomija uruchamianie własnego RPC skierowanego do klienta, pozostawiając pierwotną operację w stanie wstrzymanym, i odpowiada wynikiem tymczasowym, w którym informuje, że potrzebuje dodatkowych danych wejściowych:

{
  "resultType": "input_required",
  "inputRequests": {
    "confirm": {
      "type": "elicitation",
      "message": "Delete 48 records?",
      "schema": {
        "type": "boolean"
      }
    }
  },
  "requestState": "..."
}

Klient zbiera odpowiedzi i ponawia pierwotną prośbę z nimi dołączonymi:

Client
   |
   | tools/call
   v
Server
   |
   | input_required
   | requestState
   v
Client
   |
   | user confirmation
   v
Client
   |
   | same operation + inputResponses + requestState
   v
Any MCP instance

Operacja jest więc dzielona na kilka przejść HTTP, bez konieczności utrzymywania otwartego połączenia transportowego. Oficjalna wersja opisuje MRTR jako zamiennik dla wzorców inicjowanych przez serwer: elicitation/create, sampling/createMessage oraz roots/list.

Pole kluczowe to requestState. Wszystko, czego serwer potrzebuje, aby kontynuować pracę, trafia do tego pola, zapakowane jako nieprzejrzysty token, który jest podpisany, szyfrowany lub w inny sposób zabezpieczony przed modyfikacjami. Specyfikacja nie przechowuje całego stanu aplikacji w jednym centralnym magazynie sesji MCP – informacje potrzebne do kontynuacji interakcji są przekazywane w ramach kolejnego żądania. Przypomina to token kontynuacji, a główną zaletą jest to, że długa logiczna interakcja nie oznacza już długiego fizycznego połączenia.

Heady HTTP i wskazówki dotyczące cache’u

Przejście na model bezstanowy samo w sobie zwiększy skalowalność, a ponadto protokół staje się łatwiejszy do obsługi przez infrastrukturę HTTP. Zapytania HTTP typu streamable zawierają standaryzowane nagłówki, takie jak Mcp-Method i Mcp-Name, dzięki czemu bramy i balansery obciążenia mogą decydować o routingu, autoryzacji, ograniczeniach szybkości oraz telemetrii bez konieczności otwierania treści w formacie JSON-RPC. Treść zapytania pozostaje źródłem autorytetu, a wszelkie rozbieżności pomiędzy nagłówkiem a odpowiadającym mu polem w treści skutkują odrzuceniem zapytania.

Brama mogłaby odczytać te dwa wartości:

Mcp-Method = tools/call
Mcp-Name   = search

i zastosuj weryfikacje zasad tego typu:

tools/call + search  -> route/search-cluster
tools/call + execute -> route/execution-cluster
resources/read       -> route/resource-cluster

To zapewnia czyste rozdzielenie warstwy sterującej od warstwy danych, ponieważ pośrednik może poznać kategorię operacyjną żądania bez konieczności rozumienia schematu JSON aplikacji.

Wersja ta dodaje również metadane dotyczące cacheingu za pomocą ttlMs i cacheScope. Odpowiedź typu lista może je zawierać w następujący sposób:

{
  "result": {
    "tools": [
      ...
    ],
    "ttlMs": 60000,
    "cacheScope": "public"
  }
}

Semantyka ta celowo przypomina mechanizm HTTP cache-control. ttlMs informuje klienta, jak długo wynik uznawany jest za świeży, natomiast cacheScope wskazuje, czy wynik można bezpiecznie udostępnić innym. Ostateczna specyfikacja rozróżnia wartości "public" i "private" oraz ostrzega implementatorów, aby nie traktowali zakresu dostępu do cache jako zamiennika kontroli uprawnień. Kryterium świeżości jest określone w następujący sposób:

fresh_until = response_received_time + ttlMs

Zazwyczaj klient powinien ponownie pobrać dane, gdy potrzebuje wyniku, a ten stał się przestarzały, zamiast traktować TTL jako obowiązkowy interwał sprawdzania. Dla implementacji, które faktycznie przeprowadzają takie sprawdzania, specyfikacja zaleca stosowanie efektu jitter oraz strategii backoff.

Katalogi narzędzi sprawiają, że ta wartość jest oczywista. Jeśli serwer wymienia 250 narzędzi, a 500 agentów się do niego łączy, ciągłe wywołania tools/list przez każdego z nich powodują duży ruch w warstwie sterującej. Rozsądny TTL umożliwia klientom ponowne wykorzystanie katalogu, a deterministyczne uporządkowanie zapobiega niepotrzebnym zmianom w zserializowanym zestawie narzędzi, co może utrzymać stabilność buforów promptów w systemach LLM. W dzienniku zmian zaleca się właśnie to uporządkowanie z tego powodu. Kolejną zaletą jest to, że połączenia SSE pozostające otwarte nie są już jedynym sposobem na dowiedzenie się o zmianach w liście, dzięki czemu zarówno aktualność buforów, jak i powiadomienia o zmianach mogą funkcjonować równocześnie.

Zadania długotrwałe

API bez stanu do żądań i odpowiedzi nadal muszą obsługiwać zadania trwające minuty lub godziny. Weźmy taką rozmowę:

run_ml_training_job()

Może wysłać zadanie treningowe typu rozproszonego, czekać na GPU, uruchomić kilka etapów, tworzyć punkty kontrolne oraz przesyłać pliki wynikowe. Utrzymanie otwartej połączenia HTTP przez cały ten proces jest niestabilne. Architektura 2026-07-28 radzi sobie z tym za pomocą rozszerzenia Tasks, oznaczonego jako io.modelcontextprotocol/tasks.

Dla obsługiwanej funkcji tools/call serwer może odpowiedzieć identyfikatorem zadania zamiast ostatecznego wyniku:

{
  "resultType": "task",
  "task": {
    "taskId": "task_7b93...",
    "status": "working"
  }
}

Klient może następnie zapytać o status:

tasks/get(taskId)

I kontynuuj sprawdzanie, dopóki zadań nie zostanie uznane za completed, failed lub cancelled. Rozszerzenie to oferuje również tasks/update do wprowadzania dodatkowych danych oraz tasks/cancel do anulowania zadań.

Jedna różnica jest kluczowa. Podstawowy protokół jest bezstanowy, natomiast rozszerzenie Tasks celowo reprezentuje trwały stan:

Core MCP
    |
    +---- Stateless request/response
Tasks extension
    |
    +---- Durable asynchronous state machine

To nie jest sprzeczność. To rozdzielenie zadań. Zadanie może być powiązane z zewnętrznym systemem zadań, jak w tym schemacie:

MCP tools/call
      |
      v
Create task
      |
      v
Queue / workflow engine
      |
      +--> Kubernetes Job
      |
      +--> Azure Batch
      |
      +--> AWS Step Functions
      |
      +--> Databricks Job
      |
      +--> CI/CD pipeline

Klienci używają identyfikatora zadań MCP jako trwałego punktu dostępu do stanu danego zewnętrznego procesu pracy. Konfiguracje produkcyjne nie powinny przechowywać stanu zadań wyłącznie w słowniku wewnątrz procesu. Rozszerzenie to opisuje zadania jako trwałe maszyny stanowe i zaleca trwałe przechowywanie identyfikatorów zadań, aby polling mógł być kontynuowany po awarii klienta lub restartie serwera.

Pozostaje jeszcze jedna subtelność w implementacji. Rozszerzenie Tasks może nadal wymagać przekierowywania żądań do systemu, który przechowuje stan zadań. Ostateczna propozycja dotycząca zadań pozwala Mcp-Name przenosić identyfikator zadania dla operacji tasks/get, tasks/update oraz tasks/cancel, co umożliwia pośrednikom wysyłanie dodatkowych wiadomości do systemu przechowującego stan w razie potrzeby. Pełna wymiana informacji pomiędzy klientem, serwerem MCP a silnikiem zadań przedstawiona jest na tym diagramie sekwencyjnym:

Client                  MCP Server               Task DB / Engine
  |                         |                           |
  |--- 1. tools/call ------>|                           |
  |                         |--- 2. Register Task ----->| (Status: working)
  |<-- 3. Return taskId ----|                           |
  |                         |                           |
  |--- 4. tasks/get ------->|                           |
  |                           \--- 5. Query state ----->| (Status: working)
  |<-- 6. Status: working --/                           |
  |                         |                           |
  |--- 7. tasks/get ------->|                           |
  |                           \--- 8. Query state ----->| (Status: completed)
  |<-- 9. Final Result -----/                           |

W typowym schemacie klient rozpoczyna zadanie za pomocą tools/call, a serwer zapisuje trwałą informację o zadaniu w wspólnym backendzie, takim jak Redis, PostgreSQL lub silnikie procesów typu workflow, np. AWS Step Functions lub Kubernetes. Następnie natychmiast zwraca taskId oraz początkowy stan working. Pierwsze połączenie HTTP zostaje zamknięte w sposób czysty, co uwalnia zasoby sieciowe, a klient okresowo sprawdza postęp za pomocą tasks/get.

Dokładnym opisem architektury nie jest zatem stwierdzenie, że wszystko w MCP jest bezstanowe. Jądro MCP jest bezstanowe, natomiast zachowania związane ze stanem są wyraźnie modelowane poprzez dane aplikacji oraz rozszerzenia, takie jak Tasks.

Agent do operacji z danymi i sztuczną inteligencją w środowisku produkcyjnym

Wyobraźmy sobie platformę AI w środowisku produkcyjnym, która udostępnia narzędzia MCP agentowi przedsiębiorstwa. Agent posiada takie narzędzia jak te:

search_dataset()
inspect_schema()
run_sql()
start_training_job()
get_training_metrics()
deploy_model()
rollback_deployment()

Użytkownik prosi następnie o następujące: znalezienie najnowszego zestawu danych dotyczącego odejść klientów, jego przeanalizowanie, nauczenie modelu kandydackiego, porównanie metryk z modelem produkcyjnym oraz wdrożenie go tylko wtedy, gdy korzyść wyniesie co najmniej 5%.

W ramach starej architektury opartej na stanach system mógł utrzymywać długotrwałą sesję protokołową śledzącą interakcję, co łączyło logiczny przepływ pracy użytkownika z jedną instancją serwera. W nowej architekturze proces może być zaprojektowany w sposób wyraźny. Pierwszy wywołanie może polegać na wyszukiwaniu:

search_dataset("customer churn latest")

a serwer zwraca identyfikator zbiórki danych:

{
  "dataset_id": "ds_2026_08_20_0042"
}

Następna prośba sprawdza schemat za pomocą tego identyfikatora:

inspect_schema("ds_2026_08_20_0042")

Schemat pochodzi z systemu metadanych. Poniższy żądanie uruchamia szkolenie:

start_training_job("ds_2026_08_20_0042")

Serwer MCP tworzy trwałe zadanie:

task_id = "task_train_98af..."

Sam proces szkolenia odbywa się poza procesem MCP. Klient sprawdza jego stan regularnie:

tasks/get("task_train_98af...")

a zadanie może przechodzić przez serię stanów:

QUEUED
   |
RUNNING
   |
EVALUATING
   |
INPUT_REQUIRED
   |
RUNNING
   |
COMPLETED

W stanie INPUT_REQUIRED system może poprosić o zatwierdzenie wdrożenia, zaznaczając, że kandydat jest o 7,2% lepszy, ale zwiększyłby wydatki na GPU o 18%. MRTR może zadać to pytanie bez utrzymywania otwartego pierwszego połączenia. Klient odpowiada w ten sposób:

inputResponses = {
    "approve": true
}

a żądanie jest kontynuowane.

Teraz wyobraź sobie serwer MCP działający na sześciu replikach Kubernetes:

                  Ingress
                      |
              Load Balancer
                      |
        +------+------+------+------+
        |      |      |      |      |
       MCP1   MCP2   MCP3   MCP4   MCP5
                      |
                      v
               Task Store
                      |
              +-------+-------+
              |               |
           Redis          PostgreSQL
              |
              v
        Workflow Engine
              |
        +-----+------+
        |            |
     GPU Job     Model Registry

Tutaj pierwszy wywołanie tools/call trafia do MCP2, następne żądanie do MCP5, monitorowanie zadań do MCP1, a ponowna próba zatwierdzenia do MCP3. Nic się nie psuje, ponieważ protokół nie zakłada już, że sesja jest powiązana z konkretnym serwerem. Usunięty MCP3 jest zastępowany przez Kubernetes. Jeśli liczba replik spadnie z sześciu na dwa w ciągu nocy, proces pozostaje sprawny, ponieważ stan zadań i aplikacji znajduje się poza procesem. W tym miejscu specyfikacja dowodzi swojej praktycznej wartości.

Uprawnienia i wzmocnienie bezpieczeństwa

Oprócz zmian bez wpływu na stan aplikacji dochodzą istotne ulepszenia bezpieczeństwa. Ostateczna wersja wymaga bardziej rygorystycznego zachowania protokołów OAuth i OIDC: serwery autoryzacji powinny dostarczać parametr iss zgodnie z opisem w RFC 9207, a klienci MCP muszą sprawdzać ten identyfikator przed użyciem kodu autoryzacji, co zapobiega atakom polegającym na pomyleniu serwerów autoryzacji. Dane uwierzytelniające klienta są również powiązane z serwerem, który je utworzył, więc ich ponowne użycie wobec innego serwera autoryzacji jest zabronione. Dynamiczna rejestracja klientów pozostaje ze względu na kompatybilność, ale jest formalnie przestarzała – jej zamiennikiem są dokumenty metadanych identyfikatora klienta.

Model zagrożeń zmienia się korzystnie wraz z brakiem stanu, choć niesie ze sobą określone obowiązki. Wdrożenie w środowisku produkcyjnym powinno uwierzytelniać każdą prośbę oraz autoryzować konkretne operacje narzędzi lub zasobów. Należy sprawdzać wyraźne identyfikatory stanu w odniesieniu do uwierzytelnionego użytkownika, zapobiegać wyliczaniu identyfikatorów zadań oraz szyfrować wrażliwe dane stanu zarówno przechowywane, jak i przekazywane. Rozważmy taki przykład zapisu:

basket_id = bsk_123
user_id   = user_456

Nikt nie powinien wywnioskować z tego, że posiadanie bsk_123 wystarcza, by działać na koszyku. Przede wszystkim serwer powinien zweryfikować prawa własności w następujący sposób:

authenticated_subject == basket.owner

a następnie wprowadzić uprawnienia specyficzne dla narzędzia.

Propagacja kontekstu śledzenia W3C jest również udokumentowana i przekazywana w polu _meta za pomocą wartości traceparent, tracestate oraz baggage. Śledzenie działania w obrębie hosta, klienta MCP, serwera MCP oraz usług poniżej w łańcuchu staje się znacznie prostsze, a twórcy łączą to bezpośrednio ze śladami kompatybilnymi z OpenTelemetry. Dlatego też obserwowalność powinna być częścią projektu od samego początku. Ścieżka żądania poddawana śledzeniu może wyglądać w ten sposób:

User Request
    |
    v
Agent
    |
    | traceparent
    v
MCP Client
    |
    | traceparent
    v
MCP Gateway
    |
    v
MCP Server
    |
    v
Database / Queue / API

Wynikowy ślad może pokazać cały łańcuch przyczynowo-skutkowy, a nie zbiór niepowiązanych transakcji HTTP.

Rozszerzenia stają się pierwszorzędnymi

Rozszerzenia również uzyskują formalny status. Istniały już wcześniej, ale nic nie przypominało dojrzałego cyklu życia na poziomie równym protokołowi podstawowemu. Teraz każde rozszerzenie ma identyfikator reverse-DNS, wyraźną negocjację możliwości, własny repositoryj, niezależne wersjonowanie oraz dedykowany obszar w ramach procesu SEP.

Powodem jest to, że MCP rozwija się szybciej, niż pojedyncza wersja protokołu monolitycznego może bezpiecznie ewoluować. Funkcje wspierające nie powinny zobowiązywać każdej implementacji do wykonywania asynchronicznych zadań rozproszonych, a minimalny serwer wiersza poleceń nie powinien być zmuszany do przyjęcia aplikacji MCP. Większe ekosystemy standardów stosują ten sam podejście – utrzymują rdzeń w małym i stabilnym stanie, przenosząc specjalistyczne funkcje do modułów, które zmieniają się według własnego harmonogramu.

Dwie rozszerzenia znajdują się w centrum uwagi w tym wydaniu. MCP Apps dodaje interaktywną interfejs użytkownika generowaną przez serwer wewnątrz zabezpieczonego iframe, natomiast Tasks umożliwia asynchroniczne wykonywanie zadań. Otrzymana hierarchia wygląda następująco:

                    MCP
                     |
          +----------+----------+
          |                     |
       Core Protocol        Extensions
          |                     |
      Stateless HTTP      +-----+------+
                          |            |
                       Tasks       MCP Apps

Daje to MCP o wiele bardziej zrównoważony sposób rozwoju.

Deprecjacja i aktualizacje

W tym wydaniu celowo wprowadzono formalny cykl życia funkcji. Lista zmian określa stany Aktywne, Zdeprecjonowane i Usunięte oraz ustala minimalny okres deprecjacji wynoszący dwanaście miesięcy, dzięki czemu deweloperzy aplikacji mają przewidywalny okres migracji i nie muszą dokonywać pilnych zmian przy każdej aktualizacji protokołu.

Roots, Sampling i Logging znajdują się na liście deprecjowanych funkcji. Oficjalne zalecenia dotyczące migracji polegają na zastąpieniu Roots wyraźnymi parametrami narzędzi, adresami URI zasobów lub konfiguracją serwera, Sampling bezpośrednimi integracjami z dostawcami LLM, a Logging kodem stderr lub OpenTelemetry. Starszy transport HTTP+SSE również został zdeprecjonowany, a preferowaną opcją jest Streamable HTTP.

Eksperymentalna API Tasks z daty 2025-11-25 stanowi kolejną granicę migracji. Teraz znajduje się w rozszerzeniu io.modelcontextprotocol/tasks i ma przeprojektowany cykl życia oparty na funkcjach tasks/get, tasks/update oraz tasks/cancel. Funkcja tasks/list została usunięta, ponieważ wyświetlanie zadań bez sesji rodzi problemy z zakresem dostępu i prywatnością.

Dla organizacji migrującej istniejącą flotę MCP najbezpieczniejsza kolejność działań wygląda następująco:

  1. Uaktualnij SDK, a następnie poszukaj kodu, który wykorzystuje Mcp-Session-Id. Dokładnie przyjrzyj się słownikom opartym na sesjach, rejestrom połączeń oraz regułom routingu sticky-session zbudowanym według starego modelu.
  2. Rozdziel stan protokołu od stanu aplikacji, nadając każdemu elementowi reprezentującemu rzeczywisty stan biznesowy wyraźny identyfikator i przenosząc go do odpowiednio trwałego magazynu.
  • Należy zaktualizować konfigurację bramy, aby zrozumieć nowe nagłówki MCP, oraz nadać odpowiedziom z listą możliwości do przechowywania w pamięci cache wyraźne zasady TTL i zakresu, szczególnie ze względu na to, że cacheowanie typu public w porównaniu z private ma konsekwencje bezpieczeństwa.
  • Należy przeanalizować procesy pracujące długo czasu w celu wdrożenia zadań zamiast implementowania ich jako nieograniczenie otwarte żądania HTTP.
  • Obecna dokumentacja migracji SDK TypeScript również pokazuje tę przejściową rzeczywistość. Implementacje mogą obsługiwać nowy protokół, jednocześnie zachowując mechanizmy kompatybilności dla klientów z poprzedniej ery, dzięki czemu migracja może być stopniowa i nie wymaga całkowitej zmiany w całym ekosystemie.

    Co to oznacza dla architektury MCP

    Najważniejszą konsekwencją jest to, że MCP teraz oddziela cztery aspekty, które wcześniej były ze sobą powiązane:

    • Szczegóły komunikatów należą do warstwy protokołu.
    • Szyna transportowa przekazuje żądania przez HTTP lub stdio.
    • Szyna aplikacyjna przechowuje stan, kontekst uprawnień, procesy pracy oraz informacje identyfikujące obiekt biznesowy.
    • Szyna rozszerzeń dostarcza opcjonalne funkcje, takie jak asynchroniczne zadania i aplikacje MCP.

    Struktura warstw wygląda następująco:

                     +----------------------------+
                     |        MCP Protocol        |
                     | JSON-RPC + request model   |
                     +-------------+--------------+
                                   |
                     +-------------v--------------+
                     |         Transport          |
                     | stdio / Streamable HTTP    |
                     +-------------+--------------+
                                   |
                     +-------------v--------------+
                     |      Application Layer     |
                     | explicit IDs + databases   |
                     +-------------+--------------+
                                   |
                     +-------------v--------------+
                     |         Extensions         |
                     | Tasks / MCP Apps / others   |
                     +----------------------------+
    

    To rozwiązanie zapewnia znacznie lepszą skalowalność niż próba umieszczenia wszystkiego w jednej abstrakcji sesji opartej na połączeniu, a także dopasowuje MCP do dawno ugruntowanych praktyk w systemach rozproszonych: obsługi żądań bez stanu, trwałego stanu zewnętrznego, wyraźnych identyfikatorów, semantyki pamięci cache, powtórzeń operacji idempotentnych, obsługi zadań asynchronicznych oraz śledzenia w systemach rozproszonych.

    Kompromisy

    Istnieją pewne koszty. Główną zaletą jest skalowalność pozioma, ale ceną jest to, że zarządzanie stanem staje się zadaniem aplikacji. Programiści muszą ustalić, w jaki sposób tworzone są obsługi stanu, jak długo istnieją, gdzie są przechowywane, jak udzielana jest dostępność oraz jak usuwane są przestarzałe obsługi.

    Ponieważ możliwości klienta i metadane zmieniają się z każdym żądaniem, rozmiar danych przesyłanych rośnie nieznacznie. Dodatkowe bajty są zazwyczaj niewielkie, jednak systemy o bardzo wysokiej przepustowości powinny unikać niepotrzebnego powtarzania danych zawierających informacje o możliwościach klienta.

    MRTR umożliwia używanie bezstanowych protokołów HTTP w wymianach, które wcześniej wymagały żądań inicjowanych przez serwer, choć jednocześnie bardziej otwarcie ujawnia mechanizm stanów interakcji. Klient musi rozpoznać pole input_required, przechowywać stan żądania, zebrać odpowiedzi i prawidłowo spróbować ponownie.

    Zadania zajmują się długotrwałą eksploatacją, ale kosztem istnienia specjalnego magazynu zadań, który stanowi kolejny trwały podsystem. To nie jest wada – po prostu jest to jawny stan zamiast ukrytego stanu protokołu.

    Kasowanie danych z pamięci tymczasowej poprawia wydajność, ale błędne wartości pola cacheScope mogą powodować problemy bezpieczeństwa. Odpowiedź błędnie oznaczona jako "public" może zostać udostępniona w różnych kontekstach autoryzacji, a zalecenia dotyczące kasowania danych ostrzegają, że zakres pamięci tymczasowej nie zastępuje autoryzacji na poziomie protokołu.

    Bezstanowy rdzeń nie powinien być postrzegany jako mniej zaawansowana architektura. Lepiej go opisać jako odpowiedzialność rozproszoną w bardziej rozsądny sposób.

    Zmiana koncepcyjna

    Gdy pytano, gdzie mieści się logiczna interakcja, stary model domyślnie zakładał, że znajduje się ona w sesji MCP powiązanej z połączeniem. Nowy model zamiast tego pyta, jaki stan faktycznie jest potrzebny do wykonania operacji, a odpowiedź jest jasna: identyfikator domeny, identyfikator zadania, kontekst uprawnień lub token stanu żądania niezbędny do kontynuacji. Taka abstrakcja pozwala na znacznie lepszą skalowalność.

    Transakcje mają identyfikatory transakcji, workflow w Kubernetes mają identyfikatory zadań, koszyki zakupowe mają identyfikatory koszyków, pipeline CI mają identyfikatory wykonań, a zadania szkoleniowe mają identyfikatory wykonania. Aplikacje MCP mogą teraz korzystać z tego samego słownictwa.

    Co przynosi ta wersja

    To wydanie to coś więcej niż tylko uporządkowanie protokołu. Przesuwa MCP od integracji agentów opartych na połączeniach w kierunku chmurowych, rozproszonych systemów, a poszczególne zmiany są następujące:

    • Usunięcie Mcp-Session-Id eliminuje powiązania na poziomie protokołu.
    • Usunięcie procedury handshake sprawia, że każda prośba stanowi samodzielny wymianę danych.
    • server/discover umożliwia wykrywanie możliwości bez żadnych dodatkowych semantyk sesji.
    • Mcp-Method i Mcp-Name umożliwiają wykorzystanie ruchu MCP zwykłymi narzędziami HTTP.
    • ttlMs i cacheScope dostarczają klientom i bramkom wspólnego słownictwa dotyczącego świeżości danych i ich udostępniania.
    • MRTR porzuca koncepcję, że serwer proszący klienta o coś wymaga połączenia, które nigdy się nie zamyka.
    • Zadania stanowią trwałą abstrakcję dla operacji, które przetrwają dłużej niż pojedyncza prośba HTTP.
    • Jasne identyfikatory wyodrębniają stan biznesowy aplikacji od ukrytych metadanych transportowych i umieszczają go w własnym modelu danych aplikacji.
    • Rozszerzenia zapobiegają nadmiernemu rozrastaniu się jądra, umożliwiając jednocześnie szybszy rozwój ekosystemu.
    • Struktura uprawnień bardziej odpowiada zachowaniu rzeczywistych implementacji OAuth i OIDC.
    • Konwencje kontekstu śledzenia z OpenTelemetry ułatwiają obserwację rozproszonych systemów MCP.
    • Oficjalna polityka deprecjacji zapewnia ekosystemowi przewidywalny sposób zmian.

    Model bezstanowy znacznie ułatwia implementację MCP, a narzędzia stworzone przez niezależnego programistę, takie jak explorer i Datasette, pokazują, że ta prostota przekłada się na praktyczne narzędzia. Jego opis starego protokołu jako wymagającego inicjalizacji sesji oraz nowego jako pojedynczej, samodzielnej żądania to właśnie ta zmiana operacyjna, do której dążyli utrzymywacze.

    Wniosek dla architektów jest taki, że MCP nie usunął stanu. Usunął natomiast ukryty stan należący do protokołu, zastępując go wyraźnym, składalnym stanem należącym do aplikacji. Ta zmiana umożliwia serwerowi MCP przechodzenie z takiego połączenia:

    sticky sessions
          +
    shared session store
          +
    long-lived connections
          +
    connection affinity
    

    i w kierunku tego:

    stateless request handling
          +
    ordinary load balancing
          +
    external durable state
          +
    explicit handles
          +
    asynchronous task primitives
    

    Dla zastosowań w przedsiębiorstwach jest to ogromna zaleta, ponieważ znacznie lepiej pasuje do Kubernetes, automatycznego skalowania, wykonywania bez serwerów, bramek API, wdrażania bez przerwy w pracy, routingu między regionami, śledzenia rozproszonego oraz dużych platform wielu najemców. Mówiąc prościej, ta specyfikacja przekształca MCP z standardu określającego, w jaki sposób agenci wywołują narzędzia, w infrastrukturę, która naturalnie pasuje do nowoczesnych rozproszonych systemów AI.