MCP Access Tokens for Health Data: Scopes and Expiry
An MCP token for health data should belong to one person, reach one client, carry read-only scopes and expire in days. OAuth, personal tokens, rotation and offboarding.
An MCP access token for health-adjacent data should belong to one person, reach one client's account, carry only the read scopes the task needs, and expire in days, not years. It also needs a revocation path that works without finding the laptop it sits on. Curve issues Curve MCP tokens on that pattern: scoped, expiring, bound to one organization, and announced to admins when issued. A token controls what a server can reach, not where its answers go next, and the signed BAA included on every Curve plan covers Curve, not the AI vendor you connect.
Why the token, not the prompt, is the access control
Almost everything on the model's side of an MCP setup is advisory. The specification says tool annotations such as readOnlyHint are only hints, and a system prompt saying "only look at campaign totals" can be overridden by an instruction hidden in a search-terms report. The credential, meaning the token plus the permissions of the account behind it, is the limit the server enforces on every call.
The MCP security guidance is plain: "Attackers who obtain tokens stored by the client, or tokens cached or logged on the server can access protected resources with requests that appear legitimate." OWASP's MCP Top 10, still in beta, lists Token Mismanagement and Secret Exposure first, as MCP01:2025. Two MCP traits make it worse:
- Authorization is optional. The specification marks it "OPTIONAL" and tells local stdio servers to "retrieve credentials from the environment." In practice: a
google-ads.yaml, a credentials JSON or a bearer token pasted into a project's.mcp.json. Claude Code's docs tell teams to check.mcp.jsoninto version control, so a token pasted there becomes a token shared with everyone who clones the repo. Reference it as${GHL_TOKEN}inheadersand keep the value in each person's environment. - The token outlives the conversation. Closing a chat revokes nothing. A token made for one afternoon's analysis works until it expires or is revoked.
When the data behind a token is PHI, the Security Rule reaches the credential directly: access control under 164.312(a)(1) allows access "only to those persons or software programs that have been granted access rights." A token with a contact-read scope is a PHI credential, whatever you meant to ask with it (more in why a BAA is not enough).
OAuth or a personal access token
OAuth 2.1: short-lived by design, broad by default
For remote servers, MCP authorization is built on OAuth 2.1. Servers must confirm a token was issued for them and never pass it through, and authorization servers should issue short-lived tokens and must rotate refresh tokens for public clients. HubSpot requires OAuth 2.1 with PKCE for every connection, HighLevel's current server runs a LeadConnector consent flow, and Meta's Ads MCP server uses Facebook Login for Business.
The catch is breadth. HubSpot scopes are not chosen when you create the connector. A grant can reach whatever the server's tools expose within the permissions of the person who clicked Allow, so that person's role becomes the real scope. Connect with an account whose permissions you would hand to a model.
Personal access tokens: narrow if you make them, permanent if you forget them
A personal access token (PAT), or any static key, is a bearer secret: whoever holds the string is you. HighLevel's original MCP endpoint takes a Private Integration Token as an Authorization: Bearer header plus a locationId.
Static tokens can be scoped tightly. HighLevel says to "Enable only the scopes required for the AI workflow," to keep tokens out of "public repositories, screenshots, shared prompts, or client-side code," and to "Rotate tokens periodically." It documents no expiry, so the token lives until someone replaces it, often in a file built to be committed.
Our rule: use OAuth wherever the server offers it, and accept a PAT only for a local client on a managed device, with an expiry set the day it is created. Where the vendor offers no expiry, as with HighLevel, put a rotation date on the calendar and name an owner.
Curve MCP's personal tokens carry what OAuth would otherwise supply: expiry, scopes and a check on every call.
Least-privilege scopes: read, one client, one purpose
HIPAA's minimum necessary standard (164.502(b)) asks for "reasonable efforts" to limit PHI to what a purpose needs, and marketing analysis gets no treatment exception. For a token, that means three limits: what it can do, which accounts it reaches and which data it reads.
Read-only lives in different places
- GA4. Google's official server calls the Analytics APIs with
analytics.readonly, so it cannot change your GA4 configuration. But the setup command in its README also grantscloud-platform, so the Application Default Credentials file on that laptop reaches far more than GA4. Treat it as a broad Google credential and revoke it when the analysis is done. - Google Ads. The API has one scope,
https://www.googleapis.com/auth/adwords, and Google says it "uses the same scopes for readonly versus readwrite operations," deferring to Google Ads user roles. The official MCP server is read-only in its code. The refresh token behind it is exactly as powerful as its user. - Meta. Agents can be limited to read-only, approval-required or full access, per asset or in bulk. Set read-only before the first connection, not after the first paused campaign nobody asked for.
- HubSpot. With Sensitive Data on, activity and conversation data are blocked from the MCP server, a limit the vendor enforces whatever your token allows.
One client per token
Account reach is where agencies get hurt (see client data boundaries for healthcare agencies). Google says a role granted at the manager level "is inherited by the accounts in the hierarchy," so a token minted from an agency manager login reads every client beneath it. Scope each credential to one clinic, so a leak or a query aimed at the wrong client touches one covered entity, not all of them.
On Google Ads you cannot narrow the token itself, only the user: authenticate as a Google user with Read only access on the one client account, never a manager-account login. On HighLevel, pick one sub-account on the consent screen, not "all available sub-accounts under your agency."
Read-only removes edit and spend risk, not exposure, because reading is how PHI reaches the model. A read-only token with contact or conversation scopes is still a PHI pipe, which is why our GoHighLevel lockdown guide withholds those scopes entirely.
Expiry: days, not years
Expiry is the control for the token nobody remembers creating. Revocation needs someone to know the token exists. Expiry does not.
Long-lived tokens are still easy to get. Meta offers system user tokens that "Never expires" alongside ones valid for 60 days, calls expiring tokens "a security best practice," and says all integrations should adopt them. A refresh token saved in google-ads.yaml is a long-lived credential that keeps minting fresh access tokens.
- OAuth access tokens: minutes or hours, with refresh tokens that rotate on every use.
- Personal access tokens: days, under a hard maximum measured in weeks that nobody can override.
- Renewal means a new token, which forces the question "does this person still need this?"
- Idle tokens die. A token nobody has used recently belongs to an abandoned workflow. Revoke it.
Short expiry has a cost: more reconnecting, and someone will ask for a token that never expires "just for the Monday report." Decline. A scheduled job should run as a named service identity with its own narrow scope and an expiry, such as a Meta system user on a 60-day token, never on a staff member's personal credential.
No shared tokens, across staff or clients
A shared token breaks three things at once. The audit log can only say "marketing" or "the agency," so nobody can tell who asked what. Revoking one person becomes a team outage, so it never happens. And its reach grows to the union of everyone's needs: least privilege in reverse.
HIPAA makes unique user identification a required implementation specification: "Assign a unique name and/or number for identifying and tracking user identity" (164.312(a)(2)(i)). A credential five people paste into their configs is not a unique identity, so where it reaches PHI, it fails that requirement on its face. Curve binds each MCP token to one person and one organization for the same reason.
- One token per person, per client. One strategist on six clinics holds six tokens.
- Name every token by owner, client and purpose, so the list makes sense the day someone leaves.
- Never pass one through Slack, email or a shared vault entry. If two people have seen a token, rotate it.
- Log every call against the token, so each line maps to one person (see MCP audit logs for healthcare).
Rotation, revocation and the day someone leaves
The Security Rule's workforce security standard includes "procedures for terminating access to electronic protected health information when the employment of, or other arrangement with, a workforce member ends" (164.308(a)(3)(ii)(C)). A departing marketing manager might hold:
- An OAuth grant at HubSpot, HighLevel or Meta, tied to their login at that vendor.
- A Private Integration Token in a Claude Code or Cursor config on their laptop.
- A
google-ads.yamlholding a refresh token plus your Google Ads developer token, or a credentials JSON. - A Meta system user token they generated for "the reporting agent." It is issued to the system user, a non-human identity, not to them, so removing their personal access does not by itself revoke it. Revoke or regenerate it.
- The connector entry in their AI client, with chat history holding earlier answers.
Removing one leaves the others working. To close access:
- Revoke at each source. HighLevel's Private Integration Tokens, for example, sit under Settings, Private Integrations in each sub-account.
- Remove or downgrade their user in each ad and CRM account, so grants tied to them fail.
- Rotate every token they could see but did not own. Each one you find is a shared token your inventory missed.
- Check the logs for calls after their last day.
- Write it down, with dates. Security Rule documentation is kept six years (164.316(b)(2)(i)).
Rotate immediately when a token turns up in a screenshot, repository or shared prompt. Revocation stops future calls. It does not recall answers already sent to the model vendor, so what a token can return matters more than how fast you can kill it.
How Curve scopes and expires its MCP tokens
Curve MCP keeps the stakes of a lost token small. It returns only organization-level aggregates, built to withhold small groups, and its tokens are fenced on every axis above:
- Off until the clinic turns it on. Access is a per-user switch, off by default, and only the clinic's primary user can enable MCP for the organization.
- Issued with a check. A new token needs a confirmation code and triggers an admin notice, so no credential appears silently.
- One person, one organization. Each token is bound to the user who issued it and a single organization. The organization comes from the credential, never from anything the model types.
- Scoped and expiring. Tokens carry explicit scopes and an expiry date, and lapse on their own.
- Stored as a hash, shown once. Curve keeps only a SHA-256 hash of each token and shows the secret once, at issue.
- Checked on every call. Verification is never cached, so a revoked token, a deactivated user or an organization switched off stops working on the next call.
- Works in any MCP client. The same token connects Claude (desktop, web or Claude Code), ChatGPT, Cursor or any other MCP-capable client or agent, with every control above applying in each.
- Logged or nothing. Every call is logged against its token, and no data is returned if the log cannot be written.
What a token opens is deliberately small: three read-only tools, no write actions and completed-week reconciliation of your server-side campaigns. Each campaign's platform-reported spend, clicks and impressions sit next to the conversions Curve's server-side tracking recorded, with cost per conversion by completed week, and one link opens the full sent, accepted and matched view inside Curve. A final guard blocks any answer that looks like an email, phone number, ID, date or name, and person-level questions get a single-use link into Curve Analyst that carries no data.
None of this makes your AI vendor a business associate. The AI client is your choice, not a Curve subprocessor, so the design assumes that hop has no BAA and sends it nothing person-level.
Frequently asked questions
Is OAuth always safer than a personal access token for MCP?
Usually, not always. OAuth brings short-lived tokens and audience checks, but a grant often inherits everything the approving user can reach. A narrow static token bound to one location can reach less.
How long should an MCP access token last?
Minutes or hours for OAuth access tokens, with rotating refresh tokens, and days for personal tokens, capped in weeks. A token that never expires, such as Meta's non-expiring system user token, should need a written exception with a named owner.
Can our marketing team share one MCP token?
No. Where the token reaches PHI, sharing defeats the unique user identification required by 164.312(a)(2)(i). It also turns the audit log into "someone on the team."
What happens to an MCP token when an employee leaves?
Nothing, unless someone acts. Static tokens work until revoked or expired, and a token issued to a service identity survives the removal of its creator's access. Run the five offboarding steps above for every credential they held.
Does a read-only scope make an MCP connection safe for health data?
Safe from edits and spend, not from exposure. A read-only token that can pull contacts, conversations or appointment notes still delivers PHI to the model, so exclude those objects or use a server that only returns aggregates.
Does revoking a token remove what the AI already saw?
No. Tool results already sit in a conversation your AI vendor processed, under that vendor's retention terms. Decide what a token may return before you issue it.
Where to start
Start with an inventory, because you cannot scope, expire or revoke a token you do not know exists.
- List every MCP connection and token across Google Ads, GA4, Meta, HubSpot and HighLevel, with owner, client, scopes, created date and expiry.
- Revoke anything shared, anything that never expires and any grant spanning more than one clinic.
- Re-issue the survivors per person and per client, read-only, with an expiry date.
- Add MCP credentials to your offboarding checklist by name.
- Hold new connectors to our HIPAA-safe MCP server checklist.
If you want campaign answers in your AI client from a server whose tokens are already scoped, expiring and bound to one clinic, book a demo of Curve MCP. We will show you the token controls and which questions it will and will not answer.
Reviewed September 2026 against Google, Meta, HubSpot and HighLevel documentation and MCP specification revision 2026-07-28.
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