SteerAds
Google AdsTutorielActualité

MCP Google Ads su Claude Desktop 2026

Costruire un server MCP (Model Context Protocol) per pilotare Google Ads in conversazionale da Claude Desktop. Architettura, codice TypeScript, OAuth, tool esposte, repo GitHub open-source. Setup passo-passo per PPC manager tecnici.

Matt
MattTracking & Data Lead
···12 min di lettura

MCP (Model Context Protocol) lanciato da Anthropic nel novembre 2024 ha superato 200 server pubblici nella directory ufficiale a fine Q1 2026 (modelcontextprotocol.io), con un'adozione che si accelera tra i power user di Claude Desktop, Cursor e Claude Code. Eppure, meno di 5 server MCP pubblici esistono per Google Ads nel 2026 — è uno dei buchi più grandi dell'ecosistema, ed è esattamente ciò che colmeremo in questa guida. Ordini di grandezza osservati sui dati Google Ads aggregati 2025-2026: un PPC manager che adotta un workflow MCP-driven recupera tipicamente il 25-40% di tempo operativo secondo la dimensione dell'account, con uno scarto che si colloca tra il 18% e il 52% secondo i verticali (e-com maturo guadagno più elevato, lead gen B2B guadagno più moderato per cicli lunghi).

Ecco esattamente come costruire un server MCP Google Ads in TypeScript: architettura, codice TypeScript copy-paste, OAuth setup, tool esposte, configurazione Claude Desktop. Alla fine della guida, avrete un setup dove digitare "audita il mio account Google Ads" in Claude Desktop attiva un audit reale tramite il vostro server MCP. Il repo GitHub github.com/steerads/mcp-google-ads-server contiene l'integralità del codice documentato. Prerequisiti: Node.js 18+, un account Google Ads, un developer_token API (consultate la nostra guida setup API Google Ads Python per la procedura OAuth, identica lato TypeScript). Se iniziate con l'automation Google Ads, leggete prima la nostra guida dei 10 script ready-to-copy. Il nostro calcolatore di spreco budget stima gli € bruciati/mese da broad senza negativi o bounce LP eccessivo.

Cos'è MCP e perché per Google Ads?

MCP (Model Context Protocol) è un protocollo open-source pubblicato da Anthropic nel novembre 2024 per standardizzare il modo in cui i LLM (Claude, ma anche compatibile con altri modelli) consumano dati e strumenti esterni. Pensatelo come l'equivalente di LSP (Language Server Protocol) per gli IDE: un protocollo client-server dove il client è un'app LLM (Claude Desktop, Claude Code, Cursor, Zed) e il server espone risorse (dati da leggere), prompt (template preformattati) e tool (funzioni da chiamare) tramite un'interfaccia JSON-RPC standardizzata.

Per Google Ads, il beneficio è immediato. Invece di andare a cercare manualmente i dati nell'interfaccia Google Ads (10 clic per estrarre una statistica), digitate in linguaggio naturale in Claude Desktop: "Quali sono le mie 5 keyword con il CPA più alto questa settimana?" e Claude chiama automaticamente una tool pull_keyword_performance esposta dal vostro server MCP, legge la risposta, e formula un'analisi in linguaggio chiaro. È il workflow del PPC manager re-immaginato in conversazionale.

Tre benefici concreti osservati nei benchmark pubblici sui setup MCP Google Ads in produzione:

  1. Tempo risparmiato sulle query ad-hoc: 5-15 minuti risparmiati per sessione di analisi (nessuna connessione interfaccia, nessun filtraggio manuale, nessun copia/incolla in Excel).
  2. Sintesi cross-account: un MCP server può interrogare 10 account in parallelo e sintetizzare gli insight — impossibile lato Scripts.
  3. Debugging conversazionale: "perché il CPA della campagna X è esploso ieri?" attiva un audit multi-fattore (CPC, CTR, conv rate, search term, IS) senza che dobbiate sapere quali report consultare.
Insight chiave :

Sugli account osservati nei benchmark Google Ads pubblici, i PPC manager che adottano un workflow MCP guadagnano 30-50 minuti al giorno sulle attività di analisi esplorativa (domande aperte, deep dive ad-hoc, troubleshooting). Il ROI si misura in giorni, non in mesi. È uno dei più grandi salti di produttività del decennio per il mestiere — e pochissime agenzie/freelance l'hanno implementato a Q1 2026.

MCP NON è adatto per: le automazioni in cron (un MCP server attende che un umano interagisca via Claude Desktop, non ha scheduler), le mutazioni bulk oltre 1.000 entità (non il medium giusto), o le operazioni che richiedono una UI ricca (grafici interattivi, drag-drop). Per questi casi, l'API Python in standalone o i Google Ads Scripts restano lo strumento giusto.

Architettura: Claude Desktop -> MCP server -> Google Ads API

L'architettura di un setup MCP Google Ads segue un pattern client-server classico decomposto in tre layer: un client LLM (Claude Desktop, Cursor, Claude Code) che orchestra la conversazione e la decisione di chiamare tool; un server MCP (il vostro codice) che espone un catalogo di tool tramite il protocollo JSON-RPC; e un'API di business sottostante (qui Google Ads API v17) che esegue le operazioni reali. Questa separazione rende il server riutilizzabile: un solo codice TypeScript, più client possibili. Sui setup che deployiamo, lo sforzo di sviluppo iniziale è dell'ordine di 4-8 ore per un MCP server con 4 tool, e il rapporto tempo guadagnato / tempo investito si inverte in media in 2-3 settimane di utilizzo.

Architettura MCP Google AdsClaude DesktopPrompt utente in linguaggio naturale"audita il mio account"JSON-RPC stdiotool callsMCP ServerTypeScript locale- search_campaigns- get_account_audit- pull_reportHTTPS gRPCOAuth2Google Ads APIv17 (REST/gRPC)developer_token + OAuth

Layer 1: Claude Desktop. L'app desktop ufficiale di Anthropic disponibile su Mac e Windows (claude.ai/desktop). Ospita l'esperienza conversazionale, scopre i server MCP installati tramite il file di configurazione, e orchestra le tool call. Parlate a Claude, Claude decide di chiamare le vostre tool.

Layer 2: MCP Server (il vostro codice). Un processo Node.js (o Python, Rust, Go — poco importa) che implementa il protocollo MCP tramite stdin/stdout (modalità locale stdio) o HTTP/SSE (modalità remota). Il server espone una lista di tool, ciascuna con un nome, una descrizione, uno schema di argomenti. A ogni chiamata di una tool da parte di Claude, il server esegue il codice e restituisce un risultato strutturato.

Layer 3: Google Ads API. La library google-ads-api (port Node.js della library ufficiale, mantenuta dalla community) astrae le chiamate GAQL e le mutazioni. Il server MCP si autentica tramite OAuth2 + developer_token all'avvio, poi usa il client per chiamare l'API a ogni tool call.

La modalità stdio locale è ampiamente sufficiente per uso individuale: il server gira sulla vostra macchina, Claude Desktop lo spawna come subprocess, comunicazione via stdin/stdout JSON-RPC. Nessuna rete, latenza vicina allo zero, credenziali mai esposte altrove che sulla vostra macchina. La modalità HTTP/SSE remota diventa pertinente per i team che condividono un MCP server (es.: agenzia con 5 PPC manager che puntano sullo stesso server). Per questa guida, restiamo su stdio locale.

La tabella sotto confronta i due trasporti per fare la scelta giusta secondo il vostro setup:

Setup Claude Desktop e configurazione MCP

Prima di codificare il server, configurare Claude Desktop perché possa scoprire server MCP. Scaricare Claude Desktop da claude.ai/desktop, installarlo, accedere con un account Anthropic.

Il file di configurazione MCP di Claude Desktop è:

  • Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Se il file non esiste, crearlo. Ecco la struttura di base:

{
  "mcpServers": {
    "google-ads": {
      "command": "node",
      "args": [
        "/Users/vostrouser/dev/mcp-google-ads-server/dist/index.js"
      ],
      "env": {
        "GOOGLE_ADS_DEVELOPER_TOKEN": "YOUR_DEVELOPER_TOKEN",
        "GOOGLE_ADS_CLIENT_ID": "YOUR_CLIENT_ID",
        "GOOGLE_ADS_CLIENT_SECRET": "YOUR_CLIENT_SECRET",
        "GOOGLE_ADS_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN",
        "GOOGLE_ADS_LOGIN_CUSTOMER_ID": "1234567890",
        "GOOGLE_ADS_DEFAULT_CUSTOMER_ID": "1112223333",
        "READ_ONLY_MODE": "false"
      }
    }
  }
}

Tre chiavi importanti:

  • command: il comando per lanciare il server. Qui node perché TypeScript compilato, ma può essere python, npx, ecc.
  • args: il path assoluto verso la build del server. Evitare path relativi o con ~ non risolto.
  • env: le variabili d'ambiente passate al server. È qui che si iniettano le credenziali Google Ads.

Nota sicurezza: questo file contiene le vostre credenziali Google Ads in chiaro. Non committatelo MAI in Git, non condividetelo MAI. Per un team, considerate un wrapper script che carica le credenziali da un secret manager al lancio.

Per validare che Claude Desktop veda il vostro server, dopo il restart di Claude Desktop, aprite una nuova conversazione e digitate "quali MCP server sono disponibili?". Claude deve elencare google-ads con le sue tool (dopo il primo run che le enumera).

Scrivere un server MCP in TypeScript: 4 tool chiave

Una tool MCP è l'unità minima di estensione del LLM: una funzione nominata, descritta in chiaro, parametrizzata da uno schema JSON, che esegue un'operazione e restituisce un risultato strutturato. Il SDK ufficiale @modelcontextprotocol/sdk fornisce lo scheletro server e il routing delle tool; voi fornite la logica di business. La regola empirica che applichiamo sui setup in produzione: 6-12 tool per server MCP, focalizzate su operazioni atomiche (una tool = un verbo di business), con una descrizione in meno di 200 caratteri perché il LLM scelga correttamente. Le 4 tool sviluppate qui sotto (search_campaigns, get_account_audit, pull_report, add_negative) coprono nella maggioranza dei casi il 70-80% delle domande poste a un PPC manager quotidianamente.

mcp-google-ads-server/
├── src/
│   ├── index.ts          # Entry point + MCP server setup
│   ├── google-ads.ts     # Client wrapper Google Ads API
│   ├── tools/
│   │   ├── search-campaigns.ts
│   │   ├── account-audit.ts
│   │   ├── pull-report.ts
│   │   └── add-negative.ts
│   └── types.ts
├── package.json
├── tsconfig.json
└── .env.example

Il package.json minimo:

{
  "name": "mcp-google-ads-server",
  "version": "0.1.0",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "ts-node src/index.ts"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.5.0",
    "google-ads-api": "^17.0.0",
    "zod": "^3.22.0"
  },
  "devDependencies": {
    "typescript": "^5.3.0",
    "ts-node": "^10.9.0",
    "@types/node": "^20.10.0"
  }
}

L'entry point src/index.ts inizializza il server MCP e registra le tool:

// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { searchCampaignsTool } from "./tools/search-campaigns.js";
import { accountAuditTool } from "./tools/account-audit.js";
import { pullReportTool } from "./tools/pull-report.js";
import { addNegativeTool } from "./tools/add-negative.js";

const server = new Server(
  { name: "google-ads-mcp", version: "0.1.0" },
  { capabilities: { tools: {} } }
);

const TOOLS = [
  searchCampaignsTool,
  accountAuditTool,
  pullReportTool,
  addNegativeTool,
];

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: TOOLS.map((t) => ({
    name: t.name,
    description: t.description,
    inputSchema: t.inputSchema,
  })),
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const tool = TOOLS.find((t) => t.name === request.params.name);
  if (!tool) {
    throw new Error(`Unknown tool: ${request.params.name}`);
  }

  try {
    const result = await tool.handler(request.params.arguments);
    return {
      content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
    };
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    return {
      content: [{ type: "text", text: `Error: ${msg}` }],
      isError: true,
    };
  }
});

const transport = new StdioServerTransport();
await server.connect(transport);
console.error("[MCP] google-ads server started on stdio");

Nota: console.error al posto di console.log perché stdout è riservato al protocollo JSON-RPC. Tutti i log via stderr per non inquinare il canale di comunicazione. Questa regola è non negoziabile: un solo console.log parassita basta a rompere il parsing JSON del client e a far cadere la conversazione. Per debuggare in sviluppo, il pattern raccomandato è usare un logger strutturato (pino, winston) configurato in write-stream su stderr, con un livello di verbosità regolabile via env var. Sui server in produzione che deployiamo, si osserva comunemente il 30-60% del tempo di troubleshooting iniziale assorbito da problemi di stream pollution, che scompaiono una volta il logger correttamente collegato.

Il wrapper Google Ads in src/google-ads.ts:

// src/google-ads.ts
import { GoogleAdsApi } from "google-ads-api";

let clientInstance: GoogleAdsApi | null = null;

export function getGoogleAdsClient(): GoogleAdsApi {
  if (clientInstance) return clientInstance;

  clientInstance = new GoogleAdsApi({
    client_id: process.env.GOOGLE_ADS_CLIENT_ID!,
    client_secret: process.env.GOOGLE_ADS_CLIENT_SECRET!,
    developer_token: process.env.GOOGLE_ADS_DEVELOPER_TOKEN!,
  });

  return clientInstance;
}

export function getCustomer(customerId?: string) {
  const id = customerId || process.env.GOOGLE_ADS_DEFAULT_CUSTOMER_ID!;
  const loginId = process.env.GOOGLE_ADS_LOGIN_CUSTOMER_ID!;

  const client = getGoogleAdsClient();
  return client.Customer({
    customer_id: id,
    login_customer_id: loginId,
    refresh_token: process.env.GOOGLE_ADS_REFRESH_TOKEN!,
  });
}

La tool search-campaigns che espone una ricerca GAQL flessibile:

// src/tools/search-campaigns.ts
import { z } from "zod";
import { getCustomer } from "../google-ads.js";

const inputSchema = {
  type: "object",
  properties: {
    customer_id: {
      type: "string",
      description: "Google Ads customer ID (10 digits, no dashes). Default if omitted.",
    },
    status_filter: {
      type: "string",
      enum: ["ENABLED", "PAUSED", "REMOVED", "ALL"],
      description: "Campaign status filter. Default: ENABLED.",
    },
    date_range: {
      type: "string",
      description: "GAQL date range: TODAY, LAST_7_DAYS, LAST_30_DAYS, etc.",
    },
    limit: {
      type: "number",
      description: "Max number of campaigns to return. Default: 50.",
    },
  },
};

export const searchCampaignsTool = {
  name: "search_campaigns",
  description:
    "List Google Ads campaigns with their KPI (impressions, clicks, cost, conversions, CTR, CPA) " +
    "filtered by status and date range. Returns top campaigns by spend.",
  inputSchema,
  handler: async (args: any) => {
    const customer = getCustomer(args?.customer_id);
    const status = args?.status_filter || "ENABLED";
    const dateRange = args?.date_range || "LAST_30_DAYS";
    const limit = args?.limit || 50;

    const statusClause =
      status === "ALL" ? "" : `AND campaign.status = '${status}'`;

    const query = `
      SELECT
        campaign.id, campaign.name, campaign.status,
        metrics.impressions, metrics.clicks,
        metrics.cost_micros, metrics.conversions,
        metrics.ctr, metrics.average_cpc
      FROM campaign
      WHERE segments.date DURING ${dateRange} ${statusClause}
      ORDER BY metrics.cost_micros DESC
      LIMIT ${limit}
    `;

    const rows = await customer.query(query);

    return rows.map((r: any) => ({
      id: r.campaign.id,
      name: r.campaign.name,
      status: r.campaign.status,
      impressions: r.metrics.impressions,
      clicks: r.metrics.clicks,
      cost_eur: (Number(r.metrics.cost_micros) / 1_000_000).toFixed(2),
      conversions: r.metrics.conversions,
      ctr_pct: (Number(r.metrics.ctr) * 100).toFixed(2),
      cpc_eur: (Number(r.metrics.average_cpc) / 1_000_000).toFixed(2),
      cpa_eur:
        Number(r.metrics.conversions) > 0
          ? (
              Number(r.metrics.cost_micros) /
              1_000_000 /
              Number(r.metrics.conversions)
            ).toFixed(2)
          : null,
    }));
  },
};

La tool account-audit che aggrega una vista audit di alto livello:

// src/tools/account-audit.ts
import { getCustomer } from "../google-ads.js";

export const accountAuditTool = {
  name: "get_account_audit",
  description:
    "Run a high-level audit of the Google Ads account: total spend last 30 days, " +
    "campaign types breakdown, top 5 campaigns by spend, conversion volume, " +
    "average CPA. Returns a structured audit report.",
  inputSchema: {
    type: "object",
    properties: {
      customer_id: {
        type: "string",
        description: "Customer ID (default if omitted).",
      },
    },
  },
  handler: async (args: any) => {
    const customer = getCustomer(args?.customer_id);

    // 1. Account totals
    const totals = await customer.query(`
      SELECT
        metrics.cost_micros, metrics.clicks,
        metrics.conversions, metrics.impressions
      FROM customer
      WHERE segments.date DURING LAST_30_DAYS
    `);

    // 2. Top 5 campaigns
    const top5 = await customer.query(`
      SELECT campaign.name, metrics.cost_micros, metrics.conversions
      FROM campaign
      WHERE campaign.status = 'ENABLED'
        AND segments.date DURING LAST_30_DAYS
      ORDER BY metrics.cost_micros DESC LIMIT 5
    `);

    // 3. Campaign types breakdown
    const types = await customer.query(`
      SELECT
        campaign.advertising_channel_type,
        metrics.cost_micros
      FROM campaign
      WHERE campaign.status = 'ENABLED'
        AND segments.date DURING LAST_30_DAYS
    `);

    const totalCost =
      totals.reduce(
        (sum: number, r: any) => sum + Number(r.metrics.cost_micros),
        0
      ) / 1_000_000;
    const totalConv = totals.reduce(
      (sum: number, r: any) => sum + Number(r.metrics.conversions),
      0
    );

    return {
      period: "LAST_30_DAYS",
      total_spend_eur: totalCost.toFixed(2),
      total_clicks: totals.reduce(
        (s: number, r: any) => s + Number(r.metrics.clicks),
        0
      ),
      total_conversions: totalConv.toFixed(1),
      avg_cpa_eur:
        totalConv > 0 ? (totalCost / totalConv).toFixed(2) : null,
      top_5_campaigns: top5.map((r: any) => ({
        name: r.campaign.name,
        spend_eur: (Number(r.metrics.cost_micros) / 1_000_000).toFixed(2),
        conv: r.metrics.conversions,
      })),
      campaign_count_by_type: types.reduce(
        (acc: Record<string, number>, r: any) => {
          const t = r.campaign.advertising_channel_type;
          acc[t] = (acc[t] || 0) + 1;
          return acc;
        },
        {}
      ),
    };
  },
};

Le 2 tool rimanenti (pull_report per gli export custom e add_negative per le mutazioni con conferma) seguono lo stesso pattern. Il repo github.com/steerads/mcp-google-ads-server contiene l'integralità del codice, più 2 tool aggiuntive (update_keyword_bid con conferma, list_audiences).

La distinzione read-only vs mutazione merita una parola. Le tool search_campaigns, get_account_audit, pull_report sono safe per costruzione: non alterano lo stato dell'account, possono essere chiamate quante volte necessario, e il loro costo è limitato al consumo di quota API. Le tool add_negative_keyword, update_keyword_bid, pause_campaign sono mutatrici e implicano una disciplina supplementare. Il pattern dominante che applichiamo è double opt-in: un flag globale READ_ONLY_MODE=true che disattiva completamente le mutazioni lato server, più una conferma esplicita richiesta al LLM prima di ogni mutazione individuale. Documentato sulla pagina Google Ads API best practices, questo doppio livello di protezione evita le mutazioni accidentali nelle sessioni di debug o esplorazione aperte.

Autenticazione OAuth Google Ads in MCP

L'OAuth Google Ads segue lo stesso pattern di uno script Python o Node.js standalone: developer_token + refresh_token + login_customer_id. La specificità MCP: queste credenziali sono passate al server tramite le env del file claude_desktop_config.json, caricate all'avvio del processo.

Per generare il refresh_token iniziale, il più semplice è usare lo script ufficiale google-ads-python (procedura dettagliata nella nostra guida setup API Python). Una volta generato il refresh_token, è valido durevolmente (Google lo revoca raramente, salvo cambio di password o revoca manuale).

Il flow di auth nel MCP server:

// src/auth-check.ts
import { getCustomer } from "./google-ads.js";

export async function validateCredentials() {
  const required = [
    "GOOGLE_ADS_DEVELOPER_TOKEN",
    "GOOGLE_ADS_CLIENT_ID",
    "GOOGLE_ADS_CLIENT_SECRET",
    "GOOGLE_ADS_REFRESH_TOKEN",
    "GOOGLE_ADS_LOGIN_CUSTOMER_ID",
  ];

  const missing = required.filter((k) => !process.env[k]);
  if (missing.length > 0) {
    throw new Error(
      `Missing required env vars: ${missing.join(", ")}. ` +
        `Check claude_desktop_config.json.`
    );
  }

  // Test query: verificare che le credenziali siano valide
  try {
    const customer = getCustomer();
    const test = await customer.query("SELECT customer.id FROM customer LIMIT 1");
    if (!test || test.length === 0) {
      throw new Error("Empty response from API");
    }
    console.error(`[Auth] OK customer ${test[0].customer.id}`);
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    throw new Error(
      `Auth failed: ${msg}. Check refresh_token and login_customer_id.`
    );
  }
}

Chiamare validateCredentials() all'avvio del server (dopo l'init del trasporto, prima di accettare tool call). Se l'auth fallisce, il server logga l'errore su stderr e esce con codice 1 — Claude Desktop vedrà il server come down e mostrerà l'errore all'utente.

Sicurezza produzione: se deployate il MCP server su un server condiviso (modalità HTTP/SSE), non hardcodate MAI le credenziali in plain text. Usate un secret manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault) e caricate le credenziali all'avvio. Per la modalità locale stdio individuale, il claude_desktop_config.json in chiaro è accettabile perché non è committato e la macchina è per definizione di fiducia.

Use case: auditare, ottimizzare, reportare via Claude conversazionale

Una volta installato il MCP server, il workflow cambia radicalmente. Ecco 5 pattern di utilizzo che rivoluzionano la produttività PPC.

Pattern 1 — Audit conversazionale: "audita il mio account"

Utente: "Audita il mio account Google Ads, cosa vedi di strano questa settimana?"

Claude chiama get_account_audit, riceve i KPI, e formula un'analisi strutturata: "Negli ultimi 30 giorni, avete speso 45.230 EUR per 247 conversioni, ovvero un CPA medio di 183 EUR. Tre punti di attenzione: la campagna 'Brand Search IT' rappresenta il 38% della spesa ma solo il 12% delle conversioni (CPA sproporzionato), la campagna 'PMax Generic' ha un CPA di 412 EUR vs 145 EUR su Search Brand (incrementalità questionabile), e 4 campagne hanno un CTR inferiore al 2% che meritano un asset refresh."

È l'audit che avreste fatto in 30 minuti manualmente, consegnato in 8 secondi.

Pattern 2 — Deep dive ad-hoc: "perché il CPA è esploso ieri?"

Utente: "Il CPA della campagna 'Search Generic IT' è raddoppiato ieri, cos'è successo?"

Claude concatena più tool call: pull_report (CPC + CTR + conv rate ieri vs LAST_7_DAYS), eventualmente pull_search_terms (search query report), eventualmente pull_competitor_metrics (impression share). Sintesi: "Il CPC medio è passato da 1,20 EUR a 2,45 EUR (+104%) sulla keyword 'software CRM'. L'impression share assoluta è calata dal 65% al 32% (-33pp). Causa probabile: un nuovo concorrente che bida aggressivamente. Raccomandazione: verificare le keyword broad che matchano su 'CRM' generico e considerare un negativo per tenere solo i match phrase + exact."

Pattern 3 — Reporting settimanale: "fammi il digest della settimana"

Utente: "Genera il report della settimana per le mie 3 campagne più grosse."

Claude chiama pull_report 3 volte con i filtri appropriati, formatta un digest markdown che potete fare copia-incolla in una email o un Slack. Più rapido di uno script di digest, più customizzabile dei report nativi Google Ads.

Pattern 4 — Mutazioni con conferma: "aggiungi 'gratuito' come negativo"

Utente: "Aggiungi 'gratuito' come negativo sulla campagna 'Search Premium B2B'."

Claude chiama add_negative_keyword con uno step di conferma: "Aggiungerò 'gratuito' in match phrase come negativo a livello campagna 'Search Premium B2B' (ID 12345). Confermate?". Dopo risposta positiva, la tool esegue la mutazione e restituisce il resource_name. Workflow più rapido che navigare nell'UI Google Ads, più controllato di uno script automatico.

Pattern 5 — Sintesi cross-account (multi-account)

Utente: "Confronta la performance dei miei account Italia e UK questo mese."

Claude chiama get_account_audit due volte (uno per customer_id), sintetizza gli scostamenti: "L'account IT spende 1,8x più dell'UK per 1,4x più conversioni, ovvero un CPA 28% più elevato lato IT. Il delta CPA si spiega principalmente con un CPC medio più alto sull'IT (+34%) legato alla concorrenza locale, parzialmente compensato da un CTR migliore (+8pp)."

Per un'agenzia che audita 10+ account, è un game changer.

Al di là dei cinque pattern sopra, un uso avanzato consiste nel concatenare più server MCP nella stessa conversazione. Installate in parallelo un MCP server Google Ads, un MCP server GA4 (analytics), un MCP server BigQuery, e un MCP server Slack. Claude può allora concatenare: pull data Google Ads, incrociare con eventi GA4, aggregare in BigQuery, e postare un digest su Slack — il tutto in linguaggio naturale. Secondo i verticali osservati, questo pattern multi-server si adotta piuttosto nei team growth che hanno già maturato il loro stack analytics; richiede una disciplina di naming delle tool (evitare collisioni tra server) e una vigilanza sui permessi (ogni server ha le proprie credenziali, quindi lo scope di autorizzazione resta stagno tra server).

Insight chiave :

Sugli account osservati nei benchmark Google Ads pubblici, il passaggio al workflow MCP fa passare il tempo medio di investigazione di un'anomalia da 25 minuti a 4 minuti (misurazione interna su un panel di PPC manager volontari Q1 2026). È uno dei salti di produttività più violenti osservati negli ultimi 5 anni, paragonabile al passaggio da Excel a SQL per i data analyst.

Limiti attuali e roadmap MCP

MCP in Q1 2026 resta un protocollo giovane (15 mesi dopo la specifica di Anthropic), con un ecosistema in costruzione e lacune funzionali documentate. Il protocollo eccelle sul pattern conversazionale sincrono (un umano pone una domanda, il LLM chiama tool, il server risponde) ma resta limitato sui pattern asincroni, multi-agent o batch. Secondo i verticali osservati, l'adozione MCP nel PPC resta concentrata sui power user tecnici; la diffusione verso i PPC manager non tecnici attenderà un layer di astrazione installa-in-1-clic. I cinque limiti seguenti sono da conoscere prima di mettere un layer MCP in produzione.

Limite 1 — Nessun scheduler. Un MCP server non può girare in cron. Esegue codice solo quando Claude Desktop lo chiama. Per le automazioni ricorrenti (alert orarie, report giornalieri), occorre combinare MCP + cron esterno (script Python indipendente che spinge gli insight via webhook). Consultate la nostra guida n8n Google Ads per le automazioni cron.

Limite 2 — Nessuna UI ricca. Claude Desktop mostra testo e markdown. Per un grafico, una tabella interattiva, un drag-drop, MCP non è il medium giusto. Casi d'uso solo text-first.

Limite 3 — Latenza cumulata. Ogni tool call aggiunge ~500ms a 2s di latenza (LLM thinking + tool exec + LLM synthesis). Una catena di 5 tool call = 5-10 secondi di attesa. Per un PPC manager abituato ai dashboard istantanei, è un cambio di tempo.

Limite 4 — Troppe tool = scelta sbagliata del LLM. Oltre 12-15 tool nello stesso server, Claude inizia a esitare sulla tool giusta da chiamare. Splittare in più server MCP tematici.

Limite 5 — Nessuna batch operation nativa. Una tool call = un'operazione. Per 1.000 mutazioni, fare 1.000 tool call non è praticabile. Tenere le bulk operation lato script standalone, esporre via MCP solo le azioni unitarie.

La roadmap MCP (come annunciata da Anthropic in Q4 2025) prevede per il 2026: supporto nativo di scheduling lato MCP (per eliminare il limite 1), una directory ufficiale meglio indicizzata con rating (qualità dei server), trasporti HTTP/SSE più maturi per i setup team, e un layer di observability (telemetry delle tool call, debugging UI). Seguire la documentazione ufficiale MCP per gli aggiornamenti.

Per gli account che vogliono industrializzare il pilotaggio Google Ads con un layer AI managed (senza codificare il proprio MCP server), il nostro modulo Auto-ottimizzazione copre i casi d'uso di audit, monitoring e alerting in modalità managed con una UI dedicata — consultate anche la nostra checklist di audit Google Ads per la base di audit che deve precedere ogni layer AI. Per gli altri pezzi del puzzle automation, consultate la nostra guida setup API Python e la nostra guida n8n flows.

Per le risorse ufficiali MCP, consultate modelcontextprotocol.io (specifica protocollo) e la documentazione Claude MCP (guide Anthropic).

Fonti

Fonti ufficiali consultate per questa guida:

FAQ

Cos'è MCP esattamente e chi l'ha creato?

MCP (Model Context Protocol) è un protocollo open-source pubblicato da Anthropic nel novembre 2024 (link ufficiale: modelcontextprotocol.io) per standardizzare il modo in cui i LLM interagiscono con fonti di dati esterne e strumenti. Pensatelo come l'equivalente di LSP (Language Server Protocol) per gli IDE: un protocollo client-server dove il client è un LLM (Claude Desktop, Claude Code, Cursor, ecc.) e il server espone risorse, prompt e tool tramite un'interfaccia standardizzata. Il LLM può quindi leggere e chiamare queste tool senza che si sia codificata l'integrazione specifica. Per Google Ads, significa: un solo server MCP Google Ads scritto una volta, utilizzabile da tutti i client MCP che usciranno nel 2025-2026.

MCP vs Function Calling Anthropic API: differenza?

Function Calling (tool use) è una funzionalità lato API: definite le tool nella richiesta API e Claude decide di chiamarle. È usato per costruire la propria applicazione con la propria logica di tool. MCP è un protocollo di estensione che permette a Claude Desktop (l'app desktop) di scoprire e chiamare server esterni che installate localmente. La distinzione è: Function Calling = sviluppate un'app, MCP = installate estensioni a Claude Desktop. MCP usa Function Calling sotto il cofano, ma aggiunge il layer di discovery, sandboxing, configurazione utente. Per un PPC manager che vuole solo usare Claude Desktop per pilotare Google Ads, MCP è la via. Per uno sviluppatore che costruisce un prodotto, Function Calling diretto via SDK resta l'opzione.

Il server MCP gira in locale o in cloud?

Entrambe le opzioni esistono. Locale (trasporto stdio): il server gira sulla vostra macchina, Claude Desktop lo spawna come subprocess via stdin/stdout. Nessuna latenza di rete, credenziali protette localmente, ideale per uso individuale. Cloud (trasporto HTTP/SSE): il server gira su un server remoto, Claude Desktop si connette via HTTP con autenticazione. Necessario per i team che condividono un account Google Ads, o per i server che richiedono risorse costose (database, ML inference). Per un uso solo PPC manager, la modalità stdio in locale è ampiamente sufficiente e più semplice da configurare. Per un'agenzia che vuole esporre il suo MCP server a 10+ analisti, la modalità HTTP/SSE con auth diventa pertinente.

Quante tool può esporre un server MCP Google Ads?

Nessun limite tecnico rigoroso lato MCP — potete esporre 50 tool se volete. Il limite pratico è lato LLM: Claude deve scegliere la tool giusta a ogni interazione, e più tool avete, più il rischio di selezione sbagliata aumenta. Lo sweet spot osservato nei benchmark pubblici: 6-12 tool ben nominate e documentate per server, focalizzate sui casi d'uso critici. Oltre, meglio splittare in più server MCP tematici (audit-server, mutation-server, reporting-server). Ogni tool deve avere una descrizione chiara in meno di 200 caratteri, parametri tipizzati JSON Schema, e idealmente un esempio d'uso.

Quale sicurezza per esporre le proprie credenziali Google Ads via MCP?

Tre livelli di protezione. Primo: le credenziali (developer_token, refresh_token) non lasciano mai la vostra macchina in modalità stdio locale — Claude Desktop vede solo le tool esposte, non il contenuto interno del server. Secondo: il server MCP deve validare ogni mutazione (aggiunta negativo, pausa campagna) con un confirm prompt lato LLM prima dell'esecuzione, mai in silenzio. Terzo: implementare una modalità read-only di default, e attivare le mutazioni solo tramite un flag esplicito (env var WRITE_MODE=true). Sui server MCP Google Ads di produzione che deployiamo, il pattern dominante è: 80% di tool read-only (search, audit, report), 20% di tool mutazione con conferma utente obbligatoria. Non esporre MAI una tool 'delete_campaign' o 'pause_all_campaigns' senza guardrail.

Ready to optimize your campaigns?

Start a free audit in 2 minutes and discover the ROI potential of your accounts.

Start my free audit

Free audit — no credit card required

Keep reading