Integracje GTM dla Claude Code: trzy serwery MCP, liczba narzędzi i koszt kontekstu

Spis treści
- Trzy drogi, którymi kontener trafia do modelu
- Co leży pod spodem: 106 metod, siedem zakresów, jedna przestrzeń robocza
- Trzy serwery MCP, trzy sposoby pocięcia tego samego API
- Koszt kontekstu nie kryje się w liczbie narzędzi
- O tym, co integracja może zmienić, rozstrzyga token
- Gdzie się to psuje
- Czego to nie rozwiązuje
- Źródła
Kontener Google Tag Managera to dokument JSON, który rozstrzyga, jakie skrypty ładuje witryna i kiedy. Zmiana takiego kontenera przez prompt oznacza przekazanie modelowi językowemu prawa zapisu do tego dokumentu. Ciekawe pytanie nie brzmi, czy to działa — działa — lecz czego dokładnie model może dotknąć i ile kosztuje samo podłączenie, zanim powstanie pierwszy tag.
Na potrzeby tego artykułu zmierzono 9 września 2026 roku trzy integracje: trzy serwery MCP, każdy uruchomiony przez npx po stdio na Raspberry Pi 5 z Node 20.19.2 i zapytany o listę narzędzi, a do tego API Tag Managera v2, na którym wszystkie trzy się opierają. Liczby poniżej pochodzą z tych uruchomień oraz z dokumentu discovery samego API, nie z plików README.

Trzy drogi, którymi kontener trafia do modelu
Claude Code sam z siebie nie wie nic o Tag Managerze. Wszystko, co da się zrobić z kontenerem, przychodzi jedną z trzech dróg, a tylko dwie z nich dokładają jakąkolwiek zdolność.
Serwer MCP to proces, który Claude Code uruchamia i z którym rozmawia po stdio albo HTTP. Serwer publikuje listę narzędzi, a każde z nich pojawia się w sesji pod nazwą mcp__<serwer>__<narzędzie>. Na tę właśnie nazwę reagują później reguły uprawnień i haki — dlatego warto ją znać.
Droga przez wiersz poleceń nie wymaga żadnego serwera. Wystarczy token dostępu i curl, a zapytanie model układa sam. Nic nie ląduje wcześniej w kontekście, ale też nic nie znika za obudową — wymiana brzmi: wygoda za przejrzystość.
Skill albo polecenie ze slashem nie dokłada żadnej zdolności. Zawiera przepis: konwencję nazewniczą, listę kontrolną, kolejność, w jakiej reguła musi istnieć, zanim tag będzie mógł się do niej odwołać. To zmienia, co model robi na dwóch pozostałych drogach, nigdy zaś to, co mu wolno. Mylenie jednego z drugim jest najczęstszym nieporozumieniem wokół słowa „integracja”.
Co leży pod spodem: 106 metod, siedem zakresów, jedna przestrzeń robocza
Wszystkie drogi kończą się w tym samym miejscu. Dokument discovery API Tag Managera v2, wersja 20260902 o rozmiarze 270 858 bajtów, opisuje 106 metod w 18 zasobach: 38 GET, 38 POST, 15 PUT i 15 DELETE.
Dziesięć z tych zasobów mieści się wewnątrz przestrzeni roboczej — tagi, reguły, zmienne, zmienne wbudowane, foldery, szablony, klienty, transformacje, strefy i konfiguracja gtag. Przestrzeń robocza to szkic. To, co zostanie tam zapisane, nie dociera do żadnego odwiedzającego, choćby było zupełnie błędne.
Między szkicem a stroną na żywo stoją jeszcze dwa kroki. workspaces.create_version zamraża przestrzeń roboczą w wersję kontenera, a versions.publish czyni tę wersję aktywną. Zakres tagmanager.publish obejmuje dokładnie dwie ze 106 metod: wywołanie publikacji i environments.reauthorize. Wszystko inne, co integracja potrafi zrobić, pozostaje z założenia niewidoczne dla odwiedzających, dopóki osobne wywołanie nie postanowi inaczej.
# Odczyt tagow: sciezka niesie konto, kontener i przestrzen robocza.
# Identyfikator przestrzeni jest obowiazkowy - do tagow na zywo
# nie prowadzi zadna trasa.
ACC=6012345678; CONT=123456789; WS=42
curl -s -H "Authorization: Bearer $TOKEN" \
"https://tagmanager.googleapis.com/tagmanager/v2/accounts/$ACC/containers/$CONT/workspaces/$WS/tags"
# Bez tokenu kazda metoda odpowiada tak samo:
# {"error":{"code":401,"status":"UNAUTHENTICATED",
# "details":[{"reason":"CREDENTIALS_MISSING"}]}}
Piętnaście schematów API prowadzi pole fingerprint, którego wartość zmienia się przy każdej zmianie obiektu. Aktualizacja z nieaktualnym odciskiem zostaje odrzucona, zamiast nadpisać zmianę, którą w międzyczasie wprowadził ktoś w przeglądarce.
Trzy serwery MCP, trzy sposoby pocięcia tego samego API
| Serwer | Narzędzia | tools/list | ≈ tokeny | Krój |
|---|---|---|---|---|
google-tag-manager-mcp-server 5.1.1 |
18 | 108 201 B | 27 000 | jedno narzędzie na rodzaj obiektu, akcja jako parametr |
gtm-mcp 1.0.0 |
104 | 49 656 B | 12 400 | mniej więcej jedno narzędzie na metodę API |
@theethosteam/gtm-mcp 1.1.1 |
33 | 19 797 B | 4 900 | bliżej zadania, pięć przepisów i wywołanie surowe |
Pierwszy pakuje całe API za 18 narzędzi. Siedemnaście z nich przyjmuje parametr action, który niesie łącznie 101 akcji, z czego 38 tylko czyta; samo gtm_tag obejmuje create, get, list, update, remove i revert. Osiemnaste, gtag_destination, jedynie wypisuje listę.
Drugi odwzorowuje API niemal jeden do jednego: 104 narzędzia wobec 106 metod, 37 z nich nosi nazwę get_… lub list_….
Trzeci nie idzie za krojem API w ogóle. Obok zwykłych wywołań prowadzi pięć przepisów — gtm_recipe_ga4_config, gtm_recipe_ga4_event, gtm_recipe_meta_pixel i dwa przepisy na reguły — oraz liczące 215 bajtów wyjście awaryjne o nazwie gtm_raw na wszystko, czego pozostałe 32 narzędzia nie sięgają.
Czwarty kandydat w ogóle nie wystartował. @yoryoboy/gtm-mcp 4.1.0 przerwał komunikatem Missing required configuration: DATABASE_URL, DB_ENCRYPTION_KEY, ponieważ zbudowano go jako hostowaną usługę wielodostępną z bazą PostgreSQL za plecami, a nie jako proces lokalny. Publikacja w npm z dopiskiem „MCP server” nie mówi nic o tym, czy pakiet uruchomi się na stacji roboczej.
Koszt kontekstu nie kryje się w liczbie narzędzi
Trzy listy narzędzi różnią się rozmiarem o współczynnik 5,5, a kolejność nie idzie za liczbą narzędzi. Serwer z 18 narzędziami wysyła 108 201 bajtów definicji, ten z 33 tylko 19 797.
Dwa narzędzia odpowiadają za blisko połowę największej listy: gtm_version z 28 212 bajtami i gtm_workspace z 24 594, razem 48,8 procent ze 108 201. Powodem jest zasób ContainerVersion. Mieszczą się w nim tagi, reguły, zmienne, klienty, foldery, strefy, szablony, transformacje i konfiguracja gtag, więc w pełni otypowany schemat tego zasobu musi być duży — i jedzie w komplecie niezależnie od tego, czy jakakolwiek wersja zostanie kiedykolwiek tknięta.
To nie jest jednorazowy wydatek przy łączeniu. Definicje narzędzi należą do zapytania, jadą więc z każdą turą sesji. Wynikają z tego dwie rzeczy. Podłączenie kilku serwerów tego kroju naraz wypełnia sporą część okna kontekstu, zanim praca się zacznie. A serwer z luźniejszymi schematami nie jest z automatu wyborem słabszym: błędny typ pola API wyłapuje w sekundę, podczas gdy dokładny schemat opłaca się w każdej pojedynczej turze.
O tym, co integracja może zmienić, rozstrzyga token
Wszystkie trzy serwery logują się u Google tak samo, a właściwą barierką jest zakres OAuth. Ustawienie domyślne największego z nich żąda wszystkich siedmiu, wraz z publikacją i usuwaniem kontenerów — widać to w jego src/constants/scopes.ts jako zwykłą listę.
Ten zbiór da się zawęzić. Serwer czyta GTM_SCOPES ze zmiennych środowiskowych i dzieli po spacjach lub przecinkach. Zawężenie działa jednak tylko w jednym z trzech trybów logowania. W kodzie createAuthFromEnv przekazuje odczytane zakresy wyłącznie do gałęzi kont usługowych; gałąź tokenu odświeżającego dostaje identyfikator klienta, sekret i token, a gałąź tokenu dostępu dostaje sam token. Token odświeżający niesie w sobie zakresy, z którymi go wystawiono, a postawione obok GTM_SCOPES niczego nie zmienia i niczego nie zgłasza.
{
"mcpServers": {
"gtm": {
"command": "npx",
"args": ["-y", "google-tag-manager-mcp-server"],
"env": {
"GOOGLE_SERVICE_ACCOUNT_KEY": "{...}",
"GTM_SCOPES": "https://www.googleapis.com/auth/tagmanager.readonly"
}
}
}
}
Druga brama siedzi w samym Tag Managerze. Konto usługowe sięgnie kontenera dopiero po wpisaniu jego adresu jako użytkownika, a to uprawnienie jest stopniowane osobno dla każdego kontenera: odczyt, edycja, zatwierdzanie, publikacja. Konto z prawem edycji i zakresem publikacji i tak nie opublikuje.
Trzecia brama stoi po stronie Claude Code i chwyta za nazwę narzędzia. Reguła blokująca mcp__gtm__gtm_version wyjmuje narzędzie publikacji z zasięgu nawet tam, gdzie token pozwoliłby na wywołanie, a hak PreToolUse na tę samą nazwę może zamiast tego zażądać potwierdzenia. Są to więc trzy niezależne bramy, a rozsądnie jest domknąć najbardziej zewnętrzną — token — bo tylko ona trzyma również wtedy, gdy do kontenera ktoś sięgnie spoza tej sesji.
Gdzie się to psuje
Update zastępuje, nie uzupełnia. Piętnaście z 18 opisów narzędzi mówi to wprost: każde pole nieobecne w ładunku zostaje usunięte. Model, który wysyła tylko zmieniane pole, sprząta resztę tagu. Jedenaście narzędzi żąda dodatkowo odcisku ostatnio odczytanego stanu, co wymusza odczyt przed każdym zapisem i zamienia nieuważną zmianę w komunikat błędu zamiast w stratę.
Tag nie jest obiektem płaskim. Jego ustawienia leżą w tablicy parameter złożonej z klucza, typu i wartości, z ośmioma typami w wyliczeniu — template, integer, boolean, list, map, triggerReference, tagReference i typem nieokreślonym — przy czym list i map zagnieżdżają w sobie kolejne parametry. To na tej strukturze, a nie na nazwie tagu, wykładają się generowane ładunki.
{
"name": "GA4 - purchase",
"type": "gaawe",
"parameter": [
{ "type": "template", "key": "eventName", "value": "purchase" },
{ "type": "tagReference", "key": "measurementId",
"value": "GA4 Configuration" },
{ "type": "list", "key": "eventParameters", "list": [
{ "type": "map", "map": [
{ "type": "template", "key": "name", "value": "value" },
{ "type": "template", "key": "value", "value": "{{DLV - value}}" }
]}
]}
],
"firingTriggerId": ["17"]
}
„GTM” jest w rejestrze pakietów niejednoznaczne. Wyszukanie gtm-mcp zwraca obok serwerów do Tag Managera także te dla frameworków go-to-market; @shashwatgtmalpha/craft-gtm-mcp ma go-to-market wśród słów kluczowych, a growth-mcp określa się jako „open-source GTM MCP server”, nie mając Tag Managera na myśli w ogóle. Lista słów kluczowych rozdziela jedno od drugiego szybciej niż opis.
Czego to nie rozwiązuje
Żadna z tych integracji nie stwierdzi, czy tag rzeczywiście się uruchamia. quick_preview przekłada przestrzeń roboczą na wersję podglądową; strony nie ładuje i o spóźnionym data layerze nie powie nic. Ocena poprawności zostaje przy sesji podglądu w przeglądarce, dokładnie jak wcześniej.
API nie zapisuje też, dlaczego coś zmieniono. Wersja kontenera niesie nazwę i opis, a oba pozostają puste, o ile nie zostaną wypełnione w tym samym wywołaniu — co czyni opis wersji najtańszym miejscem na odnotowanie, który prompt wywołał którą zmianę, a zarazem pierwszą rzeczą, jakiej brakuje przy tagu zakładanym w pośpiechu.
Droga plikowa też się nie zestarzała. Wyeksportowany kontener to jeden plik JSON, a jego przejrzenie w postaci diffa nie potrzebuje ani tokenu, ani zakresu, ani serwera. Dla zmiany, którą pisze model, a czyta człowiek, eksport pozostaje drogą krótszą — przewaga API zaczyna się tam, gdzie zmianę trzeba zastosować, a nie tam, gdzie trzeba ją zrozumieć.