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:
- Marketers ask questions like "Which channel had the best ROAS last week?" directly inside Claude
- Claude inspects the BigQuery schema, writes the SQL itself, runs it, and returns a marketer-friendly summary
- All access is read-only at multiple layers, so marketers cannot accidentally damage client data
What's already proven working (pilot project: marty-search-console-ga4-api):
- Authentication via Google account → BigQuery (no API keys, no service account JSONs handed to marketers)
- Schema introspection on real GA4 connector tables (
p_ga4_*) - Live SQL execution with a sample marketer-style question, returning the right answer
- Read-only Google Developer Knowledge MCP added so Claude can self-reference Google's official docs while building/debugging
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:
- No custom MCP server built. We use Google's
genai-toolbox --prebuilt bigquerybinary, which is officially supported, free, and updated by Google. - Local toolbox per marketer rather than centrally hosted. This keeps each marketer's Google identity in their own MCP transactions, so audit logs are accurate per-user.
- No API keys for BigQuery access. Authentication is the marketer's own Google account via OAuth — meaning offboarding is just removing IAM grants in GCP, with no key rotation needed.
Prerequisites
Per client (one-time)
- A GCP project containing the client's BigQuery datasets (existing AimClear projects are fine)
- BigQuery API enabled on that project (
bigquery.googleapis.com) - Billing attached to the project (BigQuery is pay-per-query)
Per marketer
- A Google Workspace account (e.g.,
firstname@aimclear.com) - Either Claude Code or Claude Desktop installed
- Admin rights on their own laptop (to install gcloud + toolbox)
Sysadmin (Alyssa)
roles/serviceusage.serviceUsageAdminandroles/iam.securityAdminon the target GCP project (or higher)
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:
- Group name:
marketers - Group email:
marketers@aimclear.com - Members: Amber, Timothy, etc.
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
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:
- Per-marketer Google authentication. Handled by
gcloud auth application-default loginon the marketer's own machine. Tokens refresh automatically. No admin action required after initial onboarding. - Claude Desktop / Claude Code config on the marketer's laptop. The marketer owns this; if they break it, they fix it (with the deployment guide).
- Genuine secrets storage. AimClear standard is LastPass with CLI + 2FA. Not GCP Secret Manager. Don't reintroduce a second secrets store — having two is worse than one.
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:
- Marketers' MCP stack stays simple: one BigQuery MCP, that's it
- All the channel-credential complexity (API keys, OAuth, rate limits) lives in our ingestion layer
- We're not handing marketers a tangle of per-channel credentials to manage
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?
- Read any data in BigQuery datasets they've been granted access to
- Run any SELECT query (subject to BigQuery cost limits)
- See full schemas and metadata
- Trigger queries via natural language without needing to know SQL
8.2 What CANNOT a marketer do?
- Write, update, or delete any BigQuery data
- Create or drop tables, datasets, or projects
- Access projects they haven't been granted IAM roles on
- Reach data outside BigQuery (no Google Drive, Sheets, or other GCP services unless granted separately)
- Run queries on behalf of someone else's identity
8.3 Why we're confident
Three independent layers, all of which would have to fail at once for harm to occur:
- IAM allow grants are read-only roles only (
bigquery.dataViewer,bigquery.jobUser,mcp.toolUser). No write permission means no write capability. - IAM deny policy explicitly blocks
mcp.tools.callfor write-capable tools usingtool.isReadOnly == false. This is a server-side enforcement that overrides any allow grant — even if someone accidentally grantedOwnerlater, the deny still wins. - 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:
- Replace their
toolboxbinary with a new version - Run
./toolbox --versionto confirm - 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:
- Project-level quota: GCP Console → IAM & Admin → Quotas → BigQuery query usage per day. Set a hard cap.
- 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:
- Toolbox binary is present and executable:
~/bin/toolbox --versionshould print a version - ADC is set up:
gcloud auth application-default print-access-tokenshould print a token - The configured
BIGQUERY_PROJECTexists and you have access:gcloud projects describe PROJECT_ID - 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:
- Enable:
gcloud services enable geminidataanalytics.googleapis.com --project=PROJECT_ID(Alyssa) - Or just don't use that specific tool —
execute_sqlcovers the same use cases
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