#
tokens: 3806/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── assets
│   └── images
│       ├── osx-1.png
│       ├── osx-2.png
│       ├── osx-3.png
│       ├── osx-4.png
│       ├── osx-5.png
│       └── osx-6.png
├── build
│   ├── client
│   │   └── gaql-client.js
│   └── index.js
├── package.json
├── README.md
├── src
│   ├── client
│   │   └── gaql-client.ts
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | 
  2 | # Google Ads MCP (Node.js) - by TrueClicks
  3 | 
  4 | Google Ads MCP by TrueClicks enables your AI (like Claude) to securely access and query your Google Ads account data. It supports both Windows and macOS, including Intel and ARM-based systems. It connects AIs to Google Ads using [GAQL.app] as a backend.
  5 | 
  6 | This is an *unofficial* Google Ads MCP integration - and as of now, **no official version exists**.
  7 | 
  8 | ---
  9 | 
 10 | ## ✅ Why Use This MCP?
 11 | 
 12 | Unlike other open-source Multi-Client Processors (MCPs) for Google Ads, this Node.js-based MCP offers **the easiest setup experience available**:
 13 | 
 14 | - 🟢 **No Google Cloud Project setup required**
 15 | - 🟢 No OAuth credentials
 16 | - 🟢 No Developer Tokens
 17 | - 🟢 No Client IDs
 18 | - 🟢 No authentication hassles
 19 | 
 20 | Instead, it uses free **[GAQL.app](https://gaql.app)**, which securely handles authentication and query execution behind the scenes.
 21 | 
 22 | This makes it ideal for users who want to get up and running **within minutes**.
 23 | 
 24 | ---
 25 | 
 26 | ## 🛠️ Setup Guide
 27 | 
 28 | ### 1. Install Node.js
 29 | 
 30 | Ensure you have Node.js installed on your system.
 31 | 
 32 | - On Windows, open **Command Prompt** (search for "cmd" in the Start menu) and run:
 33 | 
 34 | ```sh
 35 | winget install nodejs
 36 | ```
 37 | 
 38 | - On macOS, download and install Node.js from [https://nodejs.org](https://nodejs.org). If you need help, please refer to the screenshots at the end of this document. 
 39 | 
 40 | ### 2. Get Your GPT Token
 41 | 
 42 | 1. Go to [https://gaql.app](https://gaql.app)
 43 | 2. Log in using your Google account to authorize Google Ads access.
 44 | 3. Click the **Copy GPT Token** button in the top-right corner.
 45 | 
 46 | ### 3. Configure Your AI (Claude)
 47 | 
 48 | The application is configured via a JSON file named `claude_desktop_config.json`.
 49 | 
 50 | 1. Open the **Claude** desktop application.
 51 | 
 52 | 2. Press:
 53 | 
 54 |    - `CTRL + ,` (Control key and comma) on Windows/Linux
 55 |    - `Command + ,` (Command key and comma) on macOS
 56 | 
 57 | 3. In the left sidebar, click **Developer**.
 58 | 
 59 | 4. Open  **Edit config** and open `claude_desktop_config.json` for editing.
 60 | 
 61 | 5. Paste the following JSON into your configuration file:
 62 | 
 63 |    ```json
 64 |    {
 65 |      "mcpServers": {
 66 |        "gads": {
 67 |          "command": "npx",
 68 |          "args": [
 69 |            "-y",
 70 |            "@trueclicks/google-ads-mcp-js",
 71 |            "--token=YOUR_GPT_TOKEN_HERE"
 72 |          ]
 73 |        }
 74 |      }
 75 |    }
 76 |    ```
 77 | 
 78 |    > **Important:** Replace `YOUR_GPT_TOKEN_HERE` with the token copied from GAQL.app.
 79 | 
 80 | 6. Exit Claude completely:
 81 | 
 82 |    - On Windows/Linux: **Hamburger menu > File > Exit**
 83 |    - On macOS: Right-click the Claude icon in the top-right panel and click **Quit**
 84 | 
 85 | 7. Restart Claude.
 86 | 
 87 | You’re now ready to use Claude AI to query your Google Ads accounts.
 88 | 
 89 | ---
 90 | 
 91 | ## 💬 Example Prompts
 92 | 
 93 | - `List my Google Ads accounts`
 94 | - `What is the cost for account XYZ in the past 30 days?`
 95 | - `What are the top 5 setting recommendations for my campaigns?`
 96 | 
 97 | ---
 98 | 
 99 | ## 🆚 Comparison with Other Google Ads MCPs
100 | 
101 | | Feature                    | Google Ads MCP (Node.js) | Other MCPs (Python/etc.)  |
102 | | -------------------------- | ------------------------ | ------------------------- |
103 | | Google Cloud project setup | 🟢 No                    | 🔧 Yes                    |
104 | | OAuth Client ID required   | 🟢 No                    | 🔧 Yes                    |
105 | | Developer Token needed     | 🟢 No                    | 🔧 Yes                    |
106 | | Google Ads API familiarity | 🟢 No                    | ⚠️ Yes                    |
107 | | Setup complexity           | 🎉 Very low              | 🟠 Moderate to high       |
108 | | Backend service            | ☁️ Hosted via GAQL.app   | 🔧 Direct API integration |
109 | 
110 | ---
111 | 
112 | ## 📸 Setup Screenshots (macOS)
113 | 
114 | 1. **Node.js download:** Screenshot of downloading Node.js from the official site.
115 | ![Node.js download](https://github.com/TrueClicks/google-ads-mcp-js/blob/main/assets/images/osx-1.png)
116 | 
117 | 2. **Claude Developer section:** Screenshot of accessing the Developer section in Claude.
118 | ![Claude developer section](https://github.com/TrueClicks/google-ads-mcp-js/blob/main/assets/images/osx-2.png)
119 | 
120 | 3. **Open configuration file for editing:** Screenshot showing how to open `claude_desktop_config.json`.
121 | ![Claude config file](https://github.com/TrueClicks/google-ads-mcp-js/blob/main/assets/images/osx-3.png)
122 | 
123 | 4. **Editing configuration JSON:** Screenshot of the JSON configuration being edited.
124 | ![Content in claude_desktop_config.json](https://github.com/TrueClicks/google-ads-mcp-js/blob/main/assets/images/osx-4.png)
125 | 
126 | 5. **Restarting Claude:** Screenshot showing how to quit and restart Claude from the top-right corner.
127 | ![How to hard restart Claude](https://github.com/TrueClicks/google-ads-mcp-js/blob/main/assets/images/osx-5.png)
128 | 
129 | 6. **Example prompt:** Screenshot showing an example prompt using Claude with Google Ads integration.
130 | ![Example prompting Google Ads with Claude](https://github.com/TrueClicks/google-ads-mcp-js/blob/main/assets/images/osx-6.png)
131 | 
132 | ---
133 | 
134 | For issues or questions, please contact [[email protected]](mailto:[email protected]).
135 | 
136 | ---
137 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |     "compilerOptions": {
 3 |       "target": "ES2022",
 4 |       "module": "Node16",
 5 |       "moduleResolution": "Node16",
 6 |       "outDir": "./build",
 7 |       "rootDir": "./src",
 8 |       "strict": true,
 9 |       "esModuleInterop": true,
10 |       "skipLibCheck": true,
11 |       "forceConsistentCasingInFileNames": true
12 |     },
13 |     "include": ["src/**/*"],
14 |     "exclude": ["node_modules"]
15 |   }
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@trueclicks/google-ads-mcp-js",
 3 |   "version": "0.3.7",
 4 |   "description": "Gogle Ads MCP by TrueClicks enables your GPT (like Claude) to securely access and query your Google Ads account data via GAQL.app.",
 5 |   "license": "MIT",
 6 |   "author": "TrueClicks",
 7 |   "repository": {
 8 |     "type": "git",
 9 |     "url": "https://github.com/TrueClicks/google-ads-mcp-js.git"
10 |   },
11 |   "homepage": "https://www.trueclicks.com",
12 |   "bugs": {
13 |     "url": "https://github.com/TrueClicks/google-ads-mcp-js"
14 |   },
15 |   "type": "module",
16 |   "bin": {
17 |     "google-ads-mcp-js": "build/index.js"
18 |   },
19 |   "files": [
20 |     "build"
21 |   ],
22 |   "scripts": {
23 |     "build": "npx tsc && npx shx chmod +x build/*.js",
24 |     "prepare": "npm run build",
25 |     "watch": "npx tsc --watch"
26 |   },
27 |   "dependencies": {
28 |     "@modelcontextprotocol/sdk": "^1.8.0",
29 |     "zod": "^3.24.2"
30 |   },
31 |   "devDependencies": {
32 |     "@types/node": "^22.14.0",
33 |     "typescript": "^5.8.2",
34 |     "shx": "^0.4.0"
35 |   },
36 |   "main": "index.js"
37 | }
```

--------------------------------------------------------------------------------
/src/client/gaql-client.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // src/client/gaql-client.ts
 2 | 
 3 | const API_BASE = "https://api.gaql.app";
 4 | const USER_AGENT = "qaql-tool-client/1.0";
 5 | 
 6 | export interface GaqlQueryRequest {
 7 |     query: string;
 8 |     customerId: number;
 9 |     loginCustomerId: number;
10 |     reportAggregation: string;
11 | }
12 | 
13 | export class GaqlClient {
14 |     private token: string;
15 | 
16 |     constructor(token: string) {
17 |         if (!token) {
18 |             throw new Error("GAQL token is required");
19 |         }
20 | 
21 |         this.token = token;
22 |     }
23 | 
24 |     async getAccounts(): Promise<any> {
25 |         const url = `${API_BASE}/api/gpt/google-ads/get-accounts?gptToken=${this.token}`;
26 |         
27 |         const response = await fetch(url, {
28 |             headers: {
29 |                 "User-Agent": USER_AGENT
30 |             }
31 |         });
32 | 
33 |         if (!response.ok) {
34 |             const errorText = await response.text();
35 |             throw new Error(`GAQL error ${response.status}: ${errorText}`);
36 |         }
37 | 
38 |         return response.json();
39 |     }
40 | 
41 |     async executeGaqlQuery(query: GaqlQueryRequest): Promise<string> {
42 |         const url = `${API_BASE}/api/gpt/google-ads/execute-query?gptToken=${this.token}`;
43 |         
44 |         const response = await fetch(url, {
45 |             method: "POST",
46 |             headers: {
47 |                 "Content-Type": "application/json",
48 |                 "User-Agent": USER_AGENT
49 |             },
50 |             body: JSON.stringify(query)
51 |         });
52 | 
53 |         if (!response.ok) {
54 |             const errorText = await response.text();
55 |             throw new Error(`GAQL error ${response.status}: ${errorText}`);
56 |         }
57 | 
58 |         const json = await response.json();
59 |         return JSON.stringify(json, null, 2); // pretty print
60 |     }
61 | }
62 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | #!/usr/bin/env node
 2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
 3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
 4 | import { z } from "zod";
 5 | import { GaqlClient, GaqlQueryRequest } from "./client/gaql-client.js";
 6 | 
 7 | // CLI token parsing
 8 | console.error("Process argv:", process.argv);
 9 | const tokenArg = process.argv.find(arg => arg.startsWith("--token="));
10 | const token = tokenArg?.substring("--token=".length);
11 | 
12 | if (!token) {
13 |     console.error("❌ Error: Missing --token argument.");
14 |     process.exit(1);
15 | } else {
16 |     console.error("✅ Parsed token.");
17 | }
18 | 
19 | const gaqlClient = new GaqlClient(token);
20 | 
21 | const server = new McpServer({
22 |     name: "Google Ads MCP",
23 |     version: "1.0.0"
24 | });
25 | 
26 | // Tool: get-accounts
27 | server.tool(
28 |     "get-accounts",
29 |     "Gets Google Ads accounts.",
30 |     async () => {
31 |         console.error("🛠 get-accounts called");
32 |         try {
33 |             const accounts = await gaqlClient.getAccounts();
34 |             return {
35 |                 content: [{
36 |                     type: "text",
37 |                     text: `Accounts:\n${JSON.stringify(accounts, null, 2)}`
38 |                 }]
39 |             };
40 |         } catch (err: any) {
41 |             console.error("❌ Error in get-accounts:", err);
42 | 
43 |             return {
44 |                 content: [{
45 |                     type: "text",
46 |                     text: `Failed to fetch accounts: ${err.message}`
47 |                 }]
48 |             };
49 |         }
50 |     }
51 | );
52 | 
53 | // Tool: execute-gaql-query
54 | server.tool(
55 |     "execute-gaql-query",
56 |     "Executes a GAQL query and returns the result as a formatted JSON string.",
57 |     {
58 |         query: z.string().describe("GAQL query"),
59 |         customerId: z.number().describe("Customer ID"),
60 |         loginCustomerId: z.number().describe("Login Customer ID"),
61 |         reportAggregation: z.string().describe("Report aggregation (for Microsoft Advertising only)")
62 |     },
63 |     async (args: GaqlQueryRequest) => {
64 |         console.error("🛠 execute-gaql-query called with:", args);
65 |         try {
66 |             const result = await gaqlClient.executeGaqlQuery(args);
67 | 
68 |             return {
69 |                 content: [{
70 |                     type: "text",
71 |                     text: `Query result:\n${result}`
72 |                 }]
73 |             };
74 |         } catch (err: any) {
75 |             console.error("❌ Error in execute-gaql-query:", err);
76 | 
77 |             return {
78 |                 content: [{
79 |                     type: "text",
80 |                     text: `Failed to execute query: ${err.message}`
81 |                 }]
82 |             };
83 |         }
84 |     }
85 | );
86 | 
87 | // Start server
88 | async function main() {
89 |     console.error("🚀 Connecting to MCP server...");
90 |     const transport = new StdioServerTransport();
91 |     await server.connect(transport);
92 |     console.error("✅ MCP server is running.");
93 | }
94 | 
95 | main().catch((err) => {
96 |     console.error("🔥 Fatal error in main():", err);
97 |     process.exit(1);
98 | });
99 | 
```