gtm-manager-mcp
v0.1.16
Published
Model Context Protocol (MCP) server for managing Google Tag Manager.
Maintainers
Readme
GTM Manager MCP Server
A Model Context Protocol (MCP) server that provides comprehensive Google Tag Manager (GTM) API access. This tool enables full CRUD operations on GTM tags, variables, and triggers with proper authentication and error handling.
Features
Authentication
- OAuth 2.0 authentication with Google Tag Manager
- Secure token storage and management
- Automatic token refresh
Container Operations
- List all containers in an account
- Find containers by GTM ID
Tag Management
- List all tags in a workspace
- Create custom HTML tags
- Create native GA4 Configuration/Event tags
- Update existing tags
- Update GA4 Event tags in place
- Delete tags
- Automatic trigger assignment
- Pause/unpause tags
Validation & Publish
- Validate workspace before publishing
- Create/publish versions
Variable Management
- List all variables
- Create Custom JavaScript variables
- Create Data Layer Variables (DLVs)
- Update variable code
- Delete variables
Trigger Management
- List all triggers
- Create triggers (Page View, Click, etc.)
- Create Custom Event triggers (regex supported)
- Update trigger conditions
- Delete triggers
Prerequisites
- Node.js 18.0 or higher
- npm or yarn package manager
- Google Cloud Project with Tag Manager API enabled
- OAuth 2.0 Client ID and Secret
- Access to target GTM containers
Required OAuth Scopes
For full functionality (CRUD + submit/publish), your OAuth token must include all of:
- 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
If scopes change, re-consent: run npm run auth:url, open the URL, approve, then npm run auth:exchange -- <code>.
Installation
# Local development
npm install
npm run build
# Global install from local checkout
npm i -g .
# Or once published (package name)
# npm i -g gtm-manager-mcpGoogle Cloud Configuration
Step 1: Enable Tag Manager API
- Navigate to Google Cloud Console
- Select or create a project
- Go to APIs & Services → Library
- Search for "Tag Manager API"
- Click Enable
Step 2: Create OAuth 2.0 Credentials
- Go to APIs & Services → Credentials
- Click + CREATE CREDENTIALS → OAuth client ID
- Configure the OAuth consent screen if prompted
- Select Application type: Web application
- Add Authorized redirect URIs:
http://localhost:3101/callback (for local development) - Save the generated Client ID and Client Secret
Step 3: Environment Configuration
Copy the example environment file and configure:
cp .env.example .envEdit .env with your credentials:
# Required: Google OAuth Credentials
GOOGLE_CLIENT_ID=your-client-id-here
GOOGLE_CLIENT_SECRET=your-client-secret-here
GOOGLE_REDIRECT_URI=http://localhost:3101/callback
# Optional: Default GTM Container ID
GTM_ID=GTM-XXXXXXXLocal Callback and Auth (Port 3101)
- Start the local callback server:
npm run serve:callback # Health check: http://localhost:3101/health # Callback URL (served inline): http://localhost:3101/callback - Get the OAuth URL and authenticate:
# If installed globally gtm-mcp-auth auth:url # Or from source npm run cli -- auth:url # Open the printed URL, sign in, it redirects to http://localhost:3101/callback - Exchange the authorization code for tokens (copy the
codefrom the callback page):# If installed globally gtm-mcp-auth auth:exchange "<paste-code>" # Or from source npm run cli -- auth:exchange "<paste-code>" # Tokens saved to data/gtm-token.json
If you see "insufficient authentication scopes" on create/publish:
- Ensure the token includes
tagmanager.edit.containerversionsandtagmanager.publish(re-auth if needed). - Confirm the GTM user has Container permissions: Edit, Approve, Publish (or Admin).
Using Globally
- Install globally (from npm):
npm i -g gtm-manager-mcp - Or install from source (in repo root):
npm i -g . - Binaries available:
gtm-mcp(MCP server over stdio)gtm-mcp-callback(local OAuth callback athttp://localhost:3101/callback)gtm-mcp-auth(auth:url, auth:exchange, version:create, version:publish, submit)
- Optional for active development:
npm linkinstead of global install (remember tonpm run buildto refreshdist/).
Configure your MCP client to launch gtm-mcp with the project’s env vars.
Codex CLI config example
[mcp_servers.gtm_manager]
command = "bash"
args = ["-lc", "set -a; [ -f .env ] && source .env; exec gtm-mcp"]Per-project tokens: set GTM_TOKEN_DIR=.gtm in each project’s .env to keep tokens isolated per project.
Quick global auth flow per project:
gtm-mcp-callback(keeps callback server running)gtm-mcp-auth auth:url→ open URL and approvegtm-mcp-auth auth:exchange "<code>"
Global Codex CLI integration (single env/token)
If you want the MCP server available in every Codex CLI session with a single shared .env and token directory:
- Create a wrapper script (adjust paths):
mkdir -p ~/.local/bin cat > ~/.local/bin/gtm-mcp-global <<'SH' #!/usr/bin/env bash set -euo pipefail ENV_FILE="/absolute/path/to/.env" # update TOKEN_DIR="/absolute/path/to/data" # contains gtm-token.json if [ -f "$ENV_FILE" ]; then set -a; source "$ENV_FILE"; set +a fi export GTM_TOKEN_DIR="$TOKEN_DIR" exec gtm-mcp "$@" SH chmod +x ~/.local/bin/gtm-mcp-global - Add to Codex config
~/.codex/config.toml:[mcp_servers.gtm] command = "/Users/you/.local/bin/gtm-mcp-global" - Restart Codex CLI. In a new session, call the tool (e.g., ask to run
gtm_health).
Tip: To reuse an existing token, set GTM_TOKEN_DIR to the directory that already contains gtm-token.json.
See docs/GTM-Manager-Global-Guide.md for a step‑by‑step walkthrough.
API Reference
Health
gtm_health
Check that the server is running and env/tokens are available.
Parameters: None
Returns: Status summary with env flags and token path
gtm_health_plus
Detailed health and permissions summary.
Parameters:
format(string, optional):'json'for JSON output
Returns:
- token scopes and expiry, active container/workspace, whether publish looks allowed, and missing scopes if any
Authentication
gtm_auth
Get the OAuth authentication URL.
Parameters: None
Returns: Authentication URL to visit in browser
Example:
await gtm_auth()
// Returns: "Visit this URL to authenticate: https://accounts.google.com/..."gtm_authenticate
Complete authentication with the authorization code.
Parameters:
code(string, required): Authorization code from Google OAuth
Example:
await gtm_authenticate({ code: "4/0AY0e-g7..." })Container Operations
gtm_list_containers
List all containers accessible to the authenticated account.
Parameters:
accountId(string, optional): Specific account ID to query
Example:
await gtm_list_containers()Tag Operations
gtm_list_tags
List all tags in the current workspace.
Parameters:
gtmId(string, optional): GTM container ID (uses env default if not provided)format(string, optional):'json'for JSON outputidsOnly(boolean, optional): return IDs only
Example:
await gtm_list_tags({ gtmId: "GTM-ABC123" })gtm_find_tags
Find tags by name (case-insensitive substring).
Parameters:
name(string, required): Name or substring to search forgtmId(string, optional): GTM container IDexact(boolean, optional): Exact match onlyidsOnly(boolean, optional): Return IDs only
Example:
await gtm_find_tags({ name: 'GA4 Config' })gtm_create_tag
Create a new HTML tag.
Parameters:
name(string, required): Tag namehtml(string, required): HTML/JavaScript contenttrigger(string, optional): Trigger type (default: "pageview")
Example:
await gtm_create_tag({
name: "Analytics Event",
html: "<script>console.log('Page viewed');</script>",
trigger: "pageview"
})gtm_create_ga4_configuration
Create a native GA4 Configuration tag.
Parameters:
name(string, required): Tag namemeasurementId(string, required): GA4 Measurement ID (e.g.,G-XXXXXXX)sendPageView(boolean, optional): Send initialpage_view(default: true)trigger(string, optional): Trigger type (default:pageview)fieldsToSet(object, optional): Additional fields (name -> value)
Example:
await gtm_create_ga4_configuration({
name: 'GA4 Config',
measurementId: 'G-TEST123',
sendPageView: true,
trigger: 'pageview',
fieldsToSet: { debug_mode: 'true' }
})gtm_create_ga4_event
Create a native GA4 Event tag.
Parameters:
name(string, required): Tag namemeasurementId(string, optional): GA4 Measurement ID (e.g.,G-XXXXXXX). Optional whenconfigTagIdis provided.configTagId(string, optional): ID of a GA4 Configuration tag to link. Prefer this for Google tag containers.eventName(string, required): Event name (e.g.,login,purchase)eventParameters(object, optional): Supports{ value },{ var: 'Name' },{ varId: '53' }. WithresolveVariables: true, names/IDs are resolved into macros.trigger(string, optional): Trigger type (default:pageview)triggerId(string, optional): Explicit Trigger ID to use (e.g., a Custom Event/Regex trigger)resolveVariables(boolean, optional): Enable var resolution in parameters
Example:
await gtm_create_ga4_event({
name: 'GA4 Event Login',
configTagId: '44',
eventName: 'login',
eventParameters: { method: 'email' },
triggerId: '43'
})Notes:
- When
configTagIdis provided, the event references your GA4 Configuration tag (recommended). It maps to the vendor keysendToTagand does not setmeasurementIdOverride. - If you pass
trigger: "43"withouttriggerId, the tool will treat it as an ID automatically.
gtm_update_ga4_event_tag
Update an existing GA4 Event tag in place.
Parameters:
tagId(string, required)- Optional:
name,configTagId,measurementId,eventName,eventParameters,triggerortriggerId,resolveVariables
Example:
await gtm_update_ga4_event_tag({ tagId: '57', configTagId: '44', eventName: '{{Event}}', triggerId: '43' })gtm_pause_tag / gtm_unpause_tag
Pause or unpause a tag non-destructively.
Parameters:
tagId(string, required)
Example:
await gtm_pause_tag({ tagId: '32' })
await gtm_unpause_tag({ tagId: '32' })gtm_update_tag
Update an existing tag.
Parameters:
tagId(string, required): Tag ID to updatename(string, optional): New tag namehtml(string, optional): New HTML content
Example:
await gtm_update_tag({
tagId: "12",
html: "<script>console.log('Updated code');</script>"
})gtm_delete_tag
Delete a tag from the workspace.
Parameters:
tagId(string, required): Tag ID to delete
Example:
await gtm_delete_tag({ tagId: "12" })Variable Operations
gtm_list_variables
List all variables in the current workspace.
Parameters:
gtmId(string, optional): GTM container IDformat(string, optional):'json'for JSON outputidsOnly(boolean, optional): return IDs only
Example:
await gtm_list_variables()gtm_find_variables
Find variables by name.
Parameters:
name(string, required)exact(boolean, optional)idsOnly(boolean, optional)gtmId(string, optional)
Example:
await gtm_find_variables({ name: 'Page Path (JS)', exact: true })gtm_create_variable
Create a new Custom JavaScript variable.
Parameters:
name(string, required): Variable namecode(string, required): JavaScript function codetype(string, optional): Variable type (default: "jsm")
Example:
await gtm_create_variable({
name: "Page Title",
code: "function() { return document.title; }"
})gtm_create_dlv
Create a Data Layer Variable (DLV) without writing JS.
Parameters:
name(string, required): Display namedlvName(string, required): Data Layer key (e.g.,page.path)dataLayerVersion(number, optional): 1 or 2 (default 2)defaultValue(string, optional): Fallback value
Example:
await gtm_create_dlv({ name: 'DLV Page Path', dlvName: 'page.path', dataLayerVersion: 2, defaultValue: '/' })gtm_update_variable
Update an existing variable.
Parameters:
variableId(string, required): Variable ID to updatename(string, optional): New namecode(string, optional): New JavaScript code
Example:
await gtm_update_variable({
variableId: "5",
code: "function() { return document.title.toLowerCase(); }"
})gtm_delete_variable
Delete a variable from the workspace.
Parameters:
variableId(string, required): Variable ID to delete
Example:
await gtm_delete_variable({ variableId: "5" })Trigger Operations
gtm_list_triggers
List all triggers in the current workspace.
Parameters:
gtmId(string, optional): GTM container IDformat(string, optional):'json'for JSON outputidsOnly(boolean, optional): return IDs only
Example:
await gtm_list_triggers()gtm_find_triggers
Find triggers by name (case-insensitive substring).
Parameters:
name(string, required): Name or substring to search forgtmId(string, optional): GTM container IDexact(boolean, optional): Exact match onlyidsOnly(boolean, optional): Return IDs only
Example:
await gtm_find_triggers({ name: 'Custom Event' })gtm_create_trigger
Create a new trigger.
Parameters:
name(string, required): Trigger nametype(string, required): Trigger type ("pageview", "click", "formSubmit", etc.)conditions(array, optional): Trigger conditions
Example:
await gtm_create_trigger({
name: "Contact Form Submit",
type: "formSubmit",
conditions: [{
type: "equals",
parameter: [{
type: "template",
key: "formId",
value: "contact-form"
}]
}]
})gtm_create_custom_event_trigger
Create a Custom Event trigger (regex supported).
Parameters:
name(string, required)eventName(string, required)regex(boolean, optional)
Example:
await gtm_create_custom_event_trigger({ name: 'Login Event', eventName: '^login$', regex: true })Versions & Validation
gtm_list_versions
List container versions with names/notes.
gtm_validate_workspace
Run pre‑publish checks (missing variables, trigger references, GA4 linkage). Returns issues array when failing.
Error Handling
The MCP server provides detailed error messages for common issues:
Authentication Errors
Missing required environment variables: Check your.envfileInvalid authorization code: The OAuth code may have expiredToken refresh failed: Re-authenticate usinggtm_auth
API Errors
Container not found: Verify GTM ID and permissionsWorkspace not found: Container may not have an active workspacePermission denied: Check account access to the containerInvalid tag/variable ID: Verify the ID exists in the workspace
Common Solutions
- Re-authenticate if you see permission errors
- Check GTM permissions in Tag Manager interface
- Verify API is enabled in Google Cloud Console
Best Practices
Security
- Never commit
.envfiles to version control - Use environment-specific redirect URIs
- Regularly rotate OAuth credentials
- Limit API permissions to required scopes
Workspace Management
- Always preview changes in GTM interface before publishing
- Use descriptive names for tags and variables
- Document complex JavaScript in variables
- Test in GTM Preview mode before going live
- Publish changes manually through the GTM web interface
Performance
- Batch operations when possible
- Cache container information locally
- Minimize API calls by listing before updating
Development
Running Tests
npm testBuilding from Source
npm run buildDevelopment Mode
npm run devContributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License - see LICENSE file for details
Support
For issues and feature requests, please use the GitHub issue tracker.
