LW IT Solutions
« Blog Overview /Cloud & AI / GTM-Integrationen für Claude Code: Drei MCP-Server, ihre...
This post in other languages:

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

GTM-Integrationen für Claude Code: Drei MCP-Server, ihre Werkzeugzahl und ihr Kontextpreis
Inhalt
  1. Drei Wege, auf denen ein Container zum Modell kommt
  2. Was darunter liegt: 106 Methoden, sieben Scopes, ein Workspace
  3. Drei MCP-Server, drei Zuschnitte derselben API
  4. Der Kontextpreis steht nicht in der Werkzeugzahl
  5. Was eine Integration ändern darf, entscheidet das Token
  6. Wo es schiefgeht
  7. Was das nicht löst
  8. 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.

Der Weg einer Änderung vom Prompt über Claude Code und einen MCP-Server zur Tag-Manager-API, in einen Workspace und schließlich in den Live-Container, mit markiertem Veröffentlichungsschritt; darunter drei gemessene MCP-Server mit Werkzeugzahl und der Größe ihrer Werkzeugliste als Balken sowie die sieben OAuth-Scopes mit der Zahl der Methoden je Scope
Der Weg einer Änderung, die Größe dreier gemessener Werkzeuglisten und die Verteilung der 106 API-Methoden auf sieben Scopes.

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.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Kommentar schreiben

Die E-Mail-Adresse wird nicht veröffentlicht. Pflichtfelder sind mit einem Stern versehen.

ALL ARTICLES & CATEGORIES

CCTV

Diese Rubrik per RSS verfolgen

Cloud & AI

Diese Rubrik per RSS verfolgen

Data Privacy

Alle 12 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Digital Analytics

Alle 47 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Digital Marketing

Alle 25 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

IT & Networks

Alle 16 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Raspberry Pi

Diese Rubrik per RSS verfolgen

Smart Home

Alle 14 Artikel dieser Rubrik Diese Rubrik per RSS verfolgen

Web Entwicklung

Diese Rubrik per RSS verfolgen

WordPress-Plugins & Tricks

Diese Rubrik per RSS verfolgen