google-docs-mcp

module
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 5, 2026 License: Apache-2.0

README

google-docs-mcp

A production-grade Model Context Protocol server for Google Docs, written in Go. It lets Claude Code, Claude Desktop and any other MCP client work inside a Google Doc the way a careful colleague does: read it at the right granularity, edit it in place without damaging what is around the edit, propose changes as suggestions, comment on passages, and handle tables, tabs, headers, footnotes and formatting.

Single static binary. Per-user OAuth against your own Google account, in your own Google Cloud project. Nothing leaves your machine except calls to Google's APIs.

Status: v0.5.0. Reading, searching, creating, exporting, editing with minimal diffs in suggest, direct or comment mode, formatting, reviewing suggestions, comment threads, revision history and diffs, tables, tabs, headers, footers, footnotes, images, chips, named ranges, page and section layout, named styles, gdocs:// resources, large-document performance and agent evals are in. Every GA member of the Docs API's Request union is emitted; §16 of the architecture says which fields of those requests the tools expose and which they deliberately do not. See docs/architecture.md for the design and what the evals found.

Reporting a problem

google-docs-mcp doctor checks credentials, scopes and API reachability and names what is missing; most first-run trouble is an API that was never enabled or a consent screen without you on it. If that does not explain it, open an issue — the bug form asks for the doctor output and the version. Never paste a document id or URL, document content, a client_secret.json or a token into an issue; describe the shape of the document instead. Security problems go through SECURITY.md, privately.

Why another Google Docs MCP

Existing servers hand the model raw UTF-16 indices, convert markdown in ways that silently corrupt documents, and anchor comments through the Drive API where they never render inline. This server keeps index math on the server, addresses content by exact text and stable heading ids, edits by minimal diff, refuses to overwrite anchored content, and uses the Docs API's suggestion mode where the project is enrolled. The reasoning and evidence are in docs/architecture.md.

Install

go install github.com/mmedum/google-docs-mcp/cmd/google-docs-mcp@latest

That puts google-docs-mcp in $(go env GOPATH)/bin, which is the path to give your MCP client. Or take a binary from the releases page: each tag publishes archives for linux, darwin and windows on amd64 and arm64, with a checksums.txt to verify against.

tar xzf google-docs-mcp_*_linux_amd64.tar.gz
sha256sum -c --ignore-missing checksums.txt
install -m 0755 google-docs-mcp ~/.local/bin/

Every release is built by GitHub Actions from the tag and carries proof of it. To check that an archive came from this repository's workflow rather than from someone's laptop:

gh attestation verify google-docs-mcp_*_linux_amd64.tar.gz --repo mmedum/google-docs-mcp
cosign verify-blob checksums.txt --signature checksums.txt.sig \
  --certificate checksums.txt.pem \
  --certificate-identity-regexp 'https://github.com/mmedum/google-docs-mcp/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Each archive also ships an SBOM (.sbom.json) listing what went into the binary. go install needs none of this: the module proxy and sum.golang.org verify the source before it is built.

google-docs-mcp --version reports the release it came from either way.

Set up Google (once per person)

Every deployer uses their own Google Cloud project and OAuth client. There is no shared app and nothing to verify with Google.

  1. Create or pick a Google Cloud project.
  2. Enable the Google Docs API and the Google Drive API (APIs & Services → Library).
  3. Configure the OAuth consent screen (Google Auth Platform → Audience):
    • Internal if your account is in a Google Workspace organisation. Tokens then never expire.
    • External with publishing status Testing for a consumer account. Add yourself as a test user. Google expires refresh tokens for such apps after 7 days, so you will run login weekly.
  4. Add scopes (Google Auth Platform → Data Access): .../auth/documents, .../auth/documents.readonly, .../auth/drive, .../auth/drive.readonly.
  5. Create an OAuth client (Google Auth Platform → Clients) of type Desktop app, download its JSON, and store it as ~/.config/google-docs-mcp/client_secret.json (Linux; the google-docs-mcp folder under your OS config directory elsewhere). Keep it out of any repository.
  6. Run:
google-docs-mcp login
google-docs-mcp doctor https://docs.google.com/document/d/<some doc you can open>/edit

The document is optional: doctor on its own checks credentials, scopes and API reachability, and reads the document when given one.

login opens a browser, completes Google's desktop OAuth flow on a loopback port, and stores the refresh token in your OS keyring (Secret Service, Keychain or Credential Manager), falling back to a 0600 file with a warning when no keyring is available. doctor checks every step and tells you exactly what is missing.

Optional: Developer Preview

Suggestion mode (mode: suggest), comments anchored to a text range, and accepting or rejecting suggestions use Docs API features that are in the Google Workspace Developer Preview Program. Apply with the form on that page, giving your Cloud project id. Once enabled for your project, set GDOCS_PREVIEW=true. The programme terms allow use inside your own organisation; do not offer a preview-enabled deployment to people outside it.

Connect a client

Claude Code:

claude mcp add --transport stdio google-docs -- google-docs-mcp

Claude Desktop (claude_desktop_config.json) or Cursor (mcp.json):

{
  "mcpServers": {
    "google-docs": {
      "command": "/absolute/path/to/google-docs-mcp",
      "env": { "GDOCS_LOG_LEVEL": "info" }
    }
  }
}

Claude Desktop rewrites claude_desktop_config.json from its own state while it runs, dropping edits made behind its back: quit it fully, then edit, then start it. It also loads tool definitions lazily, so give it a moment before expecting the tools in a chat.

All settings are environment variables; see docs/configuration.md. Nothing needs to be set for the defaults.

Tools

Tool What it does
get_document Title, tabs, revision id, owner, last change, counts, and this server's capabilities (available write modes, default). Per tab it also reports the page setup, the floating objects, the named ranges and the named style definitions its paragraphs carry — everything a read of the text cannot show. Cheap; call it first.
get_outline Heading tree per tab with stable heading_ids, block handles, and section sizes.
read_document Scoped, budgeted read as markdown, plain text, or raw Docs JSON. Scope by heading_id, heading text, handle range, tab, or header/footer/footnote. Block handles come with the text unless with_handles is false; options add styles, pending suggestions as {++inserted++} / {--deleted--}, and comment markers {>>c:id<<}.
find_in_document Text or regex search returning handles, offsets and context.
search_documents Locate documents by title or content, owner, or modification date.
export_document Google's own md, txt, html inline; pdf, docx, odt, rtf, epub as files under GDOCS_EXPORT_DIR.
create_document New document, optionally with markdown content.
edit_document Atomic batch of insert, append, replace (minimal diff), delete, replace_all, insert_break, insert_footnote, create_header, create_footer, delete_header, delete_footer, create_named_range, delete_named_range, replace_named_range. Targets are exact text, heading_id, handles, cells, or a named range that survives later edits. mode: suggest, direct or comment; dry_run; expect_revision; force.
format_document text_style, paragraph_style, bullets, clear_formatting on the same targets, same modes.
list_suggestions Pending suggested edits with ids, text and handles.
review_suggestion Accept, reject or discard suggestions by id or all (Developer Preview).
list_comments Comment threads with every reply, resolved and deleted state, quoted text and the block they sit on.
add_comment Comment on a passage (pinned with Developer Preview, quoted otherwise) or on the document.
reply_comment Reply to, resolve, reopen a thread, or rewrite a comment or reply of your own.
list_revisions Version history: revision ids, times, authors.
diff_revisions Unified diff of Google's markdown or text export between two revisions. read_document reads an old revision whole.
edit_table insert_table (with a data grid), set_cells (minimal diff per cell), insert_rows, delete_rows, insert_columns, delete_columns, merge_cells, unmerge_cells, style_cells, style_columns (fixed or even widths), style_rows (least height, page-break behaviour), pin_header_rows. Same modes and guard as text edits.
insert_object Insert an inline image from a public URL, a person chip, a rich-link chip or a date chip at a location; replace an image's source in place; or delete an object, including a floating image no text range covers.
layout_document page (size, margins, background, landscape, page numbering, first/even-page headers), section (the same for one section, plus 1–3 columns), section_break, and named_style to redefine NORMAL_TEXT, TITLE, SUBTITLE or HEADING_1HEADING_6 for a whole tab.
manage_tabs Add (with content), rename, move or nest tabs. Always direct: the API cannot suggest tab changes.

Two more tools register only with GDOCS_ENABLE_DESTRUCTIVE=true: delete_comment (a thread or one reply) and delete_tab (a tab with its content and child tabs). Both carry the destructive annotation and ask the client to involve the person.

Documents are identified by id or any docs.google.com URL.

Resources

Clients that attach context as MCP resources can read a document without a tool call. Each is markdown with no handles, suggestions or comments; the read tools are for scoped, budgeted reads.

  • gdocs://<id> — every tab's body, cut at 400000 characters with a note saying where read_document can continue.
  • gdocs://<id>/outline — the heading tree get_outline returns.
  • gdocs://<id>/tabs/<tab> — one tab's body; tab is an id, title or number.
How edits are addressed

The model never sees index numbers. A target is exact text quoted from a read (curly quotes, dashes and spacing are normalised; it must occur once, or occurrence / within disambiguates), a whole section by its stable heading_id, a block by handle (p12, valid for the revision it came from and re-checked on use), a table cell, or a named range, which is the one anchor that outlives an edit: Google moves it with the text it covers, so create_named_range now and target: {named_range: …} in a later call reach the same passage. New content is written as markdown. A replace is applied as the smallest diff between the old and new text, so untouched words keep their formatting and anchored comments.

Tables are named by handle (tbl1) and cells as r2c3; a table that gets a data grid is inserted empty and filled in a second batch once it exists. Table ops read in order: once one changes the grid, the ops after it on that table are applied in a batch of their own, so their row, column and cell numbers mean the grid as it is by then. Old revisions are read and diffed through Google's export, so they have no handles.

Safety model

  • Read tools are annotated read-only. Write tools take a mode chosen by the person: suggest (tracked change), direct, or comment (the proposal is posted as a comment and nothing is edited). Every write is guarded by the revision it was planned against; a concurrent edit is re-planned once, then refused.
  • Direct edits never delete a range that holds a comment anchor, a pending suggestion, an image or a footnote unless explicitly forced.
  • Destructive tools (deleting comments or tabs) are not registered unless GDOCS_ENABLE_DESTRUCTIVE=true. GDOCS_READ_ONLY=true registers only read tools and requests read-only scopes.
  • The server talks only to Google (googleapis.com, and docs.google.com for the revision export links Google's API returns). No telemetry. Logs (stderr) never contain document text.
  • Refresh tokens live in the OS keyring; logout revokes and deletes.

See docs/security.md.

Development

make check      # gofmt, vet, golangci-lint, tests with coverage floor, govulncheck, stdio smoke
make build
./google-docs-mcp --dump-schemas

Test fixtures are synthetic. Never add content, ids or URLs from real documents; gitleaks runs in pre-commit and CI. make bench measures the large-document paths; go test -tags=evals ./internal/evals runs the agent evals against your own account (see the package comment).

Licence

Apache-2.0.

Directories

Path Synopsis
cmd
google-docs-mcp command
Command google-docs-mcp is a Model Context Protocol server for Google Docs.
Command google-docs-mcp is a Model Context Protocol server for Google Docs.
internal
auth
Package auth implements Google's documented OAuth flow for desktop applications: a loopback redirect on 127.0.0.1 with a random port and PKCE, then a refresh-token-backed token source for API calls.
Package auth implements Google's documented OAuth flow for desktop applications: a loopback redirect on 127.0.0.1 with a random port and PKCE, then a refresh-token-backed token source for API calls.
config
Package config loads and validates runtime configuration.
Package config loads and validates runtime configuration.
credentials
Package credentials stores and resolves the OAuth refresh token.
Package credentials stores and resolves the OAuth refresh token.
devcheck command
Command devcheck is the JSON half of the repository's gates.
Command devcheck is the JSON half of the repository's gates.
doc
Package doc holds the parsed document model.
Package doc holds the parsed document model.
doc/doctest
Package doctest loads the synthetic document fixture for tests in several packages.
Package doctest loads the synthetic document fixture for tests in several packages.
gapi
Package gapi is a thin raw REST client for the Google Docs and Drive APIs.
Package gapi is a thin raw REST client for the Google Docs and Drive APIs.
gdocs
Package gdocs defines the Docs API v1 wire types this server reads.
Package gdocs defines the Docs API v1 wire types this server reads.
markdown
Package markdown turns markdown written by the model into a neutral fragment: headings, paragraphs, list items, code lines and tables with styled inline runs.
Package markdown turns markdown written by the model into a neutral fragment: headings, paragraphs, list items, code lines and tables with styled inline runs.
plan
Package plan compiles high-level edit operations into Docs API batchUpdate requests.
Package plan compiles high-level edit operations into Docs API batchUpdate requests.
render
Package render turns the document model into text for the model to read: markdown (default), plain text, and an outline.
Package render turns the document model into text for the model to read: markdown (default), plain text, and an outline.
server
Package server wires the MCP SDK to the tools and offers a schema dump through an in-memory client session.
Package server wires the MCP SDK to the tools and offers a schema dump through an in-memory client session.
service
Package service orchestrates reads: fetch a document, parse it, keep the handle memory, resolve a read scope, and render.
Package service orchestrates reads: fetch a document, parse it, keep the handle memory, resolve a read scope, and render.
tools
Package tools registers the MCP tools.
Package tools registers the MCP tools.
userconfig
Package userconfig stores non-secret, per-profile settings that survive between runs: where the OAuth client JSON lives, which account was logged in, and where the refresh token was stored.
Package userconfig stores non-secret, per-profile settings that survive between runs: where the OAuth client JSON lives, which account was logged in, and where the refresh token was stored.
version
Package version exposes the build-time version string.
Package version exposes the build-time version string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL