Przejdź do treści
Integracje i protokoły

Na allowliście stoi nazwa narzędzia. Protokół MCP gwarantuje jej unikalność tylko w obrębie jednego serwera

Protokół MCP gwarantuje unikalność nazwy narzędzia tylko w obrębie jednego serwera. Co to zmienia w allowliście agenta, w logu decyzji i w rachunku za cache.

Redakcja2 083 słowa10 min czytania
2 083słów w tekście
Schemat przepływu z tego tekstu2 000 zdarzeń / mies.
  1. Zdarzenie nowy mail
  2. Klasyfikacja typ, pilność, klient
  3. Narzędzia crm_search
  4. Zatrzymanie odpowiedź do klienta
  5. Działanie mail_send
  6. Log wejście, decyzja, wynik

W pliku polityki agenta stoi jedna linijka: allow: search. Do klienta podłączone są dwa serwery MCP, oba wystawiają narzędzie o nazwie search – jeden przeszukuje wewnętrzną bazę wiedzy, drugi wysyła zapytanie do zewnętrznego dostawcy danych i nabija koszt per zapytanie. Agent wywołuje search, bramka przepuszcza, w logu zostaje nazwa. Z tego logu nie da się odtworzyć, który z dwóch serwerów odpowiedział.

To nie jest błąd implementacji klienta. Specyfikacja MCP mówi wprost, że unikalność nazwy narzędzia jest ograniczona do jednego serwera, a klienty i proxy agregujące narzędzia z wielu serwerów mogą napotkać kolizje nazw – jako przykład podany jest dokładnie przypadek dwóch serwerów wystawiających search. Polityka uprawnień napisana przeciwko samym nazwom opisuje więc coś, czego protokół nie obiecuje.

Agent wywołuje narzędzie i nie wie, który serwer odpowiedział

Pierwszy odruch to sięgnąć po nazwę serwera i doklejać ją do nazwy narzędzia. Specyfikacja zamyka i tę drogę: nazwa serwera z pola serverInfo nie jest gwarantowana jako unikalna między serwerami i nie należy na niej opierać rozróżniania. Ten sam dokument zaleca klientom i proxy wdrożenie własnej strategii dezambiguacji, na przykład prefiksowania nazw identyfikatorem serwera – ale identyfikator ma pochodzić z twojej konfiguracji, nie z tego, co serwer sam o sobie mówi.

Sam format nazwy też jest tylko rekomendacją. Specyfikacja podaje, że nazwy narzędzi powinny mieć od 1 do 128 znaków, powinny być traktowane jako wrażliwe na wielkość litery i powinny używać wyłącznie liter ASCII, cyfr, podkreślenia, łącznika i kropki. Wszystko to są sformułowania typu SHOULD, nie MUST. Jeśli twoja bramka dopasowuje nazwy bez uwzględnienia wielkości liter, Search i search są dla protokołu dwoma różnymi narzędziami, a dla twojej polityki jednym.

Formalny mechanizm przestrzeni nazw jest przedmiotem otwartej propozycji SEP-993 w repozytorium specyfikacji (stan na 5 listopada 2026). Dopóki nie wejdzie do wydanej rewizji, rozróżnianie serwerów jest obowiązkiem strony klienckiej – czyli twoim.

Klient scala listy i rozstrzyga kolejnością, nie polityką

Co robią klienty w praktyce, zależy od klienta. Część prefiksuje nazwy identyfikatorem serwera z konfiguracji. Część scala listy w jedną i wywołanie trafia tam, gdzie trafi. Na forum Cursora opisano zgłoszenie, w którym wywołania przy kolizji nazw routowały się do serwera pierwszego na liście; to raport użytkownika, nie dokumentacja, i traktuj go jako objaw do sprawdzenia u siebie, nie jako opis zachowania wszystkich klientów.

Problem jednej nazwy pokrywającej kilka różnych rzeczy nie jest specyficzny dla MCP i warto to zobaczyć na mniej abstrakcyjnym przykładzie: w zakupach firmowego oprogramowania jedno słowo „VPN” nazywa trzy różne klasy produktu, a koszt pomyłki ponosi ten, kto dopasowywał po nazwie zamiast po tym, co produkt faktycznie robi. Bramka agenta popełnia dokładnie ten błąd, tylko szybciej i bez faktury, która by go ujawniła.

Sprawdzenie jest tanie i nie wymaga czytania kodu klienta. Podłącz dwa serwery testowe wystawiające narzędzie o tej samej nazwie, które w odpowiedzi zwracają własny identyfikator, i wywołaj je. Odpowiedź powie, który odpowiedział – i czy nazwa w logu wystarczy, żeby to odtworzyć po fakcie.

Serwer dopisuje narzędzie w trakcie sesji

Druga nieoczywistość: lista narzędzi nie jest stała. Serwer, który zadeklarował zdolność listChanged, może wysłać powiadomienie notifications/tools/list_changed, a specyfikacja mówi, że zestaw narzędzi może zmieniać się w czasie. Polityka zatwierdzeń napisana przeciwko liście odczytanej przy starcie opisuje stan z chwili startu, nie stan bieżący.

Są dwa różne powody, dla których lista może się zmienić, i warto je rozdzielić, bo wymagają innej reakcji. Pierwszy jest legalny: specyfikacja dopuszcza, by zestaw zwracanych narzędzi zależał od autoryzacji przedstawionej w żądaniu – serwer może oddać tylko te narzędzia, na które pozwalają nadane uprawnienia. Rotacja tokenu albo zmiana zakresu uprawnień zmieni wtedy listę bez żadnej złej intencji. Ta sama specyfikacja zabrania jednak, by zestaw różnił się per połączenie albo zmieniał się jako efekt uboczny innych żądań na tym połączeniu – i to jest granica, którą można testować.

Powód drugi jest wektorem ataku i opisuje go strona o bezpieczeństwie w specyfikacji. W scenariuszu przejęcia sesji, gdy serwer potrafi zmieniać oferowane narzędzia, klient może skończyć z narzędziami, o których nie wiedział, że są włączone. Agent nie ma czym tego zauważyć: dla niego nowe narzędzie to po prostu kolejna pozycja na liście, z opisem, który zachęca do użycia.

Bramka czyta readOnlyHint, a tę flagę deklaruje serwer

Najczęstszy skrót przy projektowaniu bramki to oparcie decyzji na adnotacjach narzędzia – przepuszczaj bez pytania to, co ma readOnlyHint, zatrzymuj to, co ma destructiveHint. Specyfikacja stawia tu ostrzeżenie w najmocniejszej formie: klienty MUSZĄ traktować adnotacje narzędzi jako niezaufane, o ile nie pochodzą z zaufanych serwerów. Adnotacja jest deklaracją strony, której właśnie nadajesz uprawnienia. Bramka oparta na niej pyta serwer, czy wolno mu to, co chce zrobić.

Od serwera pochodzi też semantyka błędu, a to zmienia zachowanie agenta. Protokół rozdziela dwa mechanizmy: błędy protokołu w polu error JSON-RPC (nieznane narzędzie, niepoprawne żądanie) i błędy wykonania narzędzia zwracane w wyniku z isError: true. Specyfikacja zaleca, by klienty przekazywały modelowi błędy wykonania, bo pozwalają na samokorektę, a błędy protokołu przekazywały opcjonalnie, bo rzadziej prowadzą do udanego odzyskania. Serwer, który zwraca odmowę uprawnień jako zwykłą treść bez isError, dostaje agenta, który uzna ją za odpowiedź i poleci dalej. Serwer, który tę samą odmowę oznaczy jako błąd wykonania, dostaje agenta, który będzie próbował ponownie – czasem w pętli.

Para serwer plus nazwa jako jedyny klucz polityki

Z trzech mechanizmów powyżej wychodzi jedna zmiana w projekcie: polityka nie może być kluczowana nazwą narzędzia. Kluczem jest para złożona z identyfikatora serwera, który pochodzi z twojej konfiguracji, i nazwy narzędzia, porównywanej z uwzględnieniem wielkości liter.

Krok przepływu Co się dzieje Co klient może zweryfikować sam Miejsce awarii
Podłączenie serwera Klient czyta serverInfo i zdolności Zgodność z wpisem w konfiguracji: adres, sposób uwierzytelnienia, własny identyfikator Identyfikator brany z serverInfo, nie z konfiguracji
tools/list Serwer oddaje zestaw narzędzi Każda nazwa przypisana do identyfikatora serwera; wykryte kolizje między serwerami Scalenie list w jedną płaską tablicę nazw
Decyzja polityki Dopasowanie wywołania do reguły Dopasowanie po parze serwer plus nazwa, wrażliwe na wielkość liter Dopasowanie po samej nazwie albo po adnotacji z serwera
Zatwierdzenie przez człowieka Operator widzi wywołanie i argumenty Nazwa serwera z konfiguracji pokazana obok nazwy narzędzia Operator widzi samo search
tools/call Wywołanie leci do konkretnego serwera Wpis w logu zawiera parę, nie samą nazwę Log nieodtwarzalny po fakcie
list_changed Serwer zgłasza zmianę zestawu Różnica wobec zestawu przypiętego przy zatwierdzeniu polityki Klient dociąga nową listę i używa jej bez porównania

Dwie rzeczy w tej tabeli są warte osobnego zdania. Po pierwsze, ekran zatwierdzenia: jeśli operator widzi samo search, jego zgoda nie rozstrzyga o niczym, bo nie wie, co zatwierdza. Po drugie, reakcja na list_changed: samo dociągnięcie nowej listy nie wystarcza. Trzeba porównać ją z zestawem przypiętym w chwili, gdy polityka była zatwierdzana, i zatrzymać agenta na narzędziach, których w tym zestawie nie było. To ta sama zasada, którą stosuje się do uprawnień: specyfikacja po stronie serwera zaleca minimalizację zakresów i wymienia zakresy wieloznaczne i omnibusowe jako typowy błąd, a serwerom MCP zabrania przyjmowania tokenów, które nie zostały wystawione dla nich – do czego dochodzi zalecenie logowania użycia narzędzi na potrzeby audytu.

Kto to składa, jest osobną decyzją niż to, czy warstwa agentowa ma sens. Rejestr po stronie klienta, przypięte zestawy narzędzi i log z parami to kilka dni pracy przy pierwszym serwerze i stały koszt utrzymania przy każdym następnym; jeśli zespół nie ma tego w planie, wykonawcy biorący na siebie utrzymanie warstwy agentowej są tańsi niż odtwarzanie po fakcie, kto wywołał które narzędzie.

Rachunek miesięczny: zmiana listy narzędzi unieważnia cały cache

Higiena protokołu ma cenę wyrażoną w rachunku za tokeny, i nie jest mała. Definicje narzędzi stoją na początku żądania: w dokumentacji Anthropica prefiks cache tworzony jest w kolejności tools, system, messages, a modyfikacja definicji narzędzi – nazw, opisów, parametrów – unieważnia cały cache. Nie część po zmianie. Cały. Ta sama zależność widziana z drugiej strony stoi w specyfikacji MCP: serwery powinny zwracać narzędzia w deterministycznej kolejności, bo to pozwala klientom cache’ować listę i podnosi skuteczność cache promptów.

Liczby dla konkretnego ustawienia. Agent z sześcioma podłączonymi serwerami, 54 narzędzia, definicje zajmują 9 400 tokenów, prompt systemowy 2 600 – prefiks 12 000 tokenów. Ruch: 1 200 spraw miesięcznie, średnio siedem żądań do modelu na sprawę, czyli 8 400 żądań. Cennik Claude Opus 5.5 sprawdzony 5 listopada 2026: 4 dolary za milion tokenów wejściowych, 5 dolarów za milion przy zapisie do cache z pięciominutowym TTL i 0,20 dolara za milion przy odczycie z cache. Rachunek dotyczy wyłącznie prefiksu – bez treści rozmowy i bez tokenów wyjściowych.

Wariant Zapisy do cache Odczyty z cache Koszt prefiksu miesięcznie
Lista stabilna, zapis raz na sprawę 1 200 × 0,06 USD 7 200 × 0,0024 USD 89,28 USD
Jedno list_changed w połowie sprawy 2 400 × 0,06 USD 6 000 × 0,0024 USD 158,40 USD
Zestaw zmienny przy każdym wywołaniu, cache bezużyteczny brak, 8 400 × 0,048 USD jako zwykłe wejście brak 403,20 USD

Między wierszem pierwszym a trzecim jest 313,92 dolara miesięcznie na samym prefiksie, przy tym samym ruchu i tym samym modelu – czyli około czteroipółkrotność. Zwróć uwagę na trzeci wiersz: zapis do cache kosztuje więcej niż zwykłe wejście (5 dolarów wobec 4 za milion), więc przy zestawie, który zmienia się co wywołanie, cache nie jest neutralny, tylko szkodliwy – taniej go nie włączać.

Założenie o jednym zapisie na sprawę zależy od gęstości ruchu i od pięciominutowego TTL i u ciebie będzie inne. Nie zgaduj: policz z pola usage.cache_read_input_tokens w odpowiedziach, jaki udział żądań faktycznie trafia w cache. Jeśli to zero przy powtarzalnym prefiksie, coś go unieważnia – a zmienna lista narzędzi jest pierwszym kandydatem, którego warto wykluczyć.

Co rozstrzygnąć przed podłączeniem drugiego serwera

Jedna rzecz do policzenia zawczasu: log, który pozwala odtworzyć, kto wywołał co i w którym systemie, bywa funkcją płatną. W narzędziach SaaS jest to regularny podział – wymuszenie drugiego czynnika bywa w planie darmowym, a log zdarzeń dopiero w najdroższym. Jeśli agent sięga przez MCP do takiego systemu, audyt po stronie dostawcy może nie istnieć w twoim planie i cały ciężar odtwarzalności spada na log klienta.

Kolejność, w której to się daje zrobić bez przepisywania bramki dwa razy:

  • Nadaj każdemu serwerowi identyfikator w swojej konfiguracji i nigdy nie bierz go z serverInfo.
  • Przerób klucz polityki z nazwy na parę serwer plus nazwa, z porównaniem wrażliwym na wielkość liter.
  • Przypnij zestaw narzędzi w chwili zatwierdzania polityki i trzymaj go jako wartość odniesienia.
  • Na list_changed porównaj nowy zestaw z przypiętym i zatrzymaj agenta na różnicy, zamiast przyjmować ją w ciszy.
  • Wyrzuć adnotacje serwera z warunków bramki. Zostaw je jako podpowiedź w interfejsie dla operatora, nie jako przesłankę decyzji.
  • Pokaż operatorowi identyfikator serwera obok nazwy narzędzia i zapisz parę w logu decyzji.
  • Sprawdź, czy serwery oddają listę w stałej kolejności, i zmierz udział trafień w cache, zanim ktokolwiek zacznie szacować rachunek.

Pytanie do rozstrzygnięcia przed podłączeniem drugiego serwera jest jedno: czy po wywołaniu, które poszło nie tam, gdzie powinno, jesteś w stanie z własnego logu wskazać serwer. Jeśli w logu stoi sama nazwa, odpowiedź jest przecząca – i żadna liczba bramek zatwierdzeń tego nie nadrobi, bo wszystkie pytają o to samo niejednoznaczne pole.