Skip to main content
Guide

Claude and Google Ads for Clinics: A PHI-Safe MCP Setup

Connect Claude to Google's read-only Google Ads MCP with no PHI: clean lead forms and Customer Match first, use a Read-only Google user, allowlist GAQL, log every query.

11 min read

To connect Claude to Google Ads safely in a clinic, run Google's read-only Google Ads MCP as a channel that never carries PHI: clean the account, use a dedicated Read-only Google user, block lead-form data in code, keep prompts aggregate and log every query. No BAA covers the connector leg, so your Claude plan is a backstop, not the control. For campaign-level answers without raw rows, Curve, the HIPAA-compliant tracking layer with a signed BAA on every plan, answers through Curve MCP from rounded weekly aggregates with small groups withheld.

What you are actually connecting

The server is google-ads-mcp, which Google open-sourced under Apache 2.0 in October 2025. It is not Google-hosted: it runs on your machine over stdio, or on infrastructure you deploy (such as Cloud Run). It has three tools:

  • list_accessible_customers lists every account the signed-in Google user can reach.
  • search builds a GAQL query from a resource, a list of fields and a list of conditions, and runs it.
  • get_resource_metadata describes a resource's fields.

Google's docs say it "cannot modify bids, pause campaigns, or create new assets." Read-only means Claude cannot change the account, not that Claude only sees aggregates: search reaches anything GAQL can, and the repository warns that the server "will expose your data to the Agent or LLM that you connect to it."

Step 1: Clean the account before Claude can read it

Every GAQL row carries whatever is stored in the account, so the first control is what sits in Google Ads, not what goes into the prompt. Audit four places.

Lead form assets

Read-only does nothing about this one. The API resource lead_form_submission_data holds each submission's fields (field types include full name, email, phone number and postal code), custom-question answers, submission time and GCLID, and the server's tool description lists it as queryable. Google keeps leads for 60 days, whether or not you also send them to your CRM by webhook.

Delete any custom question about symptoms, conditions or treatment (see PHI-safe Google lead form routing), then keep the resource out of reach in code in Step 4. A clean form this month does not clear last month's submissions.

Customer Match lists

GAQL cannot download list members, but the user_list resource returns each list's name, description, estimated size, match rate and upload key type. A list named "Semaglutide patients, March export" tells Claude, and the transcript, that a patient file went to Google.

The uncomfortable part: if that list exists, the MCP is the smaller problem. Google treats health as a sensitive category where Customer Match cannot be used, and its policy restricts uploading health information. Remove the list and trace how it got there with a customer list upload audit.

Search terms

Google's report lists only terms "a significant number of people have used" and omits low-volume terms for privacy, so a row is not one person's query. It is still condition language tied to your clinic. Keep it at theme level, never cut it by day, hour or small area, and treat it as untrusted input, because the public typed it.

Names and call details

Campaign, ad group, conversion action and label names travel with every row. Rename anything naming a person ("Retarget Maria Gomez no-show"). A conversion action named for a service line ("PrEP consult booked") is a bigger problem than the MCP, because it tells Google which service each converting click was for. Curve's neutral event aliases fix that upstream, so Google, and then Claude, see only a neutral event name.

If you use Google's call reporting, call_view returns one row per call with start time, duration and caller area code. Call counts by campaign and week are fine. Call lists are not.

Step 2: Choose a Claude plan and BAA posture you can defend

  • Enterprise is the only Claude plan with a BAA. Only Enterprise plans can enable HIPAA readiness; Team, Pro, Max and Free cannot. Only the Primary Owner can accept the BAA, and enabling it cannot be undone. The Claude API has its own BAA, but its MCP connector is not HIPAA-eligible.
  • The connector leg is excluded anyway. Anthropic allows MCP servers and connectors on Enterprise, but data sent to third parties through them is not covered by its BAA. Google Ads is not on Google's list of BAA-covered products either (our Google Ads MCP verdict has the detail).
  • The usual surfaces are the unclear ones. A local stdio server runs from Claude Desktop or Claude Code. We found no Anthropic statement on whether the desktop chat app is covered, and Anthropic's own pages conflict on Claude Code: covered only with zero data retention in one, "not covered under HIPAA readiness" in another.

So build the setup to carry no PHI at all. An Enterprise BAA is at most partial cover for a mistake: it may not reach the Desktop or Claude Code session this server runs in, and it never covers what goes to Google.

On Team, Pro or Max, "no PHI in this chat" is absolute. On any plan, use a seat the clinic or agency controls, never a personal subscription. More on plans in Is Claude HIPAA compliant?

Step 3: Give Claude a least-privilege Google identity

The Google Ads API authorizes with the adwords OAuth scope, and Google says the API "doesn't have a separate access model of its own, or use separate OAuth 2.0 scopes to limit functionality." The server is read-only because of its code. The token is not, so if it leaks, the Google user's access level is the only limit left.

  1. Create a dedicated Google account for AI reporting. Never reuse the admin login that manages billing and users.
  2. Grant it Read-only access to the one Google Ads account it needs. Read-only users can view campaigns and run reports, but cannot edit campaigns or billing information, or grant anything beyond email-only access.
  3. Keep it off manager accounts. A role granted at the manager level "is inherited by the accounts in the hierarchy," and list_accessible_customers will list every one. An agency that signs in through its MCC hands Claude every client at once. Grant access on the client account directly and leave GOOGLE_ADS_LOGIN_CUSTOMER_ID unset; the README requires it only for access through a manager account, so if queries fail without it, the identity still goes through one.
  4. Guard the credentials. A developer token needs Explorer access or higher for production accounts. Keep the credentials file out of synced folders, record who holds a copy, and remove the user's access the day its owner leaves.

Step 4: Install it pinned, and enforce the limits in code

The repository's sample config runs the server with pipx and three environment variables (GOOGLE_APPLICATION_CREDENTIALS, GOOGLE_PROJECT_ID, GOOGLE_ADS_DEVELOPER_TOKEN). Change two things.

Pin the version. The sample installs the repository's latest code, so a restart can run code nobody reviewed. Use a named release (pipx run --spec "google-ads-mcp==X.Y.Z" google-ads-mcp).

Allowlist in code. A prompt instruction is a request; a check is a control. The search tool takes resource, fields and conditions arguments. In Claude Code, a PreToolUse hook matched to mcp__<server>__search can inspect them and deny the call before it runs; elsewhere, patch the same check into the server's search function (Apache 2.0 allows it).

Allow only the resources a weekly report needs (customer, campaign, campaign_budget, ad_group, ad_group_ad, keyword_view, search_term_view, conversion_action) and reject everything else, including segments.hour and segments.geo_target_postal_code in fields. The resources that matter most, and why:

  • lead_form_submission_data (lead contact fields and answers)
  • local_services_lead and local_services_lead_conversation (contact details, messages, call recording links)
  • click_view (one row per click with its GCLID and location, a join key back to a person)
  • call_view (one row per call)
  • user_list (list names can reveal a patient upload)

Check conditions too. It is free text that goes to Google, on the leg no BAA covers, and the server writes it to its log. Accept only date ranges, status values and numeric IDs, and reject everything else, because that is where a pasted GCLID, email or name would sit.

Run this server in a session of its own, with no tool that can send data out (email, chat, a write-capable ads server), so an instruction planted in public search-term text has nowhere to go.

Step 5: Keep prompts aggregate, never paste PHI, and log every call

A safe prompt names a level (account or campaign), a period (a week or longer) and a metric. A risky prompt names a person, a moment or a small slice.

Prompts that work, and prompts that do not

  • Safe: "For the last four complete weeks, list spend, conversions and cost per conversion by campaign. Leave out any campaign with fewer than 11 conversions."
  • Safe: "Group last month's search terms into themes with total clicks and conversions per theme. Do not list individual terms."
  • Unsafe: "Show me last week's leads from the IVF form."
  • Unsafe: "Break out TRT conversions by ZIP code, by day."

The 11 is borrowed from CMS, which will not report any cell with a value of 1 to 10, including one that could be derived from other cells. That threshold governs what you report onward; the Step 4 allowlist governs what Claude can fetch. How small-group rules work explains the subtraction problem a single threshold misses.

What never to paste

  • Patient or lead names, emails, phone numbers, birth dates or addresses.
  • GCLIDs copied from your CRM, EHR or booking tool. A GCLID next to an appointment is a join key back to one person.
  • CRM, EHR or scheduling exports, however trimmed.
  • Offline conversion or Customer Match files, hashed or not. A hashed email is still unique to one person, and Safe Harbor treats "any other unique identifying number, characteristic, or code" as an identifier.

The usual temptation: paste the CRM export so Claude can "match it up" with Google's numbers. That one move turns aggregate reporting into a PHI disclosure, and the same logic applies to every AI chat.

Log every query

The MCP specification says clients should log tool usage for audit and keep a human able to deny tool calls, so approve each search call rather than pre-approving the tool. The server already writes every assembled GAQL query, conditions included, to standard error at INFO level. Keep that output, and add the user, customer ID, row count and any denial (in Claude Code, a PostToolUse hook can do it).

Log the query, not the results, or the log becomes a second copy of anything that slipped through. The client's own log may already be that copy. In Claude Desktop, server output lands in ~/Library/Logs/Claude/mcp*.log (on Windows, %APPDATA%\Claude\logs), and the MCP debugging guide says those logs also capture message exchanges.

Limit that folder to the reporting user, rotate it, and never let it sync. Review it weekly for resources outside the allowlist, day or hour cuts and unexpected customer IDs. MCP audit logs for healthcare covers what else to keep.

How Curve answers campaign-level questions without raw rows

Curve moves the campaign-level rules out of your prompts and into the product. It does not replace the Google Ads MCP for keyword, ad group or search-term questions, and it does not clean lead forms or Customer Match lists out of your account, so Step 1 still applies.

Upstream, Curve's tracking script replaces the Google tag and sends events to US-hosted infrastructure first. Only explicitly mapped fields reach each destination, identifiers are SHA-256 hashed, and neutral event aliases keep service lines out of conversion names.

Downstream, Curve MCP builds the safeguards in:

  • It reconciles your server-side campaigns: per campaign, each platform's reported spend, clicks and impressions sit beside the conversions Curve's server-side tracking recorded, with cost per conversion by completed week.
  • Figures cover completed weeks only, over fixed windows of the last 1, 4, 13 or 52 weeks.
  • It counts people, not visits. Small groups are withheld, counts and spend are rounded, and a number that could be subtracted from another to reveal a small group is withheld too.
  • Inputs are fixed choices, no visitor-set string (UTMs, page paths, referrers) is ever returned, and campaign or goal names appear only if the clinic approved them.
  • A final guard blocks any answer containing something shaped like an email, phone number, ID, date or name, and fails closed. Every call is logged, and nothing is returned if the log cannot be written.
  • The service runs under a database role that cannot read contact details, form answers or journeys.

One link opens the full sent, accepted and matched view inside Curve. Person-level questions get a single-use link to Curve Analyst instead of data, behind a Curve login.

The limits are plain: nothing below campaign level, no revenue or ROAS, no channel, device, region or page breakdowns, and figures up to a week behind the dashboard. The connector is read-only, off by default and switched on only by the clinic's primary user. How Curve MCP handles campaign data lays out the design.

Frequently asked questions

What should the resource allowlist include?

Only what a weekly report reads: customer, campaign, campaign_budget, ad_group, ad_group_ad, keyword_view, search_term_view and conversion_action. Deny by default, so a resource nobody reviewed stays blocked, and reject hour and postal-code segments.

Can a Read-only Google Ads user see lead form leads?

Not in the Google Ads interface: Google lets only Standard and Admin users download leads. Google does not say whether the API applies the same limit, so keep the Step 4 allowlist either way.

Where do the GAQL query logs end up, and how long do we keep them?

The server writes each query to standard error. Claude Desktop saves that in ~/Library/Logs/Claude/mcp*.log; a Claude Code hook writes wherever you point it. HIPAA names no period for tool logs, so six years, its documentation-retention period, is a defensible default. Keep queries, never results.

Which Claude plan should a clinic use?

Enterprise with HIPAA readiness if you have it, since it is the only Claude plan with a BAA. The setup must still carry no PHI.

Does Curve MCP work with Claude?

Yes: Claude desktop, web and Claude Code, plus ChatGPT, Cursor and any other MCP-capable client. It returns rounded weekly campaign figures with small groups withheld, and a demo shows it answering the campaign questions you bring.

Where to start

Do the account cleanup this week either way; lead forms, Customer Match lists and careless names are exposures with or without Claude. Connect the Google Ads MCP only once the Read-only identity, pinned version, allowlist and log are in place.

If the goal is a weekly campaign answer rather than a GAQL project, book a demo to see Curve MCP answer campaign questions without raw rows, and run the free compliance scanner to see what your site sends Google today. Everything else is at curvecompliance.com.

Reviewed September 2026. Checked against Google's Google Ads MCP documentation and repository, and Anthropic's BAA and HIPAA-readiness pages.

Stay Compliant. Scale Confidently.

Join healthcare innovators who trust Curve for HIPAA-compliant ad tracking.Launch in hours, not months. Your growth stack, now HIPAA-safe.

Book a free tracking audit