Skip to main content
Glama
A1-x-Tech

Google Tag Manager MCP

README.md
# <img src="./assets/a1-logo.svg" alt="A1" width="40"> Google Tag Manager MCP

**English** | [Русский](./README.ru.md)

[![npm](https://img.shields.io/npm/v/mcp-google-tagmanager)](https://www.npmjs.com/package/mcp-google-tagmanager)
[![Glama](https://glama.ai/mcp/servers/A1-x-Tech/mcp-google-tagmanager/badges/score.svg)](https://glama.ai/mcp/servers/A1-x-Tech/mcp-google-tagmanager)
[![CI](https://github.com/A1-x-Tech/mcp-google-tagmanager/actions/workflows/ci.yml/badge.svg)](https://github.com/A1-x-Tech/mcp-google-tagmanager/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)

**A1 Google Tag Manager MCP** lets an AI app inspect and manage Google Tag Manager containers in plain language. See what fires on a page, work with tags, triggers and variables in a draft workspace, then deliberately compile and publish a version when you are ready.

It connects to the Google Tag Manager API v2 through your Google account. The difference from asking an AI to guess a GTM setup is that it works with the actual container, workspace and version you choose.

- **25 tools.** 10 operations only read GTM data; 4 create drafts or change built-in variables; 5 can alter, delete, compile or publish live configuration.
- **Connects from the conversation.** Say "connect Google Tag Manager": the server walks you through the OAuth client, catches Google's redirect on `127.0.0.1` with PKCE and keeps the tokens itself — no config files, no restart.
- **Draft first.** Tags, triggers and variables are created in a workspace. Publishing is a separate, explicitly destructive operation.
- **Quota-aware.** GTM permits 0.25 requests per second per project; the server spaces requests by at least 4.2 seconds instead of overwhelming the API.
- **Your Google access.** The server uses your OAuth credentials and requests only the Tag Manager scopes needed for reading, editing, versioning and publishing.

Start with a read-only question:

> Which tags in my containers fire on the page-view trigger?

[Connect the server](#quick-start) · [Explore use cases](#what-you-can-ask-it-to-do) · [Open technical documentation](#technical-documentation)

---

## See it work in a minute

> **You:** List my GTM containers and show which tags fire on page view.
>
> **Assistant:** Lists the containers, their workspaces, relevant triggers and the tags attached to them. Nothing changes.
>
> **You:** In the Default Workspace of `GTM-ABC123`, prepare a GA4 configuration tag for measurement ID `G-XXXXXXX` on all pages.
>
> **Assistant:** Shows the workspace, proposed tag and trigger configuration, then asks for confirmation before creating the draft.
>
> **You:** Confirm the draft.
>
> **Assistant:** Creates the tag in the workspace. It does not publish the container; compiling and publishing a version remains a separate step.

## Contents

- [Quick start](#quick-start)
- [What you can ask it to do](#what-you-can-ask-it-to-do)
- [How GTM changes are connected](#how-gtm-changes-are-connected)
- [What can change](#what-can-change)
- [Getting access](#getting-access)
- [Configuration](#configuration)
- [Data and telemetry](#data-and-telemetry)
- [Limits and background work](#limits-and-background-work)
- [Technical documentation](#technical-documentation)
- [Support](#support)

## Quick start

You need Node.js 20+ and a Google account. Credentials are not required at install time — the server connects from the conversation.

1. Add the server to your AI app.
2. Say "connect Google Tag Manager": the assistant walks you through [creating the OAuth client and approving access](#getting-access) without editing config files.
3. Start with the read-only question above.

<details open>
<summary><strong>Codex</strong></summary>

<br>

**In the app:**

1. Open **Settings → MCP servers**.
2. Select **Add server**.
3. Choose **STDIO**, then enter `npx -y mcp-google-tagmanager@latest` and the three environment variables below.

| Variable | Value |
|---|---|
| `GOOGLE_TAGMANAGER_CLIENT_ID` | Your Google OAuth client ID |
| `GOOGLE_TAGMANAGER_CLIENT_SECRET` | Your Google OAuth client secret |
| `GOOGLE_TAGMANAGER_REFRESH_TOKEN` | Your Google OAuth refresh token |

4. Select **Save**, then **Restart**.

**From the command line:**

```bash
codex mcp add google-tagmanager \
  -- npx -y mcp-google-tagmanager@latest
```

```bash
codex mcp list
```

[Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli)

</details>

<details>
<summary><strong>Claude Code</strong></summary>

<br>

```bash
claude mcp add \
  --transport stdio \
  --scope user \
  google-tagmanager \
  -- npx -y mcp-google-tagmanager@latest
```

```bash
claude mcp list
```

[Claude Code MCP documentation](https://code.claude.com/docs/en/mcp)

</details>

<details>
<summary><strong>Claude Desktop</strong></summary>

<br>

The current official path is **Settings → Extensions**. For a custom desktop extension, open **Advanced settings → Extension Developer → Install Extension…**, select a `.mcpb` file and follow the prompts.

This repository currently publishes an npm stdio package and does not contain a `.mcpb` bundle. For Claude Desktop builds that still support local configuration, use the following JSON stdio configuration as a fallback:

```json
{
  "mcpServers": {
    "google-tagmanager": {
      "command": "npx",
      "args": ["-y", "mcp-google-tagmanager@latest"]
    }
  }
}
```

In those builds, save it to `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS or `%APPDATA%\Claude\claude_desktop_config.json` on Windows.

[Claude Desktop MCP documentation](https://support.claude.com/en/articles/10949351-getting-started-with-local-mcp-servers-on-claude-desktop)

</details>

<details>
<summary><strong>Cursor</strong></summary>

<br>

Add a user-level server to `~/.cursor/mcp.json` on macOS/Linux or `%USERPROFILE%\.cursor\mcp.json` on Windows:

```json
{
  "mcpServers": {
    "google-tagmanager": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "mcp-google-tagmanager@latest"]
    }
  }
}
```

[Cursor MCP documentation](https://cursor.com/docs/mcp)

</details>

<details>
<summary><strong>VS Code</strong></summary>

<br>

Run **MCP: Open User Configuration** from the Command Palette and add:

```json
{
  "servers": {
    "google-tagmanager": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "mcp-google-tagmanager@latest"]
    }
  }
}
```

Check it with **MCP: List Servers**.

[VS Code MCP documentation](https://code.visualstudio.com/docs/agent-customization/mcp-servers)

</details>

## What you can ask it to do

### Understand the current setup

- List the GTM accounts and containers I can access.
- Which tags fire on page view in this workspace?
- Show the trigger and variable configuration for this tag.
- Which built-in variables are enabled?

### Prepare tracking changes in a draft

- Create a workspace for the checkout tracking change.
- Prepare a GA4 tag and a trigger for a specific event.
- Enable the click variables needed for this trigger.
- Update this tag after showing me the complete replacement configuration.

### Release a version deliberately

- Compile this workspace into a version named `April release`.
- Show the compiler errors, if any.
- Publish version `42` after I confirm the version and its changes.

## How GTM changes are connected

GTM has a clear release path:

1. An **account** contains one or more **containers**.
2. A container has **workspaces** for draft changes.
3. Tags, triggers and variables belong to a workspace.
4. Compiling a workspace creates a **container version** and removes the source workspace. GTM provides a replacement workspace.
5. Publishing makes a selected container version live.

This server can inspect each step. It does not treat a draft as a release: version creation and publishing are separate operations.

## What can change

| Operation | What happens | Confirmation boundary |
|---|---|---|
| List accounts, containers, workspaces, tags, triggers, variables and versions | Reads GTM configuration | No change |
| Create a container or workspace | Adds a new GTM object | Changes GTM |
| Create a tag, trigger or variable | Adds a draft object to a workspace | Changes a draft workspace |
| Enable or disable built-in variables | Changes the workspace configuration | Changes a draft workspace |
| Update a tag, trigger or variable | Replaces the complete resource, protected by its fingerprint | Potentially destructive |
| Delete a tag, trigger or variable | Removes the selected object | Destructive |
| Compile a workspace | Creates a version and deletes the source workspace | Destructive |
| Publish a version | Makes a selected version live | Destructive |
| Raw API request | Can call API methods without a dedicated tool | Potentially destructive |

The AI client decides how it asks for confirmation. The server marks read-only, write and destructive operations so the client can distinguish inspection from a real change.

## Getting access

Google Tag Manager requires OAuth 2.0; an API key is not enough. There are two ways in, and the first one needs no configuration files.

### Connect from the chat (recommended)

Say "connect Google Tag Manager" and the assistant runs the flow with you:

1. `setup_instructions` prints the checklist: create or select a Google Cloud project, enable **Tag Manager API**, configure the consent screen and create a **Desktop app** OAuth client.
2. Download that client's JSON ("Download JSON") and give the assistant its **path** — `set_client` stores it owner-only. The secret never goes through the conversation.
3. `start_login` returns a Google consent link. Open it **on this machine** and approve; the code comes back to a one-shot listener on `127.0.0.1` (PKCE), never through the chat.
4. `finish_login` exchanges the code and saves the tokens to `~/.config/mcp-google-tagmanager/credentials.json` (mode 0600) and verifies them with a real Tag Manager API call — so an API that is still switched off is caught right there.

The tokens are re-read on every call, so the connection works immediately — no restart of the AI app. `auth_status` shows what is connected, `logout` revokes and deletes it.

### Environment variables (CI, unattended installs)

1. Create or select a Google Cloud project and enable the [Tag Manager API](https://console.cloud.google.com/apis/library/tagmanager.googleapis.com). A project without that API enabled receives no quota.
2. Configure the OAuth consent screen and create an OAuth client. A **Desktop app** client is suitable for local use.
3. Authorize your Google account and obtain a refresh token. The [OAuth 2.0 Playground](https://developers.google.com/oauthplayground) can do this if you enable **Use your own OAuth credentials**.
4. Request these scopes together:

   ```text
   https://www.googleapis.com/auth/tagmanager.readonly
   https://www.googleapis.com/auth/tagmanager.edit.containers
   https://www.googleapis.com/auth/tagmanager.edit.containerversions
   https://www.googleapis.com/auth/tagmanager.publish
   ```

The scopes are separate: reading, editing, compiling versions and publishing each need their corresponding permission. Treat the client secret and refresh token as passwords.

## Configuration

Every variable is optional — with none of them the server connects [from the chat](#connect-from-the-chat-recommended).

| Variable | Required | Description |
|---|---|---|
| `GOOGLE_TAGMANAGER_CLIENT_ID` | No* | OAuth client ID. |
| `GOOGLE_TAGMANAGER_CLIENT_SECRET` | No* | OAuth client secret. |
| `GOOGLE_TAGMANAGER_REFRESH_TOKEN` | No* | OAuth refresh token. |
| `GOOGLE_TAGMANAGER_ACCESS_TOKEN` | No* | Short-lived alternative to the OAuth trio. |
| `GOOGLE_TAGMANAGER_OAUTH_PORT` | No | Fixed loopback port for the in-chat login; useful over SSH port forwarding. |
| `GOOGLE_TAGMANAGER_API_BASE` | No | Tag Manager API base URL override. |
| `GOOGLE_TAGMANAGER_TIMEOUT_MS` | No | Per-request timeout; default `60000` ms. |
| `GOOGLE_TAGMANAGER_MAX_RETRIES` | No | Maximum retries on temporary failures; default `3`. |
| `GOOGLE_TAGMANAGER_MIN_INTERVAL_MS` | No | Minimum request spacing; default `4200` ms. |

\* Provide either the OAuth trio or an access token. Access tokens expire in about an hour and are not refreshed automatically.

## Data and telemetry

The server runs locally and sends GTM API requests and OAuth refresh requests to Google. Its anonymous telemetry contains a random installation ID, package version, AI client and Node.js/operating-system versions, and tool names. It does not send OAuth tokens, GTM data, tool arguments or prompts.

Disable telemetry for A1 MCP servers with:

```bash
ASKADS_TELEMETRY=0
```

## Limits and background work

- **GTM is rate-limited.** The API allows 0.25 requests per second per project, so the server serializes calls at least 4.2 seconds apart. Broad audits can therefore take time.
- **Temporary limits are retried carefully.** `429` and Google quota `403` responses use exponential backoff and `Retry-After`. Reads retry after network and `5xx` failures; writes are not replayed after an uncertain failure.
- **There is no background monitoring.** The server runs only when your AI app calls it. If the app supports scheduled tasks, it can periodically inspect a container or its live version.
- **A workspace disappears when compiled.** Before calling `create_version`, save anything you need from the workspace and inspect the returned replacement workspace path.

## Technical documentation

- [MCP capability catalog](./docs/capabilities/index.md) — task-oriented pages for every tool.
- [All tools and inputs](./docs/TOOLS.md)
- [Development documentation](./docs/DEVELOPMENT.md)
- [Publishing documentation](./docs/PUBLISHING.md)
- [Google Tag Manager API v2 reference](https://developers.google.com/tag-platform/tag-manager/api/reference/rest)

## Support

Found a bug or need a scenario? [Create an issue](https://github.com/A1-x-Tech/mcp-google-tagmanager/issues) or write in [Telegram](https://t.me/a1_mcp).

<br>

<p align="center">
  <img src="https://github.com/ztemerbekov/a1-yandex-kit-skills/raw/main/assets/images/mona-hifive-yandex-kit-warm.gif" alt="Две Моны дают пять" width="256">
</p>

<p align="center">
  You made it to the end!
</p>

TDQS

A4.1/5.0

Scored across 25 tools

Disambiguation4/5

Most tools have clearly distinct purposes, with specific list/get/create/update/delete operations for each resource type. The generic get_resource and raw_request tools are well-described as fallbacks, but they could cause minor confusion with the dedicated getters. Auth-related tools are distinct and clearly separated.

Naming Consistency4/5

The majority of tools follow a consistent verb_noun pattern (list_triggers, create_container, update_entity). A few auth-related tools (auth_status, setup_instructions, set_client, start_login, finish_login, logout) and raw_request deviate from this pattern, but they are clearly named and don't disrupt the overall consistency.

Tool Count4/5

With 25 tools, the server is on the heavier side but appropriately scoped for the Google Tag Manager API, which has many resource types and operations. Each tool covers a meaningful part of the domain, and the count is justified by the complexity of GTM.

Completeness4/5

The tool set covers the core GTM lifecycle: account/container/workspace management, CRUD for tags/triggers/variables, built-in variable toggles, and version creation/publishing. The raw_request escape hatch fills gaps for less common resources (environments, folders, templates), making the surface quite complete, though a few dedicated tools could be added for those.

Maintenance

ActivityActive
ResponsivenessNo issues