AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Google Docs Mcp

mcp-sundeepg98-google-docs-mcp · by Sundeepg98

MCP server that creates Google Docs with native Tabs (Oct 2024 sidebar feature) — for Claude Desktop and Claude Code

No reviews yet
0 installs
8 views
0.0% view→install

Install

$ agentstack add mcp-sundeepg98-google-docs-mcp

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-sundeepg98-google-docs-mcp)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Google Docs Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

appscriptly

> Workspace Automation MCP — generates persistent workflows (time-driven jobs, custom menus, reactive automations) that live IN your Google Workspace and run on Google's infrastructure. Also covers Docs / Sheets / Slides / Drive create + edit + read + retrofit.

[](https://github.com/Sundeepg98/google-docs-mcp/actions/workflows/test.yml) [](https://scorecard.dev/viewer/?uri=github.com/Sundeepg98/google-docs-mcp) [](https://www.python.org/downloads/) [](LICENSE)

Security posture: see [SECURITY.md](SECURITY.md) (disclosure policy) · [docs/security-posture.md](docs/security-posture.md) (narrative) · [docs/THREATMODEL.md](docs/THREATMODEL.md) (STRIDE + bounded blast radius) · [docs/asvs-level-1-checklist.md](docs/asvs-level-1-checklist.md) (OWASP ASVS L1 self-attestation).

> Note on the rename (2026-05-27): this project was previously published as google-docs-mcp. The original name reflected the Docs-first v1.0 scope; subsequent releases grew to cover six Google services + Apps Script-backed automation, so the rename to appscriptly matches the positioning. The Python module path stays at appscriptly (renaming would break every existing import); the CLI binary is now appscriptly with google-docs-mcp preserved as a backward-compat alias; gdocs_* tool names are unchanged (renaming would break existing claude.ai connector users); the Fly deployment is mid-migration with the legacy URL still live. See [docs/adr/2026-05-27-rename-to-appscriptly.md](docs/adr/2026-05-27-rename-to-appscriptly.md) for the staged plan.

appscriptly is the MCP server that puts the Apps Script automation moat behind a Claude-friendly interface. It creates and edits Google Docs with native sidebar Tabs (Google's October 2024 feature), losslessly retrofits existing .docx documents into tabbed format (preserving tables, drawings, and equations that text-only round-trips would destroy), and — the headline capability post-PR-α — installs a per-user Workspace Automation runtime so Claude can build persistent workflows that fire on a schedule, when data changes, or from a custom menu inside any of your docs / sheets / slides.

Tabs are a Google-Docs-native concept; they do not exist in the .docx / OOXML spec. Any pipeline that round-trips through .docx collapses to one tab. The only way to create or preserve Tabs programmatically is to call the Google Docs API directly — which is what this server does, packaged as an MCP server for Claude Desktop, Claude Code, and claude.ai custom connectors.

  • For end-users: see [docs/USERGUIDE.md](docs/USERGUIDE.md) to start using it with Claude Desktop / Claude Code / claude.ai — no install required if your operator has already deployed a connector URL.
  • For developers + operators: continue reading below.

Tested with: Claude Desktop, Claude Code, claude.ai custom connectors. Other MCP-speaking clients (Cursor, Zed, Windsurf, Cline, Continue) likely work but aren't in the test matrix — please file an issue if you hit client-specific surprises. ChatGPT Deep Research mode is NOT supported — that mode requires tools literally named search and fetch; our tool surface is prefixed (gdocs_find_doc_by_title, gdocs_read_doc). ChatGPT regular MCP mode works.


Works as: local stdio MCP (Claude Desktop / Code) or remote HTTP MCP (claude.ai custom connector via Fly.io). The cloud deployment is fully multi-tenant as of v1.1 — each user operates on their own Drive with their own Google identity.

Why this exists

Google Docs Tabs are a Google-Docs-native concept. They do not exist in the .docx / OOXML spec, so any pipeline that round-trips through .docx collapses to one tab. The only way to create tabs programmatically is to call the Google Docs API directly. This server wraps that flow + the supporting Drive / Sheets / Slides / Apps Script operations into 153 tools (primarily gdocs_*, plus gsheets_* / gslides_* / as_* for the newer services) covering the full lifecycle: create, edit, read, find, retrofit, trash/untrash, convert existing docs, one-shot per-user Apps Script Web App setup, plus Sheets / Slides editing and introspection tools that surface the server's CI test status over the MCP interface (so an agent can verify the running build was actually tested, not just trust a green badge). v1.3.0+: the server is self-documenting — connect-time instructions carry workflow choreography, and gdocs_guide() returns the same content as a structured payload. No external reference file required.

Tool index

Most tools are prefixed gdocs_; the Sheets / Slides verticals use gsheets_ / gslides_ and the appscriptly-native automation tools use as_. Call gdocs_server_info on a live server to get the authoritative list (all 153 tools) with descriptions.

| Purpose | Tool | |---|---| | Create from text (default for new content) | gdocs_make_tabbed_doc(title, tabs) | | Convert existing .docx or Google Doc | gdocs_tab_existing_doc(drive_file_id?, docx_path?, split_by?, markers?, ...) | | Preview what conversion would produce | gdocs_preview_tab_split(docx_path?/drive_file_id?, split_by) | | Add tabs to an existing doc | gdocs_add_tabs(doc_id, tabs, parent_tab_id?) | | Append to a tab | gdocs_append_to_tab(doc_id, tab_id, content) | | Rename / icon a tab | gdocs_rename_tab(doc_id, tab_id, title?, icon_emoji?) | | Set icons on multiple tabs by title | gdocs_set_tab_icons(doc_id, icons_by_title) | | Delete a tab | gdocs_delete_tab(doc_id, tab_id) | | Find/replace across tabs | gdocs_replace_all_text(doc_id, find, replace, tab_ids?) | | Read tab structure | gdocs_get_doc_outline(doc_id) | | Read body text (one tab or all) | gdocs_read_doc(doc_id, tab_id?) | | Find docs by title | gdocs_find_doc_by_title(query, exact?, include_trashed?) | | Trash / untrash (single or batch) | gdocs_trash_file(file_id) / gdocs_untrash_file(file_id) | | Move into a folder | gdocs_move_to_folder(file_id, folder_id) | | Get deep link to a tab | gdocs_get_tab_url(doc_id, tab_id) | | Sandbox upload URL (cloud chat) | gdocs_get_signed_upload_url() | | Install Workspace automation runtime (per-user, one-time) | gdocs_install_automation() | | Reset / revoke OAuth credentials (force re-consent) | gdocs_reset_authorization(full?) | | Server identity + CI test status | gdocs_server_info() | | CI test inventory + per-test outcomes | gdocs_test_manifest() | | Orientation: workflows + rules + tool groups (v1.3.0+) | gdocs_guide() | | LLM error-recovery lookup (v2.2b+) | gdocs_help(error_message) |

Self-evidencing CI gate (v1.2+)

gdocs_server_info returns a test_suite block that lets any caller verify the running build was actually tested — not just trust an opaque count. Four layers:

| Layer | Field | Proves | |---|---|---| | Count not faked | test_suite.report_digest | sha256 of canonical test-results.json; runtime recomputes and compares — mismatch → status: "tampered" | | CI actually ran | test_suite.ci_run_url | URL of the GitHub Actions run that produced this artifact ("local" for manual ./deploy.sh deploys, never empty) | | Right tests exist | gdocs_test_manifest() | full test inventory + outcomes + named-regression-guard presence check | | Tests catch bugs | test_suite.mutation_check | {ran, caught, status, asleep_guards, stale_patches, imprecise_patches} — CI applies known bug patches per build, runs the full unit suite per patch, and fails if any patch is asleep / stale / over-broad |

Every push to main flows through GitHub Actions: unitmutationdeploy. A commit that breaks any test can't reach production. The mutation gate itself is self-checking — stale_patches flags mutations whose find text moved out from under them (preventing silent "caught" reports for bugs never actually injected); v1.2.2 added that. See .github/workflows/deploy.yml, scripts/mutation_check.py, and the CHANGELOG for the full story.

Setup — local stdio (Claude Desktop / Claude Code)

Requirements

  • Python 3.10+
  • A Google Cloud project with the Google Docs API and Google Drive API enabled
  • An OAuth 2.0 Client ID of type Desktop app (downloaded as JSON from Cloud Console → APIs & Services → Credentials)
  • (Optional, for convert/retrofit only) An Apps Script Web App — see [Apps Script setup](#apps-script-setup-required-for-converting-existing-docs)

Install

With pipx (isolated, single global command — recommended):

pipx install git+https://github.com/Sundeepg98/google-docs-mcp.git

Or clone for dev:

git clone https://github.com/Sundeepg98/google-docs-mcp.git
cd google-docs-mcp
python -m venv .venv && source .venv/bin/activate    # or .venv\Scripts\activate on Windows
pip install -e ".[test]"

OAuth client config

The server looks for the OAuth client config (JSON from Cloud Console) in this order:

  1. Path in GOOGLE_DOCS_OAUTH_PATH env var
  2. ./credentials/credentials.json (relative to cwd)
  3. ~/.gmail-mcp/gcp-oauth.keys.json (reuse existing gmail-mcp keys — same Cloud project)

User tokens cache at ~/.google-docs-mcp/token.json (override with GOOGLE_DOCS_DATA_DIR).

Wire to Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "appscriptly": { "command": "appscriptly" }
  }
}

(The "appscriptly" key is the label that shows up in Claude's UI — pick whatever you want, the command must match the installed CLI binary. Pre-rename installs that use "google-docs": { "command": "google-docs-mcp" } keep working — both appscriptly and google-docs-mcp are installed as CLI binaries; see [pyproject.toml](pyproject.toml) [project.scripts]. The legacy google-docs-mcp alias stays through v3.0.)

For dev installs, point at the venv entry-point: /abs/path/repo/.venv/bin/appscriptly (or .venv\Scripts\appscriptly.exe on Windows).

Restart Claude Desktop. The gdocs_* tools should appear.

Wire to Claude Code

Add the same mcpServers entry to ~/.claude.json (user-scope) or to a project's .mcp.json (project-scope). Run /mcp and reconnect.

First-run OAuth

First tool call opens the browser. Sign in → grant scopes. Tokens cached after that; no more browser dance. Required scopes (mirror of auth.py:WORKSPACE_SCOPES, the single source of truth):

  • https://www.googleapis.com/auth/documents
  • https://www.googleapis.com/auth/drive.file
  • https://www.googleapis.com/auth/spreadsheets
  • https://www.googleapis.com/auth/presentations
  • https://www.googleapis.com/auth/forms.body
  • https://www.googleapis.com/auth/forms.responses.readonly
  • https://www.googleapis.com/auth/tasks
  • https://www.googleapis.com/auth/script.projects
  • https://www.googleapis.com/auth/script.deployments
  • https://www.googleapis.com/auth/calendar
  • https://www.googleapis.com/auth/contacts
  • https://www.googleapis.com/auth/gmail.send — send email on the user's behalf (Gmail; sensitive, send-only, no mailbox read)
  • https://www.googleapis.com/auth/gmail.labels — manage Gmail labels (create/list/delete label objects; non-sensitive)
  • https://www.googleapis.com/auth/contacts.other.readonly — read auto-saved "other" contacts (sensitive, read-only)
  • https://www.googleapis.com/auth/script.processes — read Apps Script execution history (sensitive, read-only)

Every one of these is a Google sensitive scope (except gmail.labels, which is non-sensitive); none is restricted, so the app needs sensitive-scope OAuth verification but no CASA security assessment. The four most recent (gmail.send, gmail.labels, contacts.other.readonly, script.processes) were added together as CASA-free scope growth so the verification covers the maximal app in one pass — each was checked against Google's restricted-scope list and confirmed not restricted. In particular the broad/read Gmail scopes (mail.google.com, gmail.readonly, gmail.modify, etc.) and drive.readonly (Google's only RESTRICTED scope this app ever requested) are deliberately NOT requested, to preserve the no-CASA posture (see auth.py:WORKSPACE_SCOPES for the per-scope rationale and the drive.readonly removal note). The HTTP/cloud connector flow additionally requests openid + userinfo.email for identity, for 17 scopes total; see oauth_google.py:GOOGLE_API_SCOPES.

> Verification posture (why the code lists more scopes than the consent screen currently under review shows). The live OAuth verification round currently covers the base set (Docs / Drive.file / Sheets / Slides / Apps Script + identity). The additional sensitive services (Calendar, Tasks, Forms, Contacts, Gmail send + the contacts.other.readonly / script.processes reads) reach existing users via Google's incremental-consent flow (include_granted_scopes=true), and their live rollout is held back by the CI deploy gate (DEPLOY_ENABLED repo variable set to false, which halts auto-deploy on push to main) until their own verification round (this project verifies LAST, after the surface is complete). So auth.py:WORKSPACE_SCOPES legitimately enumerates the full target set in code while the consent screen currently under review shows the subset already submitted. None of the additional scopes is restricted, so they add no CASA requirement. Each new scope still needs a demo scene in the verification recording (handled separately in the recorder).

Apps Script setup (required for converting existing docs)

gdocs_tab_existing_doc and the retrofit path use a helper Apps Script Web App for lossless content restructuring (tables, drawings, cell shading — content REST can't re-emit). Skip this section if you only use gdocs_make_tabbed_doc and edit tools.

Automated (recommended)

google-docs-mcp setup-apps-script-auto

Does everything end-to-end via the Apps Script REST API: creates the project, pushes restructure.gs (with a per-deployment HMAC key baked in), deploys as a Web App with executeAs: USER_DEPLOYING / access: ANYONE_ANONYMOUS, and saves the resulting /exec URL to ~/.google-docs-mcp/config.json. The endpoint is anonymous because the server posts with no Google sign-in, but every request is authenticated by a per-deployment HMAC signature verified in doPost (v2.0c; see docs/THREAT_MODEL.md §4 row 5) — URL secrecy is no longer the access control. First run triggers one OAuth consent screen to add Apps Script scopes (script.projects, script.deployments); subsequent runs reuse the token.

The plumbing lives in src/appscriptly/gas_deploy/ as a clean sub-package boundary — if a second project ever needs Apps Script project management, that folder can be git mv'd out and published as a standalone package.

Manual (fallback)

If the automated path doesn't work (e.g. you can't run a local browser OAuth flow), print the manual recipe:

google-docs-mcp setup-apps-script    # prints step-by-step UI instructions
# then after deploying via the UI and copying the URL:
google-docs-mcp configure-webapp https://script.google.com/macros/s/.../exec

Advanced: headless via Service Account + Domain-Wide Delegation

For CI pipelines, server-side batch document processing, or IT-managed multi-user provisioning — anywhere no human can click an OAuth consent. Google Workspace only (personal @gmail.com accounts have no Admin Console and cannot use DWD).

One-time admin setup:

  1. Create a Service Account in GCP, download its JSON key
  2. Admin Console → Security → Access and data control → API controls → Manage Domain Wide Delegation

Source & license

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

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

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.