Content
# gtm-agent — GTM MCP + CLI
One codebase that exposes [**Google Tag Manager API v2**](https://developers.google.com/tag-platform/tag-manager/api/v2/) as:
- An **MCP server** (`gtm-mcp`) — tools + prompts + read-only resources, **stdio** (Cursor, Claude Desktop, …) or **streamable HTTP** for local MCP-over-HTTP.
- A **`gtm`** CLI with the same backend.
Official overview: [Tag Manager](https://developers.google.com/tag-platform/tag-manager).
## Prerequisites
- [uv](https://github.com/astral-sh/uv) + **Python ≥ 3.11** (this repo is exercised on Python 3.13).
- A GCP project with the **Tag Manager API** enabled — easiest via the Terraform bootstrap in **[terraform/README.md](terraform/README.md)** (also creates an optional service account + key).
- **Google credentials** — pick one:
- **OAuth desktop client** (browser login): JSON at `keys/secrets.json` or `GTM_OAUTH_CLIENT_PATH`. Token cached at `~/.config/gtm-mcp/token.json`. *Create the OAuth client once in [Cloud Console → Credentials](https://console.cloud.google.com/apis/credentials) (type: Desktop app).*
- **Service account** (headless): key JSON at `keys/gtm-reader-key.json` or `GTM_KEY_PATH`. Enable with `GTM_USE_SERVICE_ACCOUNT=true`. Add the SA e-mail in Tag Manager → Admin → User Management.
- **Application Default Credentials**: `gcloud auth application-default login` (see [gcloud install](https://cloud.google.com/sdk/docs/install)). Used as fallback when no OAuth/SA file is found.
## Installation (repository)
```bash
cd gtm-agent
uv sync --group dev
uv run gtm --help
uv run gtm-mcp --help
```
### Install from a wheel *without publishing* (`uvx --from`)
Build a wheel locally, then wire your MCP client to that wheel (safe for reviewing packaging before PyPI):
```bash
uv build # omit keys/ — see hatch excludes in pyproject.toml
uvx --from dist/gtm_agent-0.1.0-py3-none-any.whl gtm-mcp --help
```
When you publish to PyPI/uv index later, swap `uvx --from …wheel…` for `uvx gtm-mcp`.
## MCP in Cursor (stdio)
Repo example: [.cursor/mcp.example.json](.cursor/mcp.example.json) — replace the absolute `--directory` path.
After edits, reload MCP in Cursor.
### Streamable HTTP (local only)
Expose the MCP app on **`http://HOST:PORT/mcp`** (default **`127.0.0.1:8931/mcp`**). No extra auth layer: treat like an open local API — do **not** forward to the public internet **without your own protections**.
```bash
uv run gtm-mcp --transport streamable-http --host 127.0.0.1 --port 8931
```
Client snippet:
```json
{
"mcpServers": {
"gtm": {
"url": "http://127.0.0.1:8931/mcp"
}
}
}
```
### Bootstrap & defaults (`~/.config/gtm-mcp/config.json`)
Recommended first calls for any agent session:
| Step | MCP tool |
|------|----------|
| 1 | `gtm_bootstrap` → accounts × containers snapshot |
| 2 | Optional `workspaces_list` → pick workspace id |
| 3 | `gtm_set_defaults` with `{ "account_id", "container_id", "workspace_id" }` |
Same defaults as **`gtm config set …`** and env vars `GTM_ACCOUNT_ID`, `GTM_CONTAINER_ID`, `GTM_WORKSPACE_ID`.
### Read-only MCP server
Expose only **non-destructive** tools (`tags_delete`, `versions_publish`, … omitted):
```bash
uv run gtm-mcp --read-only
```
Or **`GTM_MCP_READONLY=true`**.
### Tool presets (**`lite`** vs **`full`**)
Default register set is **`lite`** (fewer tools; omits zones/templates/clients/transformations and similar low-level binds). **`full`** registers every MCP binding.
Override per process:
```bash
GTM_TOOLSET=full uv run gtm-mcp
uv run gtm-mcp --toolset full
```
### MCP resources (“snapshots”, read-only JSON)
Clients can prefetch context without issuing every list tool:
| URI | Meaning |
|-----|---------|
| `gtm://catalog` | Raw method names + destructive list |
| `gtm://current_workspace` | `tags_list` / `triggers_list` / `variables_list` (≈30s cache) |
| `gtm://live_version_summary` | Live version counts |
### Prompts (~50 workflows)
Markdown library under **`gtm_mcp/prompts/library/`**, exposed as MCP prompts (Cursor `/` prompt menu, Claude Desktop prompts, …). Add a `.md` with front-matter `name` / `description` and restart MCP.
Extended intro page (Playwright MCP–style skeleton): **[docs/index.md](docs/index.md)**.
### Destructive tool calls & auth profiles
Destructive MCP methods enforce **`confirm: true`** in the MCP arguments (until blocked entirely by **`--read-only`**).
Scopes are grouped by **`GTM_AUTH_PROFILE`**: **`readonly`** / **`edit`** / **`publish`** (default CLI + MCP) / **`admin`**.
```bash
uv run gtm auth login-hint publish
```
Auth-source selection (in order):
1. `GTM_USE_SERVICE_ACCOUNT=true` → reads key from `GTM_KEY_PATH` or `keys/gtm-reader-key.json`.
2. OAuth client JSON at `GTM_OAUTH_CLIENT_PATH` or `keys/secrets.json` → browser login on first run.
3. Application Default Credentials (`gcloud auth application-default login`).
Note: profile scopes apply to **OAuth and ADC** only. Service-account access is granted in the GTM UI (per account/container), not via these scopes.
## CLI cheatsheet
```bash
uv run gtm catalog
uv run gtm catalog --destructive-only
uv run gtm run tags_list --payload '{}'
uv run gtm run tags_delete --payload '{"tag_id":"42"}' --confirm
```
GA4 shorthand examples:
```bash
uv run gtm quick ga4-event \
--account-id 6240708935 \
--container-id 190466187 \
--workspace-id 2 \
--google-tag-name "GA4 - Configuration tag"
```
See previous README sections inside your favourite notes or **`gtm --help`** for more.
## Tests
```bash
uv run pytest tests/test_smoke.py -q
```
---
## Appendix (Nederlands)
Dit package is nog **niet voor publieke distributie gedacht** als je `keys/` lokaal vult — die map hoort **`gitignored`** te zijn; laat **`uv build`** controleren dat er geen `keys/` of `secrets` in artefacten zit.
Het volledige MCP-instructiemodel zit in **`gtm_mcp/instructions.md`** (Engels onboarding-blok + GTM conventions). Gebruik `gtm_bootstrap` / `gtm_set_defaults` en optioneel MCP-resources voordat je tags wijzigt — het blijft GTM-production data.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.