gtm-mcp-server
paolobietolini/gtm-mcp-server/llms.txt
AI-accessible API for Google Tag Manager. Create tags, audit containers, generate tracking plans, and publish changes — all through natural language. Account → Container → Workspace → Entities (Tags, Triggers, Variables) Server-side containers also have: Clients, Transformations Key rules: - All mutations happen at the Workspace level — never on the live container - Changes must be versioned before publishing - Delete and Publish operations require confirm: true - Updates auto-handle fingerprint for optimistic concurrency Always discover IDs by listing…
# GTM MCP Server
> AI-accessible API for Google Tag Manager. Create tags, audit containers, generate tracking plans, and publish changes — all through natural language.
- URL: https://mcp.gtmeditor.com
- Protocol: Model Context Protocol (MCP) over Streamable HTTP
- Auth: OAuth 2.1 with PKCE (Google account)
## GTM Hierarchy
Account → Container → Workspace → Entities (Tags, Triggers, Variables)
Server-side containers also have: Clients, Transformations
Key rules:
- All mutations happen at the Workspace level — never on the live container
- Changes must be versioned before publishing
- Delete and Publish operations require `confirm: true`
- Updates auto-handle fingerprint for optimistic concurrency
## Getting Started
1. Call `auth_status` to verify authentication
2. `list_accounts` → pick an account
3. `list_containers(accountId)` → pick a container
4. `list_workspaces(accountId, containerId)` → pick a workspace (usually "Default Workspace")
5. Now you can read and write tags, triggers, and variables
Always discover IDs by listing — never guess or hardcode them.
## Tools
### Read Operations
| Tool | Purpose |
|------|---------|
| `list_accounts` | List all GTM accounts the user has access to |
| `list_containers` | List containers in an account (needs accountId) |
| `lookup_container` | Find a container by destinationId or public tagId |
| `get_container_snippet` | Get the web snippet or server container configuration |
| `list_workspaces` | List workspaces in a container (needs accountId, containerId) |
| `get_workspace` | Get workspace metadata and its fingerprint |
| `quick_preview_workspace` | Compile an ephemeral preview without saving or publishing it |
| `list_tags` | List all tags in a workspace |
| `get_tag` | Get full tag details by ID |
| `list_triggers` | List all triggers in a workspace |
| `get_trigger` | Get full trigger details by ID |
| `list_variables` | List all variables in a workspace |
| `get_variable` | Get full variable details by ID |
| `list_folders` | List folders in a workspace |
| `get_folder` | Get complete folder metadata |
| `get_folder_entities` | Get tags/triggers/variables in a specific folder |
| `list_zones` | List zones in a workspace |
| `get_zone` | Get a zone and its configuration |
| `list_environments` | List container environments (optional `environments` group) |
| `get_environment` | Get an environment and authorization metadata |
| `list_destinations` | List Google tag destinations linked to a container |
| `get_destination` | Get a destination by its link ID |
| `list_google_tag_configs` | List workspace Google tag configurations |
| `get_google_tag_config` | Get a Google tag configuration |
| `list_built_in_variables` | List enabled built-in variables |
| `get_workspace_status` | Check pending changes and merge conflicts |
### Write Operations
| Tool | Purpose |
|------|---------|
| `create_tag` | Create a new tag (needs trigger IDs) |
| `update_tag` | Modify an existing tag |
| `delete_tag` | Remove a tag (requires `confirm: true`) |
| `create_trigger` | Create a new trigger |
| `update_trigger` | Modify an existing trigger |
| `delete_trigger` | Remove a trigger (requires `confirm: true`) |
| `create_variable` | Create a new variable |
| `update_variable` | Modify an existing variable |
| `delete_variable` | Remove a variable (requires `confirm: true`) |
| `create_container` | Create a new container in an account |
| `update_container` | Rename a container |
| `delete_container` | Remove a container (requires `confirm: true`) |
| `create_workspace` | Create a new workspace |
| `update_workspace` | Update a workspace name or description |
| `delete_workspace` | Delete a workspace and pending changes (requires `confirm: true`) |
| `bulk_update_workspace` | Apply multiple entity changes (requires `confirm: true`) |
| `resolve_workspace_conflict` | Replace a conflicting entity (requires `confirm: true`) |
| `sync_workspace` | Synchronize with the latest version (requires `confirm: true`) |
| `create_folder` | Create a workspace folder |
| `update_folder` | Update a workspace folder |
| `delete_folder` | Delete a workspace folder (requires `confirm: true`) |
| `move_entities_to_folder` | Move entities into a folder (requires `confirm: true`) |
| `revert_folder` | Discard workspace changes to a folder (requires `confirm: true`) |
| `create_environment` | Create a user environment |
| `update_environment` | Update a user environment with fingerprint protection |
| `reauthorize_environment` | Rotate an environment authorization code (requires `confirm: true`) |
| `delete_environment` | Delete a user environment (requires `confirm: true`) |
| `link_destination` | Move a destination to a container (requires `confirm: true`) |
| `create_google_tag_config` | Create a Google tag configuration |
| `update_google_tag_config` | Update a Google tag configuration |
| `delete_google_tag_config` | Delete a Google tag configuration (requires `confirm: true`) |
| `combine_containers` | Merge one container into another (requires `confirm: true`) |
| `move_tag_id` | Move a tag ID to a new container (requires confirmation and terms acceptance) |
| `update_version` | Update a saved version's name or description |
| `delete_version` | Soft-delete a saved version (requires `confirm: true`) |
| `undelete_version` | Restore a deleted version (requires `confirm: true`) |
| `set_latest_version` | Make a version Latest without publishing (requires `confirm: true`) |
| `revert_workspace_entity` | Revert a built-in variable, client, tag, template, transformation, trigger, variable, or zone (requires `confirm: true`) |
| `update_account` | Rename a GTM account |
| `enable_built_in_variables` | Enable built-in variable types |
| `disable_built_in_variables` | Disable built-in variable types (requires `confirm: true`) |
| `create_zone` | Create a workspace zone |
| `update_zone` | Update selected zone fields |
| `delete_zone` | Delete a zone (requires `confirm: true`) |
### Server-Side Container Tools
| Tool | Purpose |
|------|---------|
| `list_clients` | List all clients in a server-side workspace |
| `get_client` | Get client details by ID |
| `create_client` | Create a new client |
| `update_client` | Modify an existing client |
| `delete_client` | Remove a client (requires `confirm: true`) |
| `list_transformations` | List all transformations |
| `get_transformation` | Get transformation details by ID |
| `create_transformation` | Create a new transformation |
| `update_transformation` | Modify an existing transformation |
| `delete_transformation` | Remove a transformation (requires `confirm: true`) |
### Publishing
| Tool | Purpose |
|------|---------|
| `get_workspace_status` | Check pending changes and conflicts before versioning |
| `create_version` | Create a version from workspace changes |
| `publish_version` | Publish a version to go live (requires `confirm: true`) |
| `list_versions` | List all container version headers, across all pages |
| `get_latest_version_header` | Get the latest version header; latest is not necessarily live |
| `get_version` | Get a saved version with all entity collections |
| `get_live_version` | Get the published live version with all entity collections |
### Templates
| Tool | Purpose |
|------|---------|
| `get_tag_templates` | Get GA4/HTML tag parameter format examples — call this before creating tags |
| `get_trigger_templates` | Get trigger configuration examples — call this before creating triggers |
| `list_templates` | List custom templates in a workspace |
| `get_template` | Get template details including .tpl code |
| `create_template` | Create a custom template from .tpl code |
| `update_template` | Modify an existing template |
| `delete_template` | Remove a template (requires `confirm: true`) |
| `import_gallery_template` | Import a template from the Community Gallery |
### Utility
| Tool | Purpose |
|------|---------|
| `ping` | Test connectivity to the server |
| `auth_status` | Check authentication status |
## Prompts (Workflow Templates)
These fetch workspace data and return structured analysis requests:
| Prompt | Arguments | Purpose |
|--------|-----------|---------|
| `audit_container` | accountId, containerId, workspaceId | Analyze workspace for naming issues, duplicates, orphaned items, security concerns — checked against built-in best practices |
| `best_practices_review` | accountId, containerId, workspaceId | Scored review (pass/warn/fail per category) against best-practice rules, with concrete fixes |
| `plan_safe_edit` | accountId, containerId, change_description | Step-by-step plan for a change following the safe-edit workflow (workspace → diff → version → approved publish) |
| `generate_tracking_plan` | accountId, containerId, workspaceId | Generate markdown documentation of all events, triggers, variables |
| `suggest_ga4_setup` | goals (text description) | Recommend GA4 tag structure based on tracking goals |
| `find_gallery_template` | templateName | Guide to find and import a Community Gallery template |
## Resources (URI-based Access)
Direct data access via URI patterns:
```
gtm://accounts
gtm://accounts/{accountId}/containers
gtm://accounts/{accountId}/containers/{containerId}/workspaces
gtm://accounts/{accountId}/containers/{containerId}/workspaces/{workspaceId}/tags
gtm://accounts/{accountId}/containers/{containerId}/workspaces/{workspaceId}/triggers
gtm://accounts/{accountId}/containers/{containerId}/workspaces/{workspaceId}/variables
```
Best-practices documents (static markdown, no authentication required):
```
gtm://best-practices # Index — start here
gtm://best-practices/naming-organization # Naming conventions, folders, orphans, workspace hygiene
gtm://best-practices/safe-edit-workflow # Workspace → diff → version → approved publish
gtm://best-practices/ga4-consent # GA4 tag patterns, consent mode v2, duplicate measurement
gtm://best-practices/server-side # Clients, transformations, PII redaction, first-party domains
```
Read the relevant best-practices document before creating or editing entities. Key rules: name entities `<Platform> - <Type> - <Descriptor>` (e.g. `GA4 - Event - purchase`, `DLV - transaction_id`); source measurement IDs from a lookup table or constant variable, never a literal in the tag; make changes in a dedicated workspace and show the `get_workspace_status` diff before versioning; publish only with explicit user approval. If the container already follows a different consistent convention, match it instead.
## Common Workflows
### Create a GA4 Event Tag
1. `get_tag_templates` → study the GA4 event parameter format
2. `get_trigger_templates` → study trigger format
3. `create_trigger` → create the firing condition (e.g., custom event)
4. `create_tag` → create the GA4 event tag, referencing the trigger ID from step 3
### Audit a Container
1. Discover IDs: `list_accounts` → `list_containers` → `list_workspaces`
2. Use the `audit_container` prompt with the discovered IDs
3. Or manually: `list_tags` + `list_triggers` + `list_variables` and analyze
### Publish Changes
1. `get_workspace_status` → verify no merge conflicts, review pending changes
2. `create_version` → snapshot the workspace into a version
3. `publish_version` with `confirm: true` → push the version live
### Set Up Full Ecommerce Tracking
1. `get_tag_templates` → see ecommerce tag formats
2. Create triggers for each ecommerce event (purchase, add_to_cart, view_item, etc.)
3. Create GA4 event tags for each, with `sendEcommerceData: true`
4. Create a measurement ID variable if reusing across tags
5. Version and publish when ready
### Import a Community Template
1. Use the `find_gallery_template` prompt with the template name
2. Search for the template's GitHub repository (format: `github.com/{owner}/{repo}`)
3. `import_gallery_template` with `galleryOwner` and `galleryRepository`
## Safety Rules
- **Always check status before versioning**: call `get_workspace_status` before `create_version`
- **Always version before publishing**: call `create_version` before `publish_version`
- **Confirm destructive actions**: `delete_tag`, `delete_trigger`, `delete_variable`, `delete_container`, `delete_client`, `delete_transformation`, `disable_built_in_variables`, and `publish_version` all require `confirm: true`
- **Create triggers before tags**: tags reference trigger IDs, so the trigger must exist first
- **Use templates for parameter format**: call `get_tag_templates` / `get_trigger_templates` before creating tags or triggers — the GTM API parameter format is non-obvious
- **Don't skip discovery**: always list accounts/containers/workspaces to get IDs rather than assuming them
## GA4 Tag Parameter Format
GA4 tags use a specific nested parameter structure. Key points:
- Tag type `gaawc` = GA4 Configuration, `gaawe` = GA4 Event
- `measurementId` must be an empty `tagReference` type; use `measurementIdOverride` for the actual value
- Event parameters are nested: `list` → `map` → `template` with `name`/`value` keys
- Ecommerce tags need `sendEcommerceData: true` and `getEcommerceDataFrom: dataLayer`
Always call `get_tag_templates` for exact format — do not guess the parameter structure.
## Known Limitations
- `autoEventFilter` on click/form triggers is silently dropped by the Google Tag Manager API (use the GTM web interface for those conditions)
- Tokens are in-memory — server restarts require re-authentication
- Rate limits: 10 req/s for OAuth endpoints, standard Google API quotas for GTM operations
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
No one has posted yet. Be the first.

