GTM-Integrationen für Claude Code: Drei MCP-Server, ihre Werkzeugzahl und ihr Kontextpreis

Inhalt
- Drei Wege, auf denen ein Container zum Modell kommt
- Was darunter liegt: 106 Methoden, sieben Scopes, ein Workspace
- Drei MCP-Server, drei Zuschnitte derselben API
- Der Kontextpreis steht nicht in der Werkzeugzahl
- Was eine Integration ändern darf, entscheidet das Token
- Wo es schiefgeht
- Was das nicht löst
- Quellen
Ein Google-Tag-Manager-Container ist ein JSON-Dokument, das darüber entscheidet, welche Skripte eine Website lädt und wann. Diesen Container per Prompt zu ändern heißt, einem Sprachmodell Schreibzugriff auf dieses Dokument zu geben. Die interessante Frage ist nicht, ob das funktioniert — das tut es —, sondern was das Modell genau anfassen darf und was die Anbindung kostet, bevor ein einziges Tag entsteht.
Für diesen Artikel wurden am 9. September 2026 drei Integrationen gemessen: drei MCP-Server, jeder mit npx über stdio auf einem Raspberry Pi 5 mit Node 20.19.2 gestartet und nach seiner Werkzeugliste gefragt, dazu die Tag-Manager-API v2, auf der alle drei aufsetzen. Die Zahlen unten stammen aus diesen Läufen und aus dem Discovery-Dokument der API, nicht aus den READMEs.

Drei Wege, auf denen ein Container zum Modell kommt
Claude Code weiß von sich aus nichts über den Tag Manager. Alles, was mit einem Container möglich wird, kommt über einen von drei Wegen, und nur zwei davon fügen überhaupt eine Fähigkeit hinzu.
Ein MCP-Server ist ein Prozess, den Claude Code startet und mit dem es über stdio oder HTTP spricht. Er veröffentlicht eine Liste von Werkzeugen, und jedes davon erscheint in der Sitzung unter dem Namen mcp__<server>__<werkzeug>. Auf genau diesen Namen greifen später Berechtigungsregeln und Hooks zu — deshalb lohnt es sich, ihn zu kennen.
Der direkte Weg über die Kommandozeile braucht gar keinen Server. Ein Zugriffstoken und curl genügen, und das Modell schreibt die Anfrage selbst. Vorab landet nichts im Kontext, dafür verschwindet auch nichts hinter einer Hülle — der Tausch lautet Bequemlichkeit gegen Durchsicht.
Eine Skill oder ein Slash-Befehl fügt überhaupt keine Fähigkeit hinzu. Darin steht ein Rezept: eine Namenskonvention, eine Prüfliste, die Reihenfolge, in der ein Trigger existieren muss, bevor ein Tag ihn referenzieren kann. Das ändert, was das Modell auf den anderen beiden Wegen tut, nie aber, was es tun darf. Diese beiden Dinge zu verwechseln ist das häufigste Missverständnis am Wort „Integration”.
Was darunter liegt: 106 Methoden, sieben Scopes, ein Workspace
Alle Wege enden an derselben Stelle. Das Discovery-Dokument der Tag-Manager-API v2, Fassung 20260902 und 270.858 Byte groß, beschreibt 106 Methoden in 18 Ressourcen: 38 GET, 38 POST, 15 PUT und 15 DELETE.
Zehn dieser Ressourcen liegen innerhalb eines Workspace — Tags, Trigger, Variablen, integrierte Variablen, Ordner, Vorlagen, Clients, Transformationen, Zonen und die gtag-Konfiguration. Ein Workspace ist ein Entwurf. Was dort hineingeschrieben wird, erreicht keinen einzigen Besucher, ganz gleich wie falsch es ist.
Zwischen Entwurf und Live-Seite stehen zwei weitere Schritte. workspaces.create_version friert einen Workspace zu einer Containerversion ein, und versions.publish macht diese Version live. Der Scope tagmanager.publish deckt genau zwei der 106 Methoden ab: den Veröffentlichungsaufruf und environments.reauthorize. Alles andere, was eine Integration anstellen kann, bleibt bauartbedingt für Besucher unsichtbar, bis ein eigener Aufruf etwas anderes bestimmt.
# Tags lesen: der Pfad traegt Konto, Container und Workspace.
# Eine Workspace-ID ist Pflicht - zu den Live-Tags fuehrt keine Route.
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"
# Ohne Token antwortet jede Methode gleich:
# {"error":{"code":401,"status":"UNAUTHENTICATED",
# "details":[{"reason":"CREDENTIALS_MISSING"}]}}
Fünfzehn Schemas der API führen ein Feld fingerprint, dessen Wert sich mit jeder Änderung des Objekts ändert. Eine Aktualisierung mit veraltetem Fingerabdruck wird abgewiesen, statt eine Bearbeitung zu überschreiben, die inzwischen jemand im Browser vorgenommen hat.
Drei MCP-Server, drei Zuschnitte derselben API
| Server | Werkzeuge | tools/list | ≈ Token | Zuschnitt |
|---|---|---|---|---|
google-tag-manager-mcp-server 5.1.1 |
18 | 108.201 B | 27.000 | ein Werkzeug je Objektart, Aktion als Parameter |
gtm-mcp 1.0.0 |
104 | 49.656 B | 12.400 | etwa ein Werkzeug je API-Methode |
@theethosteam/gtm-mcp 1.1.1 |
33 | 19.797 B | 4.900 | aufgabennah, fünf Rezepte und ein Rohaufruf |
Der erste packt die ganze API hinter 18 Werkzeuge. Siebzehn davon nehmen einen Parameter action entgegen, der zusammen 101 Aktionen trägt, von denen 38 nur lesen; allein gtm_tag deckt create, get, list, update, remove und revert ab. Das achtzehnte, gtag_destination, listet nur.
Der zweite bildet die API fast eins zu eins ab: 104 Werkzeuge gegenüber 106 Methoden, 37 davon heißen get_… oder list_….
Der dritte folgt dem Zuschnitt der API gar nicht. Neben den gewöhnlichen Aufrufen führt er fünf Rezepte — gtm_recipe_ga4_config, gtm_recipe_ga4_event, gtm_recipe_meta_pixel und zwei Trigger-Rezepte — und einen 215 Byte kleinen Notausgang namens gtm_raw für alles, was die übrigen 32 Werkzeuge nicht erreichen.
Ein vierter Kandidat startete überhaupt nicht. @yoryoboy/gtm-mcp 4.1.0 brach mit Missing required configuration: DATABASE_URL, DB_ENCRYPTION_KEY ab, weil er als gehosteter Mehrmandantendienst mit PostgreSQL dahinter gebaut ist und nicht als lokaler Prozess. Eine Veröffentlichung auf npm mit „MCP server” in der Beschreibung sagt nichts darüber, ob ein Paket auf einem Arbeitsplatzrechner läuft.
Der Kontextpreis steht nicht in der Werkzeugzahl
Die drei Werkzeuglisten unterscheiden sich um den Faktor 5,5 in der Größe, und die Reihenfolge folgt nicht der Zahl der Werkzeuge. Der Server mit 18 Werkzeugen sendet 108.201 Byte Definitionen, der mit 33 nur 19.797.
Zwei Werkzeuge machen fast die Hälfte der größten Liste aus: gtm_version mit 28.212 Byte und gtm_workspace mit 24.594, zusammen 48,8 Prozent von 108.201. Der Grund ist die Ressource ContainerVersion. In ihr stecken Tags, Trigger, Variablen, Clients, Ordner, Zonen, Vorlagen, Transformationen und die gtag-Konfiguration, ein vollständig typisiertes Schema davon ist also zwangsläufig groß — und es wird mitgeschickt, ob je eine Version angefasst wird oder nicht.
Das ist keine einmalige Ausgabe beim Verbinden. Werkzeugdefinitionen gehören zur Anfrage und reisen deshalb bei jedem Zug der Sitzung mit. Daraus folgen zwei Dinge. Mehrere Server dieses Zuschnitts gleichzeitig anzubinden füllt einen beträchtlichen Teil des Kontextfensters, bevor die Arbeit beginnt. Und ein Server mit lockereren Schemas ist nicht selbstverständlich die schwächere Wahl: einen falschen Feldtyp fängt die API binnen einer Sekunde ab, während ein genaues Schema in jedem einzelnen Zug bezahlt wird.
Was eine Integration ändern darf, entscheidet das Token
Alle drei Server melden sich auf dieselbe Weise bei Google an, und das eigentliche Geländer ist der OAuth-Scope. Die Voreinstellung des größten Servers fordert alle sieben an, Veröffentlichen und Containerlöschung eingeschlossen — nachzulesen in seiner src/constants/scopes.ts als schlichte Liste.
Diese Menge lässt sich einengen. Der Server liest GTM_SCOPES aus seiner Umgebung und trennt an Leerzeichen oder Kommas. Die Einengung wirkt allerdings nur in einer der drei Anmeldearten. Im Quelltext übergibt createAuthFromEnv die gelesenen Scopes ausschließlich an den Zweig für Dienstkonten; der Zweig für Refresh-Token bekommt Client-ID, Geheimnis und Token, der Zweig für Zugriffstoken bekommt das Token. Ein Refresh-Token trägt die Scopes bereits in sich, mit denen es ausgestellt wurde, und ein daneben gesetztes GTM_SCOPES ändert nichts und meldet nichts.
{
"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"
}
}
}
}
Ein zweites Tor sitzt im Tag Manager selbst. Ein Dienstkonto erreicht einen Container erst, nachdem seine Adresse dort als Benutzer eingetragen wurde, und diese Berechtigung ist je Container abgestuft: lesen, bearbeiten, genehmigen, veröffentlichen. Ein Konto mit Bearbeitungsrecht und Veröffentlichungs-Scope kann trotzdem nicht veröffentlichen.
Das dritte Tor steht auf der Seite von Claude Code und greift am Werkzeugnamen an. Eine Sperrregel auf mcp__gtm__gtm_version nimmt das Veröffentlichungswerkzeug aus der Reichweite, auch wo das Token den Aufruf erlauben würde, und ein PreToolUse-Hook auf denselben Namen kann stattdessen eine Bestätigung verlangen. Drei voneinander unabhängige Tore also, und sinnvoll ist es, das äußerste zu schließen — das Token —, weil allein dieses auch dann hält, wenn der Container von anderswo als aus dieser Sitzung erreicht wird.
Wo es schiefgeht
Update ersetzt, es ergänzt nicht. Fünfzehn der 18 Werkzeugbeschreibungen sagen es selbst: Jedes Feld, das in der Nutzlast fehlt, wird gelöscht. Ein Modell, das nur das zu ändernde Feld schickt, räumt den Rest des Tags ab. Elf der Werkzeuge verlangen zusätzlich den Fingerabdruck des zuletzt gelesenen Standes, was vor jedem Schreiben ein Lesen erzwingt und aus einer unachtsamen Änderung eine Fehlermeldung statt eines Verlusts macht.
Ein Tag ist kein flaches Objekt. Seine Einstellungen liegen in einem Feld parameter aus Schlüssel, Typ und Wert, mit acht Typen in der Aufzählung — template, integer, boolean, list, map, triggerReference, tagReference und dem unbestimmten —, wobei list und map weitere Parameter in sich verschachteln. An dieser Struktur, nicht am Tag-Namen, scheitern erzeugte Nutzlasten.
{
"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” ist im Paketverzeichnis mehrdeutig. Eine Suche nach gtm-mcp liefert neben den Tag-Manager-Servern auch solche für Go-to-Market-Frameworks; @shashwatgtmalpha/craft-gtm-mcp führt go-to-market unter seinen Schlagworten, und growth-mcp bezeichnet sich als „open-source GTM MCP server”, ohne den Tag Manager überhaupt zu meinen. Die Schlagwortliste trennt die beiden schneller als die Beschreibung.
Was das nicht löst
Keine dieser Integrationen kann feststellen, ob ein Tag tatsächlich auslöst. quick_preview übersetzt einen Workspace in eine Vorschauversion; eine Seite lädt es nicht, und über einen zu spät eintreffenden Data Layer sagt es nichts. Das Urteil über die Richtigkeit bleibt bei einer Vorschausitzung im Browser, genau wie zuvor.
Ebenso wenig hält die API fest, warum etwas geändert wurde. Eine Containerversion trägt Namen und Beschreibung, und beide bleiben leer, sofern sie nicht im selben Aufruf gefüllt werden — was die Versionsbeschreibung zur billigsten Stelle macht, um festzuhalten, welcher Prompt welche Änderung ausgelöst hat, und zugleich zum Ersten, was bei einem eilig angelegten Tag fehlt.
Und der Dateiweg ist nicht überholt. Ein exportierter Container ist eine einzige JSON-Datei, und sie gegen einen Diff zu prüfen braucht weder Token noch Scope noch Server. Für eine Änderung, die ein Modell schreibt und ein Mensch liest, bleibt der Export der kürzere Weg — der Vorteil der API beginnt dort, wo die Änderung angewendet werden muss, nicht dort, wo sie verstanden werden muss.