Skip to main content
ClaudeWave
michaelrobertsutton avatar
michaelrobertsutton

verified-googledocs-mcp

View on GitHub

A Google Docs MCP server with verified writes: every mutation re-reads the document and returns proof of what changed.

MCP ServersOfficial Registry0 stars0 forksPythonMITUpdated today
Install in Claude Code / Claude Desktop
Method: UVX (Python) · verified-googledocs-mcp
Claude Code CLI
claude mcp add verified-googledocs-mcp -- uvx verified-googledocs-mcp
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "verified-googledocs-mcp": {
      "command": "uvx",
      "args": ["verified-googledocs-mcp"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
Use cases

MCP Servers overview

# verified-googledocs-mcp

<!-- mcp-name: io.github.michaelrobertsutton/verified-googledocs-mcp -->

[![CI](https://github.com/michaelrobertsutton/verified-googledocs-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/michaelrobertsutton/verified-googledocs-mcp/actions/workflows/ci.yml)
[![Coverage](https://img.shields.io/badge/coverage-91%25-brightgreen.svg)](pyproject.toml)
[![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](pyproject.toml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

An MCP server for Google Docs whose writes carry proof. Every mutating tool re-reads the affected content from the document after it writes and returns evidence of what actually changed: before/after excerpts, the match count, and the document revision before and after. A tool never reports success for an edit that did not land.

> **Status:** all 14 tools are implemented, covered by an offline unit suite, and exercised against the real Google Docs and Drive APIs — every tool and every error code passes the [live acceptance gate](docs/acceptance-report.md). Install with `uvx verified-googledocs-mcp`. See [Status](#status).

## The problem

Driving Google Docs from an agent through a general Workspace MCP server tends to fail in quiet, expensive ways:

- A `findAndReplace` meant for one tab silently edits every tab in the document.
- A search returns "0 matches" because the document has curly quotes or a non-breaking space the query doesn't, with no hint why.
- A replace meant for one occurrence hits a repeated sentence and collapses both.
- A "resolve comment" call returns success while the comment stays open.
- Listing comments misses suggested edits entirely.
- A markdown merge injects garbled text that a human only catches days later.

Each of these has a procedural workaround: tell the agent to scope to a tab, retry with normalized quotes, re-read after every write, never trust a resolve result. Those instructions work until someone forgets one. This server moves the discipline into the protocol, where it is deterministic.

## The verified-write contract

Every mutating tool runs the same pipeline: read the tab, locate the target, apply the edit under a revision precondition, read the tab again, and return evidence built from the second read. The return value is a claim about the document's state *after* the call, backed by a server-side re-read, not an echo of the API response.

```jsonc
// replace_text(doc_id, tab_id, find="teh", replace="the", expected_matches=1)
{
  "applied": true,
  "match_count": 1,
  "rung": "exact",                 // which normalization rung matched
  "before": "...±200 chars around the edit, pre-write...",
  "after":  "...the same span, re-read after the write...",
  "revision_before": "ALm37BX...",
  "revision_after":  "ALm37Cy...",
  "audit_logged": true
}
```

When something is wrong, the tool fails loud and *diagnosed*, with a typed error the agent can act on in one round trip rather than guessing:

```jsonc
{
  "error_code": "MATCH_COUNT_MISMATCH",
  "message": "expected 1 match(es) but found 3 at rung 'exact'",
  "diagnostics": { "expected": 1, "actual": 3, "spans": [ /* every location */ ] },
  "retryable": false
}
```

### What backs the guarantee

- **Tab-scoped by default.** Editing tools require an explicit `tab_id`. There is no whole-document replace, so a one-tab edit can never leak into a cover letter or an appendix tab.
- **Normalization ladder.** A search tries exact match, then curly/straight quote equivalence, then non-breaking-space and whitespace-run equivalence, then soft-hyphen stripping, and reports which rung matched. A zero-match result includes the nearest near-miss span it found.
- **Match-count guard.** `expected_matches` defaults to 1. If the real count differs, the tool makes no edit and returns every match location.
- **Revision preconditions.** Writes carry `writeControl.requiredRevisionId` from the pre-read, so a document that changed underneath the operation is rejected by the API rather than edited blind. Section ranges from `find_sections` are stamped with the revision they were computed at and refuse to apply once stale.
- **UTF-16 correct.** Match spans are mapped to the UTF-16 code units the Docs API indexes by, so emoji, combining marks, and other astral characters don't shift an edit onto the wrong text.
- **Audit trail.** Every mutation appends a line to a local JSONL log. The append is best-effort: it never fails a write, and if it can't be written the evidence says so (`audit_logged: false`).

### Evidence by family

The guarantee is not one universal payload — it is a per-family invariant. Each
family re-reads the document after the write and proves the property that family
is responsible for. Every mutating tool also carries `revision_before`,
`revision_after`, and `audit_logged`.

| Family | Tools | Proves |
|--------|-------|--------|
| **Text edit** | `replace_text` | `match_count` equals `expected_matches`; `rung` names the normalization pass that matched; `before`/`after` are ±200-char excerpts of the edited span, the `after` re-read post-write |
| **Markdown range** | `replace_range_markdown`, `replace_tab_markdown`, `append_markdown` | `structural_match` (the written markdown round-trips), `input_blocks` vs `post_blocks` counts, and a `structural_diff` list naming any mismatch |
| **Structural** | `insert_image` | `inline_object_confirmed` — a post-write scan found the inline object at the anchor paragraph |
| **Comment state** | `add_anchored_comment`, `reply_to_comment`, `resolve_comment` | the re-queried `resolved` flag, `reply_count`, `content`, `quoted_text`, and `author` — a resolve that didn't land returns `COMMENT_STILL_OPEN`, never success |

The read and sync tools (`read_document`, `list_tabs`, `find_sections`,
`list_open_items`, `get_comment_thread`, `diff_tab_vs_file`) make no changes and
carry no `applied`/evidence payload.

### Dry run

The five mutating tools (`replace_text`, `replace_range_markdown`,
`replace_tab_markdown`, `append_markdown`, `insert_image`) accept `dry_run=true`.
No API write is issued; the response carries `applied: false`, an empty
`revision_after` (no write, so no new revision), `audit_logged: false`, and —
for `replace_text` — a predicted `after` excerpt computed by splicing the
replacement into the pre-read. Use it to confirm a locate resolves to the right
span before committing the edit.

## Tools

Fourteen focused tools, each described by *when* to reach for it, replace the slice of a 150-tool Workspace server that document workflows actually use.

### Reading and structure
| Tool | What it does |
|------|--------------|
| `read_document` | Read a tab as markdown or as structured positions and style runs |
| `list_tabs` | List tab IDs, titles, and nesting |
| `find_sections` | Find headings and return their ranges, stamped with the document revision |

### Editing (verified, tab-scoped)
| Tool | What it does |
|------|--------------|
| `replace_text` | Find/replace within a tab, with the normalization ladder and match guard |
| `replace_range_markdown` | Replace a section range with markdown |
| `replace_tab_markdown` | Replace a whole tab's content with markdown |
| `append_markdown` | Append markdown to a tab |
| `insert_image` | Insert an image at a quoted anchor or heading |

### Comments and suggestions
| Tool | What it does |
|------|--------------|
| `list_open_items` | Open comments **and** pending suggested edits in one call |
| `get_comment_thread` | Read a comment's full reply chain |
| `add_anchored_comment` | Add a comment anchored to quoted text |
| `reply_to_comment` | Reply to a comment |
| `resolve_comment` | Resolve a comment, re-query it, and confirm it actually closed |

### Sync
| Tool | What it does |
|------|--------------|
| `diff_tab_vs_file` | Diff a tab's markdown against a local file |

## Status

Built incrementally; each tool ships with its verification and tests rather than as a stub.

| Area | State |
|------|-------|
| OAuth (`verified-googledocs-mcp auth`), token cache | done |
| `read_document`, `list_tabs`, `find_sections` | done |
| Verification kernel (locator, error envelope, audit) | done |
| `replace_text` (verified) + enforcement middleware | done |
| Comment tools + `list_open_items` | done |
| Markdown write tools + `diff_tab_vs_file` | done |
| Live acceptance gate (all 14 tools, all 12 error codes) | done — [report](docs/acceptance-report.md) |
| PyPI packaging + publish workflow | done; first release `v0.1.0` |
| MCP registry listing | published with `v0.1.0` |

## Install

The server talks to Google with **your own** OAuth credentials, so setup is a
one-time Google Cloud step, then registering the server with your MCP client.

### 1. Google Cloud project (OAuth credentials)

1. Create a Google Cloud project and enable the **Google Docs API** and **Google Drive API** (APIs & Services → Library).
2. Configure the **OAuth consent screen**: User type **External**, publishing status **Testing**, and add your own Google account under **Test users**. (Testing mode is the point — the app stays private to the test users you list; you never submit it for Google verification.)
3. Create an **OAuth client ID** of type **Desktop app** and download the client secret JSON to `~/.config/verified-googledocs-mcp/credentials.json`. (Override the location with `VERIFIED_GOOGLEDOCS_MCP_CREDENTIALS`.)

### 2. Authorize once, in a terminal

```bash
uvx verified-googledocs-mcp auth
```

This opens a browser and completes consent. Because the app is unverified and in
Testing, Google shows a **"Google hasn't verified this app"** screen — click
**Advanced → Go to verified-googledocs-mcp (unsafe)** and continue. This is
expected for a personal Desktop client; you are granting access to your own app,
running locally as you. It then caches a refreshable token at
`~/.config/verified-googledocs-mcp/token.json`. Auth runs o
agentsgoogle-docsllmmcpmodel-context-protocolpython

What people ask about verified-googledocs-mcp

What is michaelrobertsutton/verified-googledocs-mcp?

+

michaelrobertsutton/verified-googledocs-mcp is mcp servers for the Claude AI ecosystem. A Google Docs MCP server with verified writes: every mutation re-reads the document and returns proof of what changed. It has 0 GitHub stars and was last updated today.

How do I install verified-googledocs-mcp?

+

You can install verified-googledocs-mcp by cloning the repository (https://github.com/michaelrobertsutton/verified-googledocs-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is michaelrobertsutton/verified-googledocs-mcp safe to use?

+

michaelrobertsutton/verified-googledocs-mcp has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.

Who maintains michaelrobertsutton/verified-googledocs-mcp?

+

michaelrobertsutton/verified-googledocs-mcp is maintained by michaelrobertsutton. The last recorded GitHub activity is from today, with 0 open issues.

Are there alternatives to verified-googledocs-mcp?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy verified-googledocs-mcp to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: michaelrobertsutton/verified-googledocs-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/michaelrobertsutton-verified-googledocs-mcp)](https://claudewave.com/repo/michaelrobertsutton-verified-googledocs-mcp)
<a href="https://claudewave.com/repo/michaelrobertsutton-verified-googledocs-mcp"><img src="https://claudewave.com/api/badge/michaelrobertsutton-verified-googledocs-mcp" alt="Featured on ClaudeWave: michaelrobertsutton/verified-googledocs-mcp" width="320" height="64" /></a>