The official Google Ads MCP connector works fine in Claude Code, but in Claude Cowork filtered queries fail. This gist explains the issue and a small wrapper script that fixes it, without modifying the connector itself.
The connector loads and authenticates. Simple reads work. But the moment you ask for anything filtered or sorted, for example "spend by campaign last month," it fails with:
Input should be a valid list [type=list_type, input_value='[...]', input_type=str]
Meanwhile the exact same connector, same credentials, works perfectly in Claude Code.
An MCP client decides how to send each argument based on the tool's schema. The Google Ads search tool declares its filter and sort parameters (conditions and orderings) as arrays without a typed items entry. Faced with an untyped array, Cowork serializes the value into a string instead of a real list. The connector then rejects the string.
You can see the split clearly:
| Parameter | Schema | What Cowork sends | Result |
|---|---|---|---|
fields |
array with typed items | a real list | works |
conditions |
array, untyped | a JSON string | rejected |
orderings |
array, untyped | a JSON string | rejected |
Instead of changing the connector, put a tiny script in front of it. The script reads each request, turns those stringified arrays back into real lists, and passes everything else through untouched. Then you point Cowork at the script instead of the connector.
Cowork -> ga_mcp_proxy.py -> the real Google Ads connector
(repairs the request
on the way through)
It is non invasive and reversible. Point the config back at the connector to undo it.
ga_mcp_proxy.py: the wrapper script (no secrets, safe to share).
1. Save the script somewhere on your machine, for example:
C:\Users\YOURNAME\ga_mcp_proxy.py
Open it and set REAL_EXE to the path of your real connector (or set a GA_MCP_REAL_EXE environment variable instead).
2. Point Cowork at the script. In Claude Desktop go to Settings, Developer, Edit Config, and change the connector entry.
Before:
"google-ads": {
"command": "C:\\Users\\YOURNAME\\.local\\bin\\google-ads-mcp.exe",
"args": [],
"env": { "...your credentials..." }
}After:
"google-ads": {
"command": "python",
"args": ["C:\\Users\\YOURNAME\\ga_mcp_proxy.py"],
"env": { "...your credentials, unchanged..." }
}3. Restart. Fully quit Claude Desktop from the system tray, reopen, and start a new Cowork session. Filtered queries now work.
Google's setup guide shows an env block with only two keys:
"env": {
"GOOGLE_PROJECT_ID": "YOUR_PROJECT_ID",
"GOOGLE_ADS_DEVELOPER_TOKEN": "YOUR_DEVELOPER_TOKEN"
}That was not enough for me. This is the env that actually worked:
"env": {
"GOOGLE_APPLICATION_CREDENTIALS": "C:\\path\\to\\application_default_credentials.json",
"GOOGLE_PROJECT_ID": "YOUR_PROJECT_ID",
"GOOGLE_CLOUD_PROJECT": "YOUR_PROJECT_ID",
"GOOGLE_ADS_DEVELOPER_TOKEN": "YOUR_DEVELOPER_TOKEN",
"GOOGLE_ADS_LOGIN_CUSTOMER_ID": "YOUR_MANAGER_MCC_ID",
"FASTMCP_LOG_LEVEL": "CRITICAL",
"FASTMCP_DISABLE_BANNER": "1"
}What the extra keys do:
GOOGLE_APPLICATION_CREDENTIALS: path to your credentials file. Rungcloud auth application-default loginfirst to create it. The official sample leaves this out.GOOGLE_CLOUD_PROJECT: set it to the same value asGOOGLE_PROJECT_ID. The Google auth library readsGOOGLE_CLOUD_PROJECTfor the billing and quota project, andGOOGLE_PROJECT_IDalone is effectively ignored by it.GOOGLE_ADS_LOGIN_CUSTOMER_ID: your manager (MCC) account ID, needed when the account you query sits under a manager account.FASTMCP_*: optional. They just keep the connector's startup output quiet.
Never publish your config file. It holds your credentials and developer token. The script in this gist contains no secrets and is safe to share. The values above are placeholders, so replace them with your own and keep the filled in version private.
The wrapper idea came from a second AI assistant after the first kept telling me it could not be done in Cowork. Worth remembering: when one assistant hits a wall, ask another.