Przejdź do głównej zawartości

MCP 2026-07-28: co się zmieniło i jak zmigrować serwer

Specyfikacja MCP 2026-07-28 czyni protokół bezstanowym: znika handshake initialize i nagłówek Mcp-Session-Id, każde żądanie niesie wersję protokołu i możliwości klienta w _meta, a serwer musi implementować server/discover. Własny serwer migruje się przez przejście na SDK v2, zastąpienie stanu sesji i żądań inicjowanych przez serwer oraz obsługę obu er protokołu naraz.

Wewnętrzny serwer MCP twojego zespołu opakowuje API wdrożeń. Trzyma cache per sesja oparty na Mcp-Session-Id, prosi użytkownika o potwierdzenie rollbacku przez elicitation/create i loguje przez logging/setLevel. W 2026-07-28 wszystkie trzy mechanizmy zostały usunięte albo oznaczone jako przestarzałe. Claude Code domyślnie negocjuje już nową rewizję z serwerami HTTP, a Codex 0.157.1 jeszcze nie, więc ten sam serwer musi odpowiadać obu. Ta strona jest dla programisty, który utrzymuje taki serwer, i dla tech leada, który zatwierdza migrację.

Sprawdzone 2026-09-26 na podstawie changelogu 2026-07-28, wpisu opiekunów o wydaniu (2026-07-28), dokumentacji TypeScript SDK 2.1.0 i Python SDK 2.2.0, Claude Code 2.1.283 oraz codex-cli 0.157.1. Obsługi protokołu MCP w Cursorze nie zweryfikowaliśmy 2026-09-26; sprawdź ją w aplikacji (zakładka Cursor). Ta strona zakłada, że masz już działający serwer zbudowany jak w Tworzenie własnego serwera MCP.

  • Tabelę wszystkich zmian łamiących zgodność w 2026-07-28: co psują w twoim serwerze i czym je zastąpić.
  • Informację, które z narzędzi Claude Code, Codex i Cursor mówią już nową rewizją i dlaczego serwer musi dalej obsługiwać starą.
  • Migrację serwera w TypeScripcie krok po kroku oraz odpowiadające jej zmiany w serwerze w Pythonie.
  • Test dymny, który łączy się raz na każdą erę protokołu i zatrzymuje CI, gdy którakolwiek się zepsuje.
  • Cztery prompty do wklejenia: audyt serwera, migracja, wywołanie z dowolnego agenta i test obu er.
  • Checklistę akceptacji, którą tech lead wkleja do pull requesta z migracją.

Opiekunowie podsumowują wydanie jako „a stateless protocol core, Multi Round-Trip Requests, header-based routing, cacheable list results, authorization hardening, a formal extensions framework, and updated Tier 1 SDKs” (blog MCP, 2026-07-28). Release candidate zamrożono 21 maja 2026. Dla autora serwera changelog sprowadza się do poniższych wierszy.

Zmiana w 2026-07-28Co psuje w twoim serwerzeCzym ją zastąpić
Usunięte initialize / notifications/initializedKod, który raz, przy połączeniu, odczytuje możliwości lub dane klientaKlucze _meta w każdym żądaniu: io.modelcontextprotocol/protocolVersion, clientCapabilities i opcjonalnie clientInfo
Dodane server/discover, które serwer musi implementowaćRęcznie pisany serwer bez obsługi tej metodySDK v2 odpowiadają na nią za ciebie
Usunięte Mcp-Session-Id i sesje protokołuStan oparty na identyfikatorze sesji: cache, kontekst autoryzacji, przepływy wieloetapoweJawne uchwyty zwracane przez jedno narzędzie i przekazywane jako argumenty do następnego albo podpisany requestState
Żądania serwera sampling/createMessage, elicitation/create, roots/list zastąpione przez Multi Round-Trip RequestsNarzędzie, które w trakcie wywołania zatrzymuje się, by o coś zapytać użytkownikaZwróć resultType: "input_required" z inputRequests; klient ponawia wywołanie z inputResponses
Każdy wynik ma wymagane pole resultTypeRęcznie budowane wyniki JSON-RPC"complete" dla zwykłych wyników (SDK ustawiają je same)
Strumień HTTP GET i resources/subscribe zastąpione przez subscriptions/listenPowiadomienia o zmianach wysyłane samodzielnym strumieniemJeden strumień na klienta, na który klient się zapisuje, oznaczony identyfikatorem subskrypcji
Usunięte ping, logging/setLevel i notifications/roots/list_changedHealth checki oparte na ping, poziom logowania dla całej sesjiio.modelcontextprotocol/logLevel w _meta każdego żądania; bez tego pola serwer nie wysyła logów
Usunięte wznawianie strumieni SSE (Last-Event-ID)Długie wywołania, które liczyły na wznowienie zerwanego strumieniaKlient wysyła żądanie ponownie, więc wywołania narzędzi muszą być bezpieczne do powtórzenia
Nagłówki Mcp-Method i Mcp-Name wymagane w żądaniach POST Streamable HTTPBramki i reguły WAF, które wycinają nieznane nagłówkiPrzepuść nagłówki; routuj i limituj ruch na ich podstawie
Wyniki list mają ttlMs i cacheScope; tools/list powinno mieć deterministyczną kolejnośćListy narzędzi budowane z nieuporządkowanej mapyStałe sortowanie, dzięki któremu klienci i cache promptów widzą tę samą listę
Tasks przeniesione do rozszerzenia io.modelcontextprotocol/tasksKod na eksperymentalnym API tasks w rdzeniuOdpytywanie przez tasks/get, przekazywanie danych przez tasks/update; tasks/list zniknęło
Kod błędu „resource not found” zmieniony z -32002 na -32602Klienci i testy, które sprawdzają stary kodKod JSON-RPC Invalid Params

Cztery funkcje są przestarzałe, ale nadal działają przez co najmniej dwanaście miesięcy zgodnie z nową polityką wycofywania: Roots, Sampling, Logging i transport HTTP+SSE. Dynamic Client Registration jest przestarzałe na rzecz Client ID Metadata Documents, a klient musi teraz weryfikować parametr iss, jeśli odpowiedź autoryzacyjna OAuth go zawiera. Nowy kod nie powinien sięgać po żadną z przestarzałych funkcji.

Framework rozszerzeń formalizuje też MCP Apps: interaktywny interfejs, który serwer zwraca do wyrenderowania w izolowanym iframe. SDK tego rozszerzenia to @modelcontextprotocol/ext-apps (npm 2.0.0, tag latest na 2026-09-26, opublikowane 2026-09-08), a jego README wymienia Claude, ChatGPT i VS Code jako obsługiwanych klientów. Klient ogłasza obsługę pod identyfikatorem rozszerzenia io.modelcontextprotocol/ui; rozszerzenie Tasks używa io.modelcontextprotocol/tasks. Rozszerzenia są wyłączone, dopóki obie strony ich nie zadeklarują, więc serwer musi wrócić do zachowania z rdzenia protokołu, gdy klient ich nie obsługuje. W codex-cli 0.157.1 funkcja enable_mcp_apps ma status under development i jest wyłączona, więc narzędzie, które zwraca App, nadal musi zwracać sensowny wynik tekstowy.

O protokole nie decyduje serwer, tylko klient. Klient obsługujący obie ery najpierw sonduje serwer (przez server/discover albo, w HTTP, pierwszym żądaniem w nowej erze) i wraca do initialize, gdy serwer nie odpowie w nowej erze. Klient znający tylko starą erę wysyła initialize i nic więcej. Klienci się różnią, więc zaplanuj obsługę obu er na tym samym endpoincie.

KlientMówi 2026-07-28?Jak wymusić erę na potrzeby testu
Claude Code 2.1.283Tak z serwerami HTTP, domyślnie w kliencie v2 (na wszystkich typach instalacji od v2.1.274). Serwery stdio zostają przy starym handshake’u, chyba że to włączyszMCP_PROTOCOL_NEGOTIATION=auto sonduje także serwery stdio; legacy wyłącza sondowanie dla wszystkich serwerów
Codex 0.157.1Nie. mcp_2026_07_28 ma status under development i jest wyłączone (codex features list)codex --enable mcp_2026_07_28 włącza niedokończoną funkcję na jedno uruchomienie. Traktuj to jak podgląd, nie jak bramkę
CursorNiezweryfikowane 2026-09-26Testuj w aplikacji po każdej aktualizacji Cursora

Stan SDK na 2026-09-26: pakiety TypeScript v2 @modelcontextprotocol/server i @modelcontextprotocol/client są w wersji 2.1.0 (npm), pakiet v1 @modelcontextprotocol/sdk jest w wersji 1.30.1 i dostaje poprawki przez co najmniej sześć miesięcy od wydania v2, a mcp na PyPI jest w wersji 2.2.0. Opiekunowie podają w tym samym wpisie o wydaniu „close to half-a-billion downloads a month” dla SDK z Tier 1 (TypeScript, Python, Go i C#); to liczba podana przez samych opiekunów.

SDK nadal obsługują klientów z ery 2025, więc migracja dotyczy głównie założeń twojego własnego kodu. Znajdź wiersz, który pasuje do twojego serwera.

Twój serwer dziśPotrzebna praca
Bezstanowe narzędzia na TypeScript SDK v1, stdioPrzejście na v2 i zmiana na serveStdio. Niewiele: większość zrobi codemod
Bezstanowe narzędzia na TypeScript SDK v1, Streamable HTTP z sessionIdGenerator: undefinedPrzejście na v2; domyślny createMcpHandler wprost odpowiada temu ustawieniu
Cokolwiek oparte na identyfikatorze sesjiPrzeprojektowanie tego stanu na jawne uchwyty lub requestState. To jest prawdziwy koszt
Narzędzia wywołujące elicitInput, createMessage lub roots/listPrzepisanie ich tak, by zwracały input_required (TypeScript) albo użycie parametrów Resolve(...) (Python)
Transport HTTP+SSEPrzejście na Streamable HTTP. Serwer v2 nie obsługuje SSE
Python na mcp 1.xDziś przypnij mcp<2 (tak radzi samo SDK; 1.29.1 to ostatnie 1.x na 2026-09-26), potem przenieś kod na MCPServer (niżej)
Ręcznie pisany JSON-RPC bez SDKSamodzielna implementacja server/discover, parsowania _meta, resultType i nowych nagłówków albo przejście na SDK

TypeScript SDK dzieli migrację na dwie części. Codemod przenosi kod z pakietu v1 na pakiety v2. Obsługa 2026-07-28 jest potem osobnym, jawnym krokiem, bo serwer v2 zbudowany ręcznie i podłączony wprost do transportu nadal mówi protokołem 2025, dla którego go napisano.

  1. Spisz, co serwer zakłada. Zanim cokolwiek zmienisz, uruchom prompt audytowy poniżej. Potrzebujesz listy wszystkich odczytów identyfikatora sesji, wszystkich żądań inicjowanych przez serwer, wszystkich wywołań logowania i wszystkich narzędzi, których wynik zależy od wcześniejszego wywołania.

  2. Uruchom codemod w katalogu głównym pakietu, żeby przepisał też importy w testach i skryptach:

    Okno terminala
    npx @modelcontextprotocol/codemod@latest v1-to-v2 .

    Codemod wykonuje mechaniczne zmiany nazw z @modelcontextprotocol/sdk na @modelcontextprotocol/server i @modelcontextprotocol/client. Nie wprowadza za ciebie obsługi 2026-07-28.

  3. Przejdź na punkt wejścia per żądanie. Buduj serwer w funkcji fabrykującej, bo ścieżka 2026 tworzy nową instancję na każde żądanie (HTTP) lub na każde połączenie (stdio).

    // v1: new McpServer(...) + await server.connect(new StdioServerTransport())
    import { McpServer } from '@modelcontextprotocol/server';
    import { serveStdio } from '@modelcontextprotocol/server/stdio';
    import * as z from 'zod/v4';
    function buildServer() {
    const server = new McpServer({ name: 'deploy-tools', version: '2.0.0' });
    server.registerTool(
    'get_release',
    { description: 'Read one release by id', inputSchema: z.object({ releaseId: z.string() }) },
    async ({ releaseId }) => ({ content: [{ type: 'text', text: await readRelease(releaseId) }] }),
    );
    return server;
    }
    serveStdio(buildServer); // obsługuje 2026-07-28 i domyślnie także połączenia z ery 2025

    Dla HTTP użyj createMcpHandler(buildServer) z @modelcontextprotocol/server. We frameworkach Node opakuj go przez toNodeHandler z @modelcontextprotocol/node, na przykład app.all('/mcp', toNodeHandler(handler)). Domyślne legacy: 'stateless' obsługuje też klientów z ery 2025, osobno dla każdego żądania.

  4. Zastąp stan sesji. Cache albo kontekst autoryzacji oparty na identyfikatorze sesji nie ma już klucza. Niech narzędzie, które tworzy stan, zwraca jawny uchwyt (na przykład releaseId), a kolejne narzędzie przyjmuje go jako argument; model widzi uchwyt i sam go przekazuje dalej. Dla przepływu wieloetapowego w ramach jednego wywołania użyj requestState i podpisz go przez createRequestStateCodec({ key }), bo klient odsyła go z powrotem i jest to niezaufane wejście. Klucz musi mieć co najmniej 32 bajty i pochodzić z magazynu sekretów, nigdy z kodu źródłowego.

  5. Zastąp żądania inicjowane przez serwer. Tam, gdzie narzędzie wywoływało elicitInput lub createMessage, teraz zwraca inputRequired(...) i przy ponowieniu czyta odpowiedź z ctx.mcpReq.inputResponses. Ten sam handler nadal działa dla klientów z ery 2025 dzięki warstwie zgodności (legacy shim) w SDK.

  6. Wyprowadź logowanie poza protokół. Loguj na stderr (nigdy na stdout w stdio) albo do OpenTelemetry. ctx.mcpReq.log() nic nie wysyła w żądaniu z ery 2026, jeśli klient nie ustawił logLevel w _meta, a klient z SDK domyślnie go nie ustawia.

  7. Posortuj tools/list. Rejestruj narzędzia w stałej kolejności, żeby lista była identyczna przy każdym żądaniu, a cache po stronie klienta pozostawał ważny.

  8. Jeśli musisz, utrzymaj stare wdrożenie z sesjami. Postaw restrykcyjny handler (createMcpHandler(buildServer, { legacy: 'reject' })) za rozgałęzieniem na isLegacyRequest(request) i kieruj ruch z ery 2025 do istniejącej konfiguracji v1, dopóki jej klienci nie znikną.

mcp 2.x z PyPI implementuje 2026-07-28 i obsługuje obie ery z tego samego streamable_http_app() lub serwera stdio, bez żadnej flagi. Zmiany dotyczą twojego kodu:

  • pip install mcp instaluje teraz 2.x. W każdym projekcie, który nie jest jeszcze zmigrowany, przypnij mcp<2, bo inaczej build bez przypięcia sam zrobi aktualizację.
  • FastMCP nazywa się teraz MCPServer: from mcp.server import MCPServer. Opcje transportu, takie jak host, port i stateless_http, przechodzą z konstruktora do run() i metod budujących aplikację.
  • ctx.elicit() i ctx.session.create_message() rzucają NoBackChannelError w połączeniu z ery 2026. Przenieś pytanie do parametru oznaczonego Resolve(...), który zada je mechanizmem dostępnym w danym połączeniu.
  • Klucz do pieczętowania request_state jest domyślnie generowany osobno w każdym procesie. Za load balancerem przekaż RequestStateSecurity(keys=[...]), żeby każda replika mogła zweryfikować ponowienie.
  • Przewodnik migracji v2 podaje, że eksperymentalna obsługa Tasks została usunięta. Dopóki nie potwierdzisz obsługi rozszerzenia Tasks w przypiętej wersji SDK, trzymaj długie operacje za własnym identyfikatorem zadania i narzędziem do sprawdzania statusu.

Zielona kropka w jednym kliencie dowodzi działania jednej ery. Bramka, która ma znaczenie, łączy się dwa razy: raz przypięta do 2026-07-28, raz przez handshake z 2025. Zatrzymuje build, gdy którekolwiek połączenie nie zwraca narzędzi, znane wywołanie się psuje albo ery udostępniają różne nazwy narzędzi. Tryb przypięcia (pin) nigdy nie wraca do starej ery, więc serwer, który po cichu obsługuje tylko stary protokół, oblewa pierwsze połączenie zamiast przejść.

// scripts/mcp-era-smoke.mjs (uruchom: MCP_URL=http://localhost:3000/mcp node scripts/mcp-era-smoke.mjs)
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const url = new URL(process.env.MCP_URL ?? 'http://localhost:3000/mcp');
const modes = [{ pin: '2026-07-28' }, 'legacy'];
const names = [];
for (const mode of modes) {
const client = new Client({ name: 'era-smoke', version: '1.0.0' }, { versionNegotiation: { mode } });
await client.connect(new StreamableHTTPClientTransport(url));
const { tools } = await client.listTools();
console.log(`${client.getProtocolEra()}: ${tools.length} tools`);
if (tools.length === 0) process.exitCode = 1;
names.push(JSON.stringify(tools.map((t) => t.name).sort()));
try {
// znane wywołanie z identyfikatorem z fixture musi działać w obu erach
const result = await client.callTool({
name: 'get_release',
arguments: { releaseId: process.env.FIXTURE_ID ?? 'r-102' },
});
if (result.isError) process.exitCode = 1;
} catch (err) {
console.error(`${client.getProtocolEra()}: get_release failed`, err);
process.exitCode = 1;
}
await client.close();
}
// obie ery muszą udostępniać te same nazwy narzędzi
if (names[0] !== names[1]) {
console.error('listy narzędzi różnią się między erami');
process.exitCode = 1;
}

Oczekiwany wynik to jedna linia modern i jedna linia legacy z tą samą liczbą narzędzi oraz kod wyjścia 0; nieudane wywołanie get_release albo różne nazwy narzędzi ustawiają kod wyjścia 1. Błąd ERA_NEGOTIATION_FAILED w pierwszej linii oznacza, że serwer nigdy nie zaoferował 2026-07-28. W testach bez gniazda sieciowego przekaż do transportu metodę fetch handlera (fetch: (u, init) => handler.fetch(new Request(u, init))), która obsługuje żądanie w tym samym procesie. W Pythonie Client(mcp) podłączony do obiektu serwera domyślnie negocjuje 2026-07-28; drugiego klienta testowego przypnij do mode="legacy", żeby pokryć starą ścieżkę.

Żeby ręcznie sprawdzić działający serwer bez pisania kodu, użyj CLI MCP Inspectora (@modelcontextprotocol/inspector 2.8.0 na 2026-09-26). Bez dodatkowej flagi łączy się w erze legacy, więc za każdym razem podawaj --protocol-era jawnie:

Okno terminala
npx @modelcontextprotocol/inspector --cli http://localhost:3000/mcp --transport http --protocol-era modern --method tools/list
npx @modelcontextprotocol/inspector --cli http://localhost:3000/mcp --transport http --protocol-era legacy --method tools/list

Oba polecenia powinny wypisać te same nazwy narzędzi. Dla serwera stdio zamień URL i --transport http na polecenie uruchamiające, na przykład node build/index.js.

Następnie zarejestruj serwer w każdym obsługiwanym agencie i wywołaj jedno narzędzie tylko do odczytu. Polecenia różnią się między narzędziami:

Zarejestruj lokalny serwer, a potem porównaj obie ery. Claude Code domyślnie sonduje serwery HTTP pod kątem 2026-07-28:

Okno terminala
claude mcp add --transport http deploy-tools http://localhost:3000/mcp
claude mcp list # domyślnie: serwery HTTP w 2026-07-28, jeśli je oferują
MCP_PROTOCOL_NEGOTIATION=legacy claude mcp list # wymuś starszy handshake
MCP_PROTOCOL_NEGOTIATION=auto claude # sonduj też serwery stdio, potem wywołaj narzędzie

Jeśli serwer działa tylko z legacy, błąd leży w jego ścieżce 2026. Serwer stdio, który jest też kanałem, nie zostaje zarejestrowany jako kanał, gdy wynegocjuje 2026-07-28, bo ta rewizja nie przenosi wiadomości kanałów.

W każdym z trzech agentów ten prompt dowodzi, że narzędzie działa od początku do końca, i pokazuje, co dostał model:

Zobaczysz dokładnie jedno wywołanie get_release i rekord wydania. Prośba o potwierdzenie albo runda input_required przy narzędziu tylko do odczytu oznacza, że narzędzie żąda danych, których nie powinno potrzebować.

Migracja jest skończona wtedy, gdy poniższe dowody są dołączone do pull requesta, a nie wtedy, gdy kod się kompiluje. Dostarcza je właściciel serwera; zatwierdza tech lead odpowiedzialny za konfigurację MCP zespołu.

  • SDK jest w wersji v2: @modelcontextprotocol/server 2.x albo mcp 2.x z PyPI z jawnym zakresem wersji.
  • Żaden kod nie czyta identyfikatora sesji; stan między wywołaniami przechodzi jako jawne uchwyty lub podpisany requestState.
  • Żadne narzędzie nie wysyła żądania inicjowanego przez serwer na ścieżce 2026; każde pytanie zwraca input_required.
  • Test dymny obu er przechodzi w CI, z tymi samymi nazwami narzędzi w obu erach.
  • tools/list zwraca tę samą kolejność przy każdym wywołaniu.
  • Logi trafiają na stderr lub do OpenTelemetry; w stdio nic nie pisze na stdout.
  • Bramki, proxy i reguły WAF przepuszczają Mcp-Method, Mcp-Name i MCP-Protocol-Version.
  • Każdy obsługiwany agent został sprawdzony: Claude Code w obu erach, Codex w ustawieniu domyślnym, Cursor ręcznie.
  • Rollback jest opisany: tag poprzedniego wydania, a dla użytkowników Claude Code MCP_PROTOCOL_NEGOTIATION=legacy (lub MCP_SDK_GENERATION=v1) jako furtka po stronie klienta.

Rewizja nie zmniejsza definicji narzędzi, więc liczba tokenów, którą każde narzędzie zajmuje w kontekście agenta, zostaje taka sama. Zmienia się stabilność. tools/list w deterministycznej kolejności, z podpowiedzią świeżości ttlMs, pozwala klientowi zapisać katalog w cache i utrzymuje stabilny cache promptów u dostawcy modelu między kolejnymi połączeniami. Serwer, który przy każdym żądaniu tasuje narzędzia, psuje jedno i drugie. Zmierz stan przed zmianą i po niej przez /context w Claude Code, a narzędzia przytnij wzorcami z ograniczania kosztu tokenów MCP.

ERA_NEGOTIATION_FAILED: ... did not offer pinned protocol version 2026-07-28. Serwer nadal odpowiada tylko na initialize. Sprawdź, czy punktem wejścia jest serveStdio lub createMcpHandler, a nie bezpośrednie server.connect(...), i czy żadne proxy przed serwerem nie odpowiada na server/discover stroną błędu.

Logi przestały się pojawiać. W żądaniu z ery 2026 serwer wysyła notifications/message tylko wtedy, gdy klient umieścił logLevel w _meta. Loguj na stderr lub do OpenTelemetry, zamiast polegać na logowaniu w protokole.

NoBackChannelError (Python) albo prośba o potwierdzenie, która nigdy się nie pokazuje. Narzędzie nadal wysyła elicitation inicjowane przez serwer. W TypeScripcie zwróć input_required, w Pythonie przenieś pytanie do parametru Resolve(...).

Ponowienia kończą się błędem invalid params za load balancerem. Każda replika podpisuje requestState własnym kluczem z procesu, więc ponowienie, które trafi na inną replikę, nie przechodzi weryfikacji. Skonfiguruj jeden wspólny zestaw kluczy (createRequestStateCodec({ key }) w TypeScripcie, RequestStateSecurity(keys=[...]) w Pythonie) i rotuj go jak każdy inny sekret.

Żądania kończą się HeaderMismatch (-32020) albo w ogóle nie docierają do serwera. Bramka przepisała lub usunęła Mcp-Method albo Mcp-Name. Przepuszczaj oba nagłówki i pozwól bramce routować na ich podstawie. Jeśli serwer wywołują klienci działający w przeglądarce, dodaj Mcp-Method, Mcp-Name i MCP-Protocol-Version do Access-Control-Allow-Headers, bo przeglądarka blokuje niestandardowe nagłówki, na które nie zezwala preflight CORS.

Serwer działa w Codeksie, a w Claude Code nie. Codex mówi protokołem 2025, Claude Code z serwerami HTTP mówi 2026. Potwierdź to przez MCP_PROTOCOL_NEGOTIATION=legacy claude, co jest też obejściem dla użytkowników, a ścieżkę 2026 napraw z pomocą testu dymnego opisanego wyżej.

Serwer stdio w Ruście kończy działanie, gdy tylko klient się połączy. Serwery na Rust SDK (rmcp) kończą pracę na każde żądanie przed initialize, także na sondę server/discover. Dlatego klient TypeScript sonduje w osobnym, jednorazowym procesie. Jeśli piszesz własnego klienta, sonduj w ten sam sposób albo przypnij dla tego serwera mode: 'legacy'.

Klient nadal sprawdza stary kod błędu zasobu. „Resource not found” to teraz -32602, a nie -32002. Zaktualizuj testy, które sprawdzają starą liczbę.