# Gdocs Comments Mcp

> MCP server for adding inline, range-anchored comments to Google Docs — the one comment operation the Google Docs & Drive APIs can't do. For AI agents (Claude, Cursor, Copilot) that review documents.

- **Type:** MCP server
- **Install:** `agentstack add mcp-stanislawherjan1-gdocs-comments-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [stanislawherjan1](https://agentstack.voostack.com/s/stanislawherjan1)
- **Installs:** 0
- **Category:** [Web & Browser](https://agentstack.voostack.com/c/web-and-browser)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [stanislawherjan1](https://github.com/stanislawherjan1)
- **Source:** https://github.com/stanislawherjan1/gdocs-comments-mcp

## Install

```sh
agentstack add mcp-stanislawherjan1-gdocs-comments-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

gdocs-comments-mcp

  Inline, range-anchored comments for Google Docs — the one comment operation the Google APIs can't do.

  
  
  
  = 18">
  

  
    Quickstart
    &nbsp;·&nbsp;
    Scope
    &nbsp;·&nbsp;
    Tools
    &nbsp;·&nbsp;
    Configuration
    &nbsp;·&nbsp;
    How it works
    &nbsp;·&nbsp;
    Troubleshooting
    &nbsp;·&nbsp;
    Server deployment
    &nbsp;·&nbsp;
    FAQ
  

You're building an AI process around Google Docs — an agent that reviews drafts, audits contracts, gives editorial feedback. The natural way to deliver that feedback is how humans do it: **a comment pinned to the exact sentence it's about**, not a wall of text dumped at the end of the doc or into chat.

Then you hit the wall: **the Google APIs can't create anchored comments.** The Docs API has no comment endpoints at all, and the Drive API accepts an `anchor` field only to have the Docs editor ignore it — the comment shows up as a general, whole-document comment.

This MCP server closes that gap. Your agent calls `add_comment` with a text fragment and a comment; the server posts it through a real, logged-in Google Docs session, so it lands anchored to that exact text — just as if a human had selected it and pressed `Ctrl+Alt+M`:

  

## Why not the official APIs?

This server does one thing: **add a comment to a Google Doc.** The interesting case is the anchored one — a comment pinned to a specific text range — which no Google API can do.

| Add a comment… | Google Docs API | Google Drive API | this server |
|---|:---:|:---:|:---:|
| unanchored (whole document) | ❌ | ✅ | ✅ |
| anchored to a text range | ❌ | ❌ | ✅ |

The Docs API has no comment endpoints at all. The Drive API's `comments.create` accepts an `anchor` field, but the Docs editor **ignores** it — the comment renders as an unanchored, whole-document comment. The editor's own anchor format (`kix.*`) is undocumented and can't be produced externally ([Drive API docs](https://developers.google.com/workspace/drive/api/guides/manage-comments), [issuetracker #292610078](https://issuetracker.google.com/issues/292610078), open since 2016). Driving the editor UI is the only way — so this server does exactly that, and nothing else. (Listing, replying, resolving, and deleting comments already work over the Drive API — use a Drive-based tool for those.)

## What this does — and what it doesn't

This server is deliberately **one narrow thing**. Read this before wiring it in.

**✅ It does:** add comments to a Google Doc — anchored to a specific text range (the part no API can do), or unanchored on the whole document.

**❌ It does NOT:**

| You want to… | Use instead |
|---|---|
| **Read the document's content** (so an agent can decide what to comment on, or get the exact text to anchor to) | **Google Docs API** (`documents.get`) or a Docs-reading MCP |
| Export the doc (text / markdown / PDF) | **Google Drive API** (`files.export`) |
| List / reply to / resolve / delete comments | **Google Drive API** (`comments.*`) — faster, no browser |

> **Important:** this tool **never returns document content** — its output is structured-only (`{ ok, anchored, occurrence_used, verified }`), by design, so a malicious doc can't inject instructions into your agent. That means the agent is writing *blind*: to review a doc intelligently, pair this with a **read** capability (Docs API `documents.get`) and feed the exact quoted text back in as `find_text`. The two use different auth — this server drives a logged-in browser session (no OAuth), while the Docs/Drive APIs need an OAuth token or service account — but they can run against the same Google account.

## Quickstart

**One command** — signs you in (opens a browser once), then registers the server with Claude Code:

```bash
npx -y gdocs-comments-mcp setup
```

That's it — skip to **Use it** below. Prefer to do it by hand, or use another client? The manual steps are below.

Manual setup

**1. Log in once** — opens a browser window; the Google session is saved to a local profile (`~/.gdocs-comments-mcp/profile`):

```bash
npx -y gdocs-comments-mcp login
```

**2. Add the server to your MCP client:**

```bash
# Claude Code
claude mcp add gdocs-comments -- npx -y gdocs-comments-mcp
```

**Other MCP clients** — after `login`, add the config for your client:

Claude Desktop / Cowork

Add to `claude_desktop_config.json` (Settings → Developer → Edit Config):

```json
{
  "mcpServers": {
    "gdocs-comments": {
      "command": "npx",
      "args": ["-y", "gdocs-comments-mcp"]
    }
  }
}
```

Project-level .mcp.json (shared with your team via git)

Create `.mcp.json` in the project root — Claude Code, Cowork, and most MCP clients pick it up:

```json
{
  "mcpServers": {
    "gdocs-comments": {
      "command": "npx",
      "args": ["-y", "gdocs-comments-mcp"]
    }
  }
}
```

Note: every user of the project still runs `npx gdocs-comments-mcp login` once on their own machine — sessions are personal and never shared through git.

Cursor

Add to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):

```json
{
  "mcpServers": {
    "gdocs-comments": {
      "command": "npx",
      "args": ["-y", "gdocs-comments-mcp"]
    }
  }
}
```

VS Code (GitHub Copilot)

Add to `.vscode/mcp.json`:

```json
{
  "servers": {
    "gdocs-comments": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "gdocs-comments-mcp"]
    }
  }
}
```

**3. Use it** — ask your agent:

> Add a comment to https://docs.google.com/document/d/1AbC…/edit — anchor it to "quarterly numbers" and say "Update this before Friday".

The agent calls `add_comment` and gets back:

```json
{ "ok": true, "anchored": true, "occurrence_used": 1, "verified": true }
```

…and the comment is sitting on the highlighted phrase in the doc, from the account you logged in with.

No Playwright browser download is needed — by default the server drives your installed Google Chrome via `playwright-core`.

## Tools

### `add_comment`

| Param | Required | Description |
|---|:---:|---|
| `doc` | ✅ | Document id **or** full `docs.google.com/document/d//edit` URL |
| `comment_text` | ✅ | Comment body (plain text, newlines OK) |
| `find_text` | — | Exact, single-line text fragment to anchor to (must match the doc text). **Omit to add a general, unanchored comment on the whole document.** |
| `occurrence` | — | Anchor to the N-th match when `find_text` appears multiple times (default 1) |

Returns `{ ok, anchored, occurrence_used, verified }` — `verified: true` means the posted comment was observed in the page after submitting. If `find_text` is given but not found, the call fails with `TEXT_NOT_FOUND` and **nothing is posted**.

The tool **never returns document content**, so a malicious doc can't inject instructions into your agent through it.

### `check_connection`

Probes the Google session; returns `{ connected, mode }`. If `connected: false`, run `npx gdocs-comments-mcp login` again.

> **Scope note:** this server does *one* thing — creating anchored comments. Listing, replying, resolving, and deleting comments all work fine through the Drive API (`comments.*`), which is faster and needs no browser — use a Drive-based MCP for those.

## CLI

```bash
npx gdocs-comments-mcp login    # one-time interactive Google sign-in
npx gdocs-comments-mcp status   # is the saved session still valid?
npx gdocs-comments-mcp logout   # delete the saved session/profile
```

## Configuration

All optional, via environment variables:

| Env var | Default | Purpose |
|---|---|---|
| `GDOCS_COMMENTS_PROFILE_DIR` | `~/.gdocs-comments-mcp/profile` | Where the logged-in browser profile lives (set a different dir per Google account) |
| `GDOCS_COMMENTS_BROWSER_CHANNEL` | `chrome` | `chrome` \| `msedge` \| `chromium` (bundled; needs `npx playwright install chromium`) |
| `GDOCS_COMMENTS_HEADLESS` | `true` | Set `false` to watch the automation work |
| `GDOCS_COMMENTS_IDLE_CLOSE_MIN` | `10` | Close the managed browser after N idle minutes (`0` = keep open) |
| `GDOCS_COMMENTS_CDP_URL` | — | Attach to an existing browser over CDP instead of managing a profile ([see below](#running-on-a-server--datacenter-ip)) |
| `GDOCS_COMMENTS_AUDIT_LOG` | off | JSONL audit log (hashes only, no content) |

## Troubleshooting

| Error | What it means | Fix |
|---|---|---|
| `NOT_CONNECTED` | No saved Google session yet | `npx gdocs-comments-mcp login` |
| `SESSION_EXPIRED` | The saved session lapsed (idle sessions die after ~1–2 weeks) | `npx gdocs-comments-mcp login` again |
| `TEXT_NOT_FOUND` | `find_text` doesn't occur in the doc (or `occurrence` > number of matches) | Pass a fragment that matches the doc text exactly — nothing was posted |
| `NO_BROWSER` | No Chrome/Edge/Chromium found | Install Google Chrome, or `npx playwright install chromium` + `GDOCS_COMMENTS_BROWSER_CHANNEL=chromium` |
| `PROFILE_LOCKED` | Another process holds the profile (usually a running server + a `login`/`status` attempt) | Stop one of them, or use a second `GDOCS_COMMENTS_PROFILE_DIR` |
| Comment lands but `verified: false` | The post-submit check couldn't see the comment (can be a false negative on long comments) | Check the doc; rerun with `GDOCS_COMMENTS_HEADLESS=false` to watch |

First run on a new machine? `npx gdocs-comments-mcp status` tells you exactly where you stand.

## Running on a server / datacenter IP

On a residential machine the default profile mode just works. On datacenter IPs, Google's anti-fraud **rejects a freshly launched browser process reusing a saved session** — it bounces to `accounts.google.com/confirmidentifier`. Relaunching from a profile does not work there.

What does work: keep the exact browser the operator logged into **alive**, and let this server attach to it:

1. Start a long-lived Chrome/Chromium (under Xvfb if headless) with `--remote-debugging-port=9333` and log in to Google inside it once.
2. Run the MCP server with `GDOCS_COMMENTS_CDP_URL=http://127.0.0.1:9333`.

The server then drives that live session over CDP and never launches its own browser. Keep the session warm by navigating it to `docs.google.com` every few hours, or an idle session expires after ~1–2 weeks.

## How it works

Because the APIs can't anchor a comment, the server does exactly what a person would: it drives the real Google Docs editor. Here's the full path of one `add_comment` call.

**1. Attach to a logged-in browser.** In the default *profile mode*, the server owns a persistent Chromium profile (your installed Google Chrome, via `playwright-core` — no extra browser download). You authenticate into it once with `gdocs-comments-mcp login`; the Google session cookies are saved to `~/.gdocs-comments-mcp/profile` and reused headlessly on every later run. In *CDP mode* (`GDOCS_COMMENTS_CDP_URL`) the server instead attaches over the Chrome DevTools Protocol to a browser you keep alive — see [server deployment](#running-on-a-server--datacenter-ip).

**2. Open the document.** It navigates to `https://docs.google.com/document/d//edit?hl=en`. The `doc` id is validated first, and navigation is hard-pinned to `docs.google.com` — the tool can't be steered elsewhere. If the page bounces to `accounts.google.com`, the session is dead and the call returns `SESSION_EXPIRED`. `?hl=en` pins the UI language so the find-bar counter is parseable in the next step.

**3. Find the anchor text.** The document body renders to an HTML ``, not selectable DOM — so you can't just query for the text and click it. Instead the flow is entirely keyboard-driven (which also makes it locale- and CSS-class-independent):

```
Ctrl/Cmd+F  →  type find_text  →  read the "N of M" match counter
```

Reading the counter **before** commenting is the key safety step: if `find_text` has zero matches, or `occurrence` is larger than the match count, the call fails with `TEXT_NOT_FOUND` and **nothing is posted** — instead of the old failure mode where a blind key sequence would silently drop the comment wherever the cursor happened to sit.

**4. Select the requested occurrence and comment.** It presses `Enter` N times to land on the N-th match, `Esc` to close the find bar (leaving that occurrence selected), then:

```
Ctrl/Cmd+Alt+M  →  type comment_text  →  Ctrl/Cmd+Enter (submit)
```

`Ctrl/Cmd+Alt+M` is the Docs shortcut for "insert comment on the current selection" — which is precisely the anchored comment the APIs won't create. Keyboard shortcuts are chosen per-platform (`Cmd` on macOS, `Ctrl` elsewhere).

(If `find_text` is omitted, steps 3–4 collapse to "put the cursor at the document start and comment there" — a general, unanchored comment.)

**5. Verify and report.** After submitting, the server waits for the comment text to appear in the page and returns `{ ok, anchored, occurrence_used, verified }`. `verified: true` means the posted comment was actually observed; it never returns any document content, so a poisoned document can't smuggle instructions back into your agent. Concurrent calls are serialized behind a mutex, because two keyboard flows in the same window would interleave and corrupt each other.

```
add_comment ─▶ attach browser ─▶ open doc (?hl=en) ─▶ Ctrl/Cmd+F find_text
             ─▶ check match counter ─(0 matches)─▶ TEXT_NOT_FOUND, nothing posted
             ─▶ Enter×N ─▶ Esc ─▶ Ctrl/Cmd+Alt+M ─▶ type ─▶ Ctrl/Cmd+Enter
             ─▶ verify comment in page ─▶ { ok, occurrence_used, verified }
```

## Limitations

- **UI automation is inherently less stable than an API.** If Google reworks the editor, this can break until updated. The `verified` flag tells you whether the comment was actually observed after posting; contributions reporting UI changes are very welcome.
- The logged-in account needs **comment access** to the target doc.
- `find_text` must be a **single-line** fragment (the find bar is one line) and must match the document text exactly.
- An unused session expires after roughly 1–2 weeks; `status` tells you, `login` fixes it.
- Calls are serialized, so bulk commenting is sequential by design (typically a few seconds per comment).
- Automating your own Google account through its normal UI is your responsibility under Google's Terms of Service. Use your own account; don't use this for spam.

## Security

**What the AI agent (and the MCP client) can see.** Nothing sensitive. Sign-in happens in a real browser where you type your Google credentials directly to Google — the `login` step is a terminal CLI, *not* an MCP tool, so the model is never in that loop and never sees your password, 2FA, cookies, or OAuth tokens. During normal use the `add_comment` and `check_connection` tools return **structured status only** (`{ ok, anchored, occurrence_used, verified }` / `{ connected, mode }`) and **never any document content** — so a poisoned document can't smuggle instructions back into the model through this tool. The only things that reach the model's context are what the agent itself supplied (`doc`, `find_text`, `comment_text`) and, occasionally, a local file path inside an error message.

**Where the sensitive material actually lives.** Your **Google session cookies** sit in the profile directory (`~/.gdocs-comments-mcp/profile`), created with `0700` permissions — treat that directory like a password. It stays on disk and is never returned to the model. `logout` deletes it; you can also revoke server-side via [Google device activity](https://myaccount.google.com/device-activity). The optional audit log stores **hashes only**, never content. The one residual risk is ordinary local-machine hygiene: any other process with read access to that directory could reuse the session — that's not an MCP data flow, just standard local security.

**Containment.** Doc ids are strictly validated and navigation is hard-pinned to `docs.google.com` — the tool can't be steered to other sites.

## FAQ

**Can the Google Docs API or Drive API create anchored comments on a specific text range?**
No. The Google Docs API has no comment endpoints, and

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [stanislawherjan1](https://github.com/stanislawherjan1)
- **Source:** [stanislawherjan1/gdocs-comments-mcp](https://github.com/stanislawherjan1/gdocs-comments-mcp)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-stanislawherjan1-gdocs-comments-mcp
- Seller: https://agentstack.voostack.com/s/stanislawherjan1
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
