Admin Setup Guide ← All Guides

Admin Setup Guide

For Alyssa — GCP configuration, IAM, onboarding marketers, and ongoing ops.

Executive Summary

This guide deploys a working pipeline that lets AimClear marketers ask plain-English questions about client BigQuery data through Claude. Rather than building custom infrastructure, we use Google's official BigQuery MCP toolbox bridged into Claude Code (or Claude Desktop) on each marketer's machine.

What this enables today:

What's already proven working (pilot project: marty-search-console-ga4-api):

Time to onboard a new marketer: ~15 minutes once GCP-side IAM is in place.
Time to onboard a new client project: ~30 minutes one-time, plus per-marketer above.

Architecture

┌────────────┐       ┌─────────────────┐       ┌──────────────────┐
│  Marketer  │──────▶│  Claude Code /  │──────▶│  MCP Toolbox     │
│  (browser  │       │  Claude Desktop │ stdio │  (local binary)  │
│  or app)   │       │                 │       │                  │
└────────────┘       └─────────────────┘       └────────┬─────────┘
                                                        │
                                              Google Application
                                              Default Credentials
                                                  (OAuth2)
                                                        │
                                                        ▼
                                              ┌──────────────────┐
                                              │  Google BigQuery │
                                              │  (client data)   │
                                              └──────────────────┘

                Security gates (in order, all enforced server-side):
                ┌─────────────────────────────────────────────────┐
                │  1. IAM allow grants (read-only roles only)     │
                │  2. IAM deny policy: tool.isReadOnly=false      │
                │  3. BigQuery time travel (7-day undo)           │
                │  4. Audit log of every query (goog-mcp-server)  │
                └─────────────────────────────────────────────────┘

Key architectural decisions:

Prerequisites

Per client (one-time)

Per marketer

Sysadmin (Alyssa)

One-Time GCP Project Setup

Run these once per client project. All commands are for Alyssa on her admin machine.

5.1 Enable required APIs

PROJECT=marty-search-console-ga4-api   # change per project

gcloud services enable bigquery.googleapis.com --project=$PROJECT
gcloud beta services mcp enable bigquery.googleapis.com --project=$PROJECT

5.2 Create the marketer Google Group (recommended)

If you don't already have one, make a single Google Group like marketers@aimclear.com. Granting access at the group level means adding/removing a marketer is a one-line membership change, not 10+ IAM grants per project.

In Google Workspace Admin → Groups → Create:

5.3 Grant the group read-only BigQuery + MCP roles

PROJECT=marty-search-console-ga4-api
GROUP=marketers@aimclear.com

gcloud projects add-iam-policy-binding $PROJECT \
  --member="group:$GROUP" --role="roles/bigquery.dataViewer"

gcloud projects add-iam-policy-binding $PROJECT \
  --member="group:$GROUP" --role="roles/bigquery.jobUser"

gcloud projects add-iam-policy-binding $PROJECT \
  --member="group:$GROUP" --role="roles/mcp.toolUser"

These three roles are the minimum and maximum marketers should ever have on a client project. Do not grant dataEditor, dataOwner, or Editor/Owner at the project level.

5.4 Apply the deny policy (defense-in-depth)

This blocks write-capable MCP tools (execute_sql running anything other than SELECT) even if a marketer somehow ends up with elevated permissions for unrelated reasons.

Save as mcp-deny-readwrite.json:

{
  "rules": [
    {
      "denyRule": {
        "deniedPrincipals": [
          "principalSet://goog/group/marketers@aimclear.com"
        ],
        "deniedPermissions": [
          "mcp.googleapis.com/tools.call"
        ],
        "denialCondition": {
          "title": "Deny write-capable MCP tools for marketers",
          "expression": "api.getAttribute('mcp.googleapis.com/tool.isReadOnly', false) == false"
        }
      }
    }
  ]
}

Apply:

gcloud iam policies create mcp-deny-readwrite \
  --attachment-point=cloudresourcemanager.googleapis.com/projects/$PROJECT \
  --kind=denypolicies \
  --policy-file=mcp-deny-readwrite.json
The mcp-deny-readwrite.json file is a working artifact — only needed during apply. Once GCP accepts it, the policy lives server-side. Recommended: keep the file in a private AimClear-internal infra repo so it's version-controlled.

5.5 Verify the policy is active

gcloud iam policies list-deny-policies \
  --attachment-point=cloudresourcemanager.googleapis.com/projects/$PROJECT

You should see mcp-deny-readwrite listed.

Ops Responsibility Map

Audience: Alyssa (and anyone covering for her).
Context: I'm wearing every hat on this — GCP, IAM, MDM, BigQuery, Workspace, secrets — but each ongoing task lives in a different console or tool. This is a quick-reference so I open the right one without thinking about it.

The Map

Task Tool / Console Frequency
Add or remove a marketer from the team Google Workspace Admin (marketers@aimclear.com group) Per hire / depart
Grant a marketer access to a client's data GCP IAM — folder-level grants on the client's folder Per assignment
Add or remove a client → marketer mapping GCP IAM — grant/revoke marketers@aimclear.com group on the client's project (no BigQuery table needed) Per assignment
Add a new client project to AimClear's portfolio GCP IAM + BigQuery directory tables Per new client
Push toolbox.yaml to all marketer laptops MDM (Intune / Jamf / whatever we run) Rare — only on capability changes
Push toolbox binary updates MDM ~Quarterly
Rotate genuine secrets (OAuth client secrets, service account JSON keys, ad-channel API tokens) LastPass CLI (AimClear standard, with 2FA) Per security policy
Investigate "why can't [marketer] see [client]?" GCP IAM logs + BigQuery directory tables As needed
Audit who ran what query GCP Logging — filter resource.type="bigquery_resource" AND protoPayload.metadata.jobChange.job.jobConfig.queryConfig.labels.goog-mcp-server="true" As needed
Set or adjust per-project query cost caps GCP Console → IAM & Admin → Quotas → BigQuery Per project, then rarely

For each task there's exactly one console to open. That's the point of this map — same person, but different mental mode per task.

Directory decision: resolved — no table needed

IAM is the sole source of truth. The toolbox is registered in Claude with no pinned project. When a marketer asks about a client, Claude queries the Google Cloud Resource Manager API using the marketer's existing credentials — this returns exactly the projects that marketer's Google account has access to. No BigQuery directory table to maintain, no drift between IAM and a separate list.

Adding a new client to a marketer's view = granting marketers@aimclear.com access to that client's GCP project in IAM. That's it. The change is visible to Claude immediately.

What's NOT in this map (and why)

These are real ongoing concerns, but not Alyssa-managed:

One assumption to flag

The whole architecture is built on the assumption that multi-channel data (Google Ads, Meta, LinkedIn, etc.) streams into BigQuery via central ingestion pipelines — not that marketers individually connect to ad platforms via MCP.

Practically this means:

If that assumption ever breaks (e.g., we decide marketers should be able to push changes back to ad platforms via Claude), the entire credential and security model reopens. Worth a deliberate conversation before going there.

Security Model

8.1 What CAN a marketer do?

8.2 What CANNOT a marketer do?

8.3 Why we're confident

Three independent layers, all of which would have to fail at once for harm to occur:

  1. IAM allow grants are read-only roles only (bigquery.dataViewer, bigquery.jobUser, mcp.toolUser). No write permission means no write capability.
  2. IAM deny policy explicitly blocks mcp.tools.call for write-capable tools using tool.isReadOnly == false. This is a server-side enforcement that overrides any allow grant — even if someone accidentally granted Owner later, the deny still wins.
  3. BigQuery time travel retains 7 days of table state. If something somehow slipped through both layers above, recovery is one query.

8.4 What happens if a marketer leaves AimClear?

Remove them from marketers@aimclear.com Google Group. All access on every client project disappears immediately. Nothing else to revoke — no API keys, no service account passwords, no local credentials we have to chase down. Their local ADC token is already expired by the time they're walked out, and even if it weren't, the IAM grant is gone.

FAQ — Sysadmin

Q: How is auth handled? Is there an API key I have to rotate?

No API keys for BigQuery access. Each marketer authenticates via their own Google account using gcloud auth application-default login. Tokens are stored locally and refresh automatically. Revocation is via Google Workspace or by removing them from the marketers group.

Q: How do I revoke a marketer's access immediately?

Remove them from the marketers@aimclear.com Google Group. IAM updates propagate within ~1 minute. Their next BigQuery query will fail with 403 Permission Denied. Their local ADC token is useless without the IAM grant behind it.

Q: How do I audit who ran what query?

GCP Console → Logging → Logs Explorer. Filter by:

resource.type="bigquery_resource"
protoPayload.metadata.jobChange.job.jobConfig.queryConfig.labels.goog-mcp-server="true"

Every MCP-driven query is auto-tagged with that label. The protoPayload.authenticationInfo.principalEmail field shows the actual user.

Q: What if the toolbox binary updates?

Google publishes new versions to https://storage.googleapis.com/genai-toolbox/vX.Y.Z/. To upgrade a marketer:

  1. Replace their toolbox binary with a new version
  2. Run ./toolbox --version to confirm
  3. No Claude config changes needed

We should pin a known-good version organization-wide to avoid drift between marketers. Current pinned: v0.32.0.

Q: What if BigQuery exports change schema?

The MCP introspects the schema fresh on every conversation, so schema changes are picked up automatically. No code on our side needs updating. Worst case: Claude returns "I don't see a column called X" and the marketer tries a different question.

Q: What happens if a marketer accidentally racks up a huge BigQuery bill?

Two cost controls available:

  1. Project-level quota: GCP Console → IAM & Admin → Quotas → BigQuery query usage per day. Set a hard cap.
  2. Per-query bytes-billed limit: can be set as a default project property; queries that estimate exceeding it are rejected before running.

Recommend: set per-project daily query quota at ~10x typical use as a safety net.

Q: Can we centrally host the MCP toolbox instead of installing per laptop?

Yes, eventually. Google's hosted BigQuery MCP server (https://bigquery.googleapis.com/mcp) does exactly this — but requires an OAuth client setup per Claude install, which is more friction for marketer onboarding than ADC. Worth migrating to once we have 5+ marketers and the per-laptop install starts feeling tedious.

Q: Does this work behind AimClear's VPN / firewall?

Yes, as long as marketers can reach *.googleapis.com and *.google.com (they already can — they use Workspace). The toolbox makes outbound HTTPS calls to BigQuery; nothing inbound.

Troubleshooting

bigquery-X — ✗ Failed to connect after claude mcp list

Check, in order:

  1. Toolbox binary is present and executable: ~/bin/toolbox --version should print a version
  2. ADC is set up: gcloud auth application-default print-access-token should print a token
  3. The configured BIGQUERY_PROJECT exists and you have access: gcloud projects describe PROJECT_ID
  4. MCP service is enabled on the project: check with Alyssa

Error 403: BigQuery: Permission denied while getting Drive credentials

The query touches a Sheets-backed external table but ADC lacks Drive scope. Re-auth with:

gcloud auth application-default login \
  --scopes=https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/bigquery

Error 403: SERVICE_DISABLED: Data Analytics API with Gemini has not been used

Only the ask_data_insights tool needs this. Either:

Error: Permission 'mcp.tools.call' denied on tool by deny policy

Working as intended — the deny policy from §5.4 caught a write attempt. Confirm with the marketer that they were trying to do something read-only; if so, the query may be misclassified. If not, the system is doing its job.

Claude Desktop config not picked up

Restart Claude Desktop fully (quit + reopen), don't just close the window. On macOS: Cmd+Q. On Windows: right-click the tray icon → Quit, then reopen.

Claude Code MCP showing as connected but tools not appearing in conversation

Start a fresh Claude Code session — MCP tools are registered at session start. /reload-plugins does NOT reload MCP servers (it's for plugins/skills/agents/hooks).

Quick Reference

PROJECT_ID:       marty-search-console-ga4-api    (pilot)
TOOLBOX VERSION:  v0.32.0
MARKETER ROLES:   bigquery.dataViewer, bigquery.jobUser, mcp.toolUser
DENY POLICY:      mcp-deny-readwrite (blocks tool.isReadOnly=false)
GROUP:            marketers@aimclear.com

COMMANDS CHEAT SHEET (sysadmin)
  Enable APIs:       gcloud services enable bigquery.googleapis.com --project=$PROJECT
                     gcloud beta services mcp enable bigquery.googleapis.com --project=$PROJECT
  Grant marketer:    gcloud projects add-iam-policy-binding $PROJECT \
                       --member="user:NAME@aimclear.com" --role="roles/bigquery.dataViewer"
                     (repeat for jobUser, mcp.toolUser)
  Apply deny policy: gcloud iam policies create mcp-deny-readwrite \
                       --attachment-point=cloudresourcemanager.googleapis.com/projects/$PROJECT \
                       --kind=denypolicies --policy-file=mcp-deny-readwrite.json
  Audit log filter:  resource.type="bigquery_resource" AND
                     protoPayload.metadata.jobChange.job.jobConfig.queryConfig.labels.goog-mcp-server="true"

COMMANDS CHEAT SHEET (marketer, one-time setup)
  Authenticate:      gcloud auth application-default login
  Add to Claude:     claude mcp add --scope user bigquery ~/bin/toolbox -- --prebuilt bigquery --stdio
  Verify:            claude mcp list