# ============================================================ # Samarth GTM MCP Server — Environment Configuration # Copy this file to .env and fill in your values. # NEVER commit .env or any *.gtm-mcp-tokens.json file. # ============================================================ # ── Google OAuth 2.0 Credentials (self-hosted / local dev) ─── # Create at: https://console.cloud.google.com/apis/credentials # Type: "OAuth 2.0 Client ID" → Application type: "Desktop app" or "Web application" # # Enable the "Tag Manager API", the "Google Analytics Admin API", and the # "Google Analytics Data API" in your Google Cloud project. The onboarding flow # requests the GTM scopes plus the read-only # "https://www.googleapis.com/auth/analytics.readonly" scope, which powers both # the read-only GA4 Admin tools (ga4_*) and the read-only GA4 Data API reporting # tools (ga4_run_report / ga4_run_realtime_report). No GA4 write access is # requested. # # Preferred new names: GOOGLE_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com GOOGLE_OAUTH_CLIENT_SECRET=your-client-secret GOOGLE_OAUTH_REDIRECT_URI=http://localhost:3001/oauth/callback # Legacy names (still supported — use these OR the new names, not both): # GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com # GOOGLE_CLIENT_SECRET=your-client-secret # GOOGLE_REDIRECT_URI=http://localhost:3001/oauth/callback # ── Samarth-hosted public OAuth app (optional) ─────────────── # Reserved for the Samarth-owned OAuth client used by the hosted service. # If you self-host the MCP, LEAVE THESE BLANK and use the GOOGLE_OAUTH_* vars # above. The hosted client secret MUST live on the hosted backend only — it is # never committed to this repo and never shipped to client machines. # SAMARTH_GOOGLE_OAUTH_CLIENT_ID= # SAMARTH_GOOGLE_OAUTH_CLIENT_SECRET= # ── OAuth tokens ───────────────────────────────────────────── # Easiest path: run `npm run auth:google` — it opens a browser, completes the # OAuth flow, and writes tokens to the path below (default # ./.gtm-mcp-tokens.json, in .gitignore). You do NOT need to fill these in # manually if you use the script. GTM_MCP_TOKEN_FILE=.gtm-mcp-tokens.json # Or paste tokens directly here (env vars take precedence over the token file): GOOGLE_ACCESS_TOKEN= GOOGLE_REFRESH_TOKEN= # ── Service Account (Optional, see README for limitations) ─── # Path to your downloaded service account JSON key file. # NOTE: GTM API does NOT support service accounts without domain-wide delegation. # See README section "Service Account Limitations". GOOGLE_SERVICE_ACCOUNT_KEY_FILE= # ── Transport ──────────────────────────────────────────────── # "stdio" → for Claude Desktop / Cursor / Claude Code (default) # "http" → for cloud/team HTTP+SSE server GTM_MCP_TRANSPORT=stdio # HTTP server port (only used when GTM_MCP_TRANSPORT=http) GTM_MCP_HTTP_PORT=3001 # Bearer token gating the /mcp HTTP endpoint. REQUIRED before exposing the # HTTP transport beyond localhost — when unset, /mcp is open (local dev only) # and the server logs a warning. Clients send: Authorization: Bearer # Used in single-identity mode (ignored when multi-user/Stytch mode is on). GTM_MCP_HTTP_AUTH_TOKEN= # ── Multi-user mode (Stytch Connected Apps — Phase 3) ─────────── # Setting STYTCH_PROJECT_ID switches the HTTP transport to multi-user mode: # each /mcp request carries a Stytch-issued JWT, validated here and resolved to # that user's own Google identity. Leave unset for single-identity mode. # See docs/PHASE3_IMPLEMENTATION_SPEC.md and docs/adr/0001. STYTCH_PROJECT_ID= STYTCH_SECRET= # Public token for the /oauth/authorize page (publishable, not secret). STYTCH_PUBLIC_TOKEN= # Public origin of this server (used in the Protected Resource Metadata doc). GTM_MCP_PUBLIC_URL= # Optional overrides — derived from STYTCH_PROJECT_ID when unset: # STYTCH_API_BASE (test.stytch.com / api.stytch.com) # STYTCH_JWKS_URL # STYTCH_AUTH_SERVER_METADATA_URL # Pin these once confirmed against a real token (recommended for production): # STYTCH_JWT_ISSUER # STYTCH_JWT_AUDIENCE # Bring-up only: log decoded token claims to stderr to confirm claim names. # STYTCH_DEBUG_CLAIMS=true # ── Guardrails ─────────────────────────────────────────────── # Default: read-only mode. Set to "true" to allow write operations. GTM_MCP_ENABLE_WRITES=false # Set to "true" to allow publish/version-publish operations. GTM_MCP_ENABLE_PUBLISH=false # Set to "true" to allow destructive delete operations. GTM_MCP_ENABLE_DELETES=false # ── GA4 Admin write guardrails (separate from GTM) ─────────── # GA4 is READ-ONLY by default. Enabling writes also requires the analytics.edit # scope (and analytics.manage.users for access-binding tools) — re-run the auth # flow if you first authorized read-only. Every GA4 write still needs confirm=true. # Set to "true" to allow GA4 creates/updates (key events, dimensions, metrics, # streams, links, audiences, channel groups, access bindings, properties, …). GA4_MCP_ENABLE_WRITES=false # Set to "true" to allow GA4 deletes AND archives (archive is effectively # permanent for custom dimensions/metrics and audiences). GA4_MCP_ENABLE_DELETES=false # Set to "true" to simulate all write/delete/publish without actually calling the API. DRY_RUN=false # ── Retry / backoff (heavy-workload resilience) ───────────── # Transient Google API failures (HTTP 408/429/5xx and network errors) on READ # requests are retried with exponential backoff + jitter. Mutations (anything # behind the write/publish/delete guardrails) are NEVER auto-retried. # Retry attempts after the first failure. 0 disables retries. GTM_MCP_RETRY_MAX=3 # Cap on a single backoff sleep, in milliseconds. GTM_MCP_RETRY_MAX_DELAY_MS=30000 # Cap on total wall time from first request to last retry, in milliseconds. GTM_MCP_RETRY_TOTAL_TIMEOUT_MS=60000 # ── Optional: GTM defaults ─────────────────────────────────── # Pre-fill default accountId/containerId to avoid passing them every call. GTM_DEFAULT_ACCOUNT_ID= GTM_DEFAULT_CONTAINER_ID= GTM_DEFAULT_WORKSPACE_ID= # ── Production foundation (portal — forward-looking) ───────── # The durable production subsystems (Postgres, token vault, Redis/Upstash cache, # async job queue, runtime worker, observability exporter) are scaffolded but NOT # wired. They live in the PORTAL env, not this MCP-server env. Their variable # names + secret-vs-non-secret classification are documented in # apps/portal/.env.example, and the step-by-step rollout/rollback is in # docs/PRODUCTION_CUTOVER_RUNBOOK.md. Leave them unset to keep today's behavior.