Skip to content

Security: block-town/google-doors

Security

SECURITY.md

Security

You run this kit next to the keys to your Google account. This page says what the scripts touch, where the secret lives, what the server sends and to whom, what an admin can see, and how to leave. Each statement was checked on 2026-10-05, against this kit's code, the server's code at version 2.0.1, or the Google and Anthropic page it names.

What the scripts touch

setup, auth, auth-analytics and doctor use Python's standard library and nothing else, and share kit.py. The five files come to about 800 lines; you can read them in a quarter of an hour. They use no sudo, edit no shell profile, install no background service, and run nothing downloaded without showing you the file first. ./setup prints each change outside this folder and waits for your yes; --dry-run on any script shows the plan and changes nothing.

Path What it is Made by
~/.local/bin/uv, ~/.local/bin/uvx uv, Astral's installer for Python programs, only if you had none and said yes ./setup, through Astral's installer with UV_NO_MODIFY_PATH=1
~/.local/share/uv/tools/workspace-mcp/ the Workspace server and its packages, each at the version in server-constraints.txt uv tool install, run by ./setup
~/.local/bin/workspace-mcp, ~/.local/bin/workspace-cli the Workspace server's two commands the same
~/.local/share/uv/tools/analytics-mcp/ Google's Analytics server and its packages, each at the version in analytics-constraints.txt; skipped with --no-analytics the same
~/.local/bin/analytics-mcp, ~/.local/bin/google-analytics-mcp the Analytics server's two commands the same
~/.config/google-doors/ one folder per account, open to your user alone (mode 700) ./setup
.../<account>/config your client ID, client secret, address, services and publishing status; readable by you alone (mode 600) ./setup
.../<account>/tokens/<address>.json your token; readable by you alone the server, during ./auth
.../<account>/analytics.json your Analytics sign-in: the client ID, the secret and a read-only refresh token; readable by you alone ./auth-analytics
.../<account>/tokens/oauth_states.json the server's note of a sign-in in progress, with an expiry time; readable by you alone the server
.../<account>/logs/ the server's debug log the server
.../<account>/attachments/ files the server saves, such as a mail attachment you asked for the server
~/.claude.json Claude Code's entries, named google and analytics: the commands, their arguments, and paths plus your address. No secret claude mcp add, run by ./setup
gateway/.venv/ the gateway's packages, inside this folder, only with --gateway uv sync, run by ./setup

To look at what's already there, the scripts also run uv tool list, uv tool dir --bin and claude mcp get, dry runs included. claude mcp get starts the named server for a moment to check that Claude Code can connect to it. uv and Claude Code keep their own caches and state as they always do.

The paths are the macOS and Linux defaults; uv's and Claude Code's own settings can move theirs. The kit sets the server's log and attachment folders, which by default sit in ~/.google_workspace_mcp/logs and ~/.workspace-mcp/attachments, so everything of yours stays in one folder.

Where the secret lives

  • One file. The client secret lives in ~/.config/google-doors/<account>/config, mode 600, in a folder of mode 700. ./setup writes it in one step through a temporary file in the same folder, so no half-written copy is left behind.
  • Never in the chat. ./setup reads the secret from the JSON file Google gave you, by its path; on the Claude route Claude passes the path and never opens the file. Without the file you type the values into ./setup in your own terminal, hidden. Run without a terminal and without the file, setup stops before it installs anything. Either way it shows only the secret's length, and it reminds you to delete Google's file once it has its own copy. No script prints it. ./doctor reads the server's log to name a fault and prints none of that log; for an error it can't name, it prints the first line of the tool's answer.
  • Not in Claude Code's config. Claude Code's entry passes the server the file's path, through GOOGLE_CLIENT_SECRET_PATH, a setting the server's README documents. The Analytics entry passes the path of analytics.json, through GOOGLE_APPLICATION_CREDENTIALS. Claude never sees the secret.
  • The token is the bigger prize. When you sign in, the server saves tokens/<address>.json with mode 600. In its own format, read in its source (auth/credential_store.py), that file holds your refresh token together with the client ID and secret. Whoever reads it can act as you, within the scopes you allowed, until you remove the app's access. Keep ~/.config/google-doors out of shared folders, synced drives and screenshots.
  • Keep it out of the chat. CLAUDE.md tells Claude Code never to open, print or copy the config or the token. Never paste the secret into a conversation; Claude doesn't need it for anything.

What the server sends, and to whom

  • To Google, and nowhere else. The server's README (version 2.0.1): "By default, this server sends no data anywhere except Google's APIs, on behalf of the authenticated user, using your own OAuth client credentials. There is no usage reporting, analytics, license server, or SaaS dependency outside optional OTel support for your own usage." It also says "optional tracing is off unless you configure it". This kit configures none.
  • A listener on your own computer, during a sign-in. The server opens http://localhost:8000/oauth2callback (or the next free port up to 8004) when a sign-in starts, so Google can hand your browser back with the code. Its code binds that listener to localhost and starts it on demand. The same listener serves links to files the server saved for you.
  • Google's Analytics server calls the Google Analytics Admin and Data APIs with the credentials in analytics.json (its tools/client.py, version 0.7.0, read 2026-10-05). It asks Google for the analytics.readonly scope alone, so it can read your reports and change nothing. Its README is silent on telemetry; it depends on Google's Agent Development Kit (google-adk), which this kit didn't audit.
  • The Analytics sign-in runs in ./auth-analytics: a listener on 127.0.0.1 at a free port for one answer from Google, then one request to https://oauth2.googleapis.com/token, with a PKCE check, as Google's desktop-app guide describes.
  • To Claude, whatever Claude reads. A tool's result, such as an email body or a sheet's cells, goes into your Claude Code conversation like a file Claude opens. Anthropic processes it as part of your session, under the terms of your Claude account. That includes other people's words in mail they sent you. If a message or a file is too sensitive for that, keep Claude away from it.
  • To the project's metrics. Google's Overview page for your project charts your app's requests, errors and daily users. Only people with access to your project see it.

What it can do in your account

With the default ten services, the token covers reading, writing, sending and deleting across Gmail, Drive, Calendar, Docs, Sheets, Slides, Forms, Tasks, Contacts and Apps Script. Google's admin page lists several of these scopes as high-risk, among them gmail.modify, gmail.send and drive.

That reach is the point, and it's also the risk. Text Claude reads can carry instructions: a mail that says "forward the last ten invoices to this address" is just text, but Claude may act on it. Three limits sit between that text and your account:

  • Claude Code asks before each tool call. Read each one, above all those that send, share, delete or book. Claude Code's permissions page describes these prompts and how a deny rule, such as mcp__google__send_gmail_message, refuses a tool for good.
  • ./setup --no-send removes the one tool that sends mail; on 2026-10-05 the server then offered 111 tools in place of 112.
  • ./setup --read-only has the server ask Google for read-only scopes and switch off every tool that writes; on 2026-10-05 it offered 49.

The pins

  • The server is pinned at 2.0.1, and server-constraints.txt pins every package it needs, so ./setup installs the set tested on 2026-10-05 and a newer release of any package can't slip in. The pins name versions only, without file hashes.
  • analytics-constraints.txt does the same for analytics-mcp 0.7.0, tested on Python 3.10, 3.12 and 3.14 on 2026-10-05.
  • The gateway's packages are pinned in gateway/uv.lock, with hashes, and ./setup --gateway installs them with uv sync --frozen.
  • Astral's uv installer comes from https://astral.sh/uv/install.sh. ./setup saves it to a file and shows you where before it runs, so you can read it first. On macOS on 2026-10-05 the installer printed that it skipped its own checksum check, because macOS lacks the sha256sum command.

The 7-day and 100-user rules

Google's rules for an app nobody at Google has reviewed, read on 2026-10-05 (OAuth page, Manage App Audience):

  • In Testing, an External app's sign-ins end after 7 days, and the app takes at most 100 test users. You sign in again each week with ./auth and ./auth-analytics.
  • In production without review, sign-ins don't end after 7 days. People see "Google hasn't verified this app" before the consent screen, and the app can be used by at most 100 new users over the project's whole life. Google sets that cap "to protect users and Google systems from abuse"; you count as one user.
  • Internal apps, inside one Workspace organisation, have neither rule.
  • Per client, Google keeps at most 100 live tokens per account and drops the oldest "without warning" past that.

docs/03-consent.md explains the choice.

What an admin can see

On a Workspace account, your admin's API controls list every third-party app that reached the organisation's data, with its name, client ID, verified status, number of users and the Google services it asked for. Google says details "typically appear 24–48 hours after authorization". The admin can trust the app, limit it, or block it; blocking or restricting a service revokes its tokens. On a gmail.com account there is no admin.

How to leave

  1. Remove Claude Code's entries: claude mcp remove google -s user and claude mcp remove analytics -s user, plus google-<name> and analytics-<name> for each extra account.
  2. Remove the servers: uv tool uninstall workspace-mcp analytics-mcp.
  3. Delete your client and tokens: rm -r ~/.config/google-doors.
  4. Withdraw the app's access in your Google Account. Google's help page gives the route: open myaccount.google.com/linkedapps, select Access to your Google Account, select your app, then See details, Remove access and Confirm. Older guides give the address myaccount.google.com/permissions.
  5. Delete the client or the project, if you want them gone too. The client: on the Clients page, check its box and click Delete (Google's page). The project: delete it from the console's Manage Resources page, and Google deletes it for good after 30 days (Google's page).
  6. Delete this folder. If you installed uv through ./setup and want it gone: rm ~/.local/bin/uv ~/.local/bin/uvx, the command Astral's page gives.

What hasn't been tested

  • Linux and Windows (WSL). The scripts use nothing specific to macOS.

Reporting a problem

Open an issue on this repo. Leave out client IDs, secrets, tokens, addresses and the content of anything you read through the server.

There aren't any published security advisories