gdocs-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GDOCS_DEFAULT_ACCOUNT | No | Sets which authorized account this project uses by default. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_accountsA | List the Google accounts that have been authorized for this server. |
| set_project_defaultA | Write this project’s defaults to a .gdocs-mcp.json in the current working directory (or update an existing one up the tree). Set a default account and/or a default folder (URL or id). The folder is where write_doc is told new docs go: a new doc given as a bare name or at the top of My Drive is refused once, naming the folder and the full path to call. It is read when the server starts, so write_doc’s description shows a change after a restart; the refusal reads it fresh. To set a folder by name, find it first with drive({ cmd: 'find' }) and pass its id. |
| get_project_configA | Show the effective .gdocs-mcp.json defaults (account/folder) for the current working directory, and where the file is. |
| read_docA | Read a Google Doc as markdown + inline HTML. The read opens with a block — one CSS rule per named style (p = Normal text, h1–h6, .title, .subtitle), in pt — and a paragraph or run shows style="…" only where it differs from its rule (text-align, line-height, margin-top/bottom/left/right, text-indent; a hanging indent is margin-left:36pt with a negative text-indent). Title and Subtitle paragraphs read as . A page break reads as on its own line, where the break is. Every element in a paragraph reads, so an edit that quotes one can give it back: a footnote is [^1] with its note as a [^1]: line at the end; a date is Nov 15, 2026; a person or a link chip is Jane Doe (the text is Google’s); a dropdown is with its list as a Draft line after the block; a horizontal rule is --- on a line of its own; a column break is ; an equation and a page-number field are empty and whose title says to edit them in Google Docs. A table of contents is not read. List items show no indent: their nesting owns it. mode: clean (committed text, default) · tracked (suggestions shown as /) · accepted · rejected. segment picks the content tree: body (default), header, footer, or all (body plus every header/footer, each labelled). Text that would otherwise read as markup is marked as literal: a paragraph wrapped in … ("4. Term" is a paragraph, not a list) or a backslash before a character (5 * 3), and \ is a real backslash — write them back as read, and the document keeps only the words. A body read always reports which headers/footers exist and what they hold, since their content — a letterhead logo, a page number — is NOT part of the body and would otherwise be invisible. |
| edit_docA | Replace an exact unique snippet of text in a Google Doc (like a local file Edit). old_string is matched markup-tolerantly; ambiguous matches return surrounding context to disambiguate; a table is matched as its rows, in the form read_doc shows it (a pipe table, or the HTML of a styled one). Elements read_doc shows are kept when old_string and new_string both hold them as read (a person chip inside a sentence you reword survives), deleted when new_string leaves them out, and created when new_string adds one: [^label] with a [^label]: note line, Nov 15, 2026 (the text’s shape picks the date format), for a person or for a Drive file, with its line, and --- for a rule. A column break, equation, page-number field, or link chip to anything but a Drive file cannot be made: it is refused before anything is sent, and a chip’s text is Google’s (a chip given other words is refused). A footnote’s note is edited by quoting its [^1]: line, and a dropdown’s list by quoting its line. INSERTING IS AN EDIT: quote the text to add after (or before), write it back in new_string, and add the new content to it. Text from old_string that comes back unchanged is kept as it is, with its style, comments and suggestions, so old_string |
| get_page_setupA | Read a doc’s (or tab’s) page setup — margins, page size (in points, plus a preset name if it matches letter/legal/a4/tabloid), and orientation. The read counterpart to set_page_setup; use it to mirror another document’s layout onto a new doc. |
| set_page_setupA | Set document-level page setup for a doc (or tab): page margins, page size, and orientation — the File > Page setup controls. Margins and explicit page sizes are in points (72 pt = 1 inch). pageSize is a preset (letter/legal/a4/tabloid) or an explicit {width,height} in points; orientation (portrait/landscape) swaps the page dimensions. Always a direct change: page geometry is a document-style change, so there is no suggest option. |
| download_imagesA | Download every embedded image in a Google Doc to a local folder. Returns the objectId→filename mapping, which correlates with read_doc’s |
| list_suggestionsA | List the pending suggestions (tracked changes) in a Google Doc, in document order. Each has an |
| apply_suggestionsA | Accept or reject pending suggestions (from list_suggestions) in one update. Each one is resolved on its own, exactly as clicking the check or the cross in Docs: accept keeps the proposed change, reject restores the original. Two suggestions that touch each other (by different people) are decided one at a time, and the text comes out as Docs makes it; to decide them together, pass both. A style-only suggestion resolves like any other. expectTitle is checked against the live document first (status "wrong_doc" on a mismatch, e.g. an id from a different, similarly-titled document), and each expectContext is checked against the live suggestion (status "error" on a mismatch or an id that is gone); nothing is changed unless all match. Pass the |
| list_commentsA | List the comments on a Google Doc, each with the text it is on ( |
| add_commentA | Comment on text in a Google Doc: |
| resolve_commentA | Resolve (or reopen) a comment thread by comment id. expectQuotedText is REQUIRED: the |
| export_docA | Export a Google Doc to a real file on disk — pdf (default), docx, odt, rtf, txt, html, epub, or md. Google renders it server-side (File > Download in the UI), so page setup, pagination and layout match the editor. A doc path exports every tab; a tab path (/folder/doc/tab) exports only that tab, through an endpoint Google does not document and rate-limits — if it fails the call is refused and says so, it never falls back to the whole doc. Returns the local path and byte size. Note: Drive refuses to export files larger than 10 MB. |
| write_docA | Write markdown-rendered content to a path, like the local Write tool. A path that names nothing is CREATED and never asks, but only an absolute path (or a Drive id or URL start) creates: a bare name like Contract is refused with the full path to call. When the project has a default folder for new docs, a new doc at the top of My Drive (/Contract) is refused once too, with the default folder’s full path to call, so the user is told where it goes first; the same call repeated goes through: /Work/Contract creates a doc in the folder /Work, /Work/Contract/Notes a tab in that doc, /Work/Contract/Part 2/Ch.4 a child tab under Part 2 (only the last step may be new; make the folder with drive mkdir first). A path that names something is REPLACED, and the first call is refused with a loss summary — the paragraphs of text and everything a read cannot carry that the replace would take with it: comments, suggestions, tab stops, links to bookmarks, section breaks, a table of contents, column breaks, equations, page-number fields, a date in a format the API can only read, and a link chip to anything but a Drive file — plus a confirmLoss string. Ask the user before anything else — show them what would be lost and wait for a yes; never pass confirmLoss on your own. Only after their yes, call again with the same content and confirmLoss set to that string exactly. If the doc changed in between, the string no longer matches and the call is refused again with a fresh summary. A doc with several tabs needs a tab step (the refusal lists them); a doc with one tab means that tab. Nothing to lose, nothing to ask: an empty doc, tab, header or footer is written without the refusal. segment: "header" or "footer" writes the page header or footer of an existing doc instead of its body: a missing default one is created and written, an existing one with content is replaced after the same confirmLoss round-trip, and a missing first-page or even-page one (page: "first" / "even") is refused with the instruction to turn on Different first page in Docs. Replacing keeps the doc’s title, sharing and other tabs but the new paragraphs start unstyled, so anything not in the markdown (including indents) is gone; prefer edit_doc to change a document, which keeps everything its anchor does not cover. Style is CSS, in the spelling read_doc emits: a leading block sets the named styles (p, h1–h6, .title, .subtitle), / / style a paragraph, a run. Supported: text-align, line-height, margin-top/bottom/left/right, text-indent (pt; text-indent is relative to margin-left), and on spans/rules font-family, font-size, font-weight, font-style, text-decoration, color. Any other property fails the whole write before anything is sent, listing every offending line. Footnotes, dates, person chips, Drive link chips and dropdowns are written back as read_doc spells them ([^1] and a [^1]: note line; ; ; with its line); --- is written as an empty paragraph with a thin grey bottom border. A new column break, equation, page-number field, or link chip to anything but a Drive file (YouTube, Calendar, Maps, a web page) is refused before anything is sent: the API cannot make it, so write text for a link, or ask the user to insert the rest in Google Docs. A chip’s text is Google’s, so a chip given other words is refused. A page break is on a line of its own (also accepted: , break-before: page, break-after: page); any other or is refused. For long documents, pass contentFile instead of content so the server reads the body directly (retyping a long doc inline can silently drop text). Returns images ({src, objectId}) for pushed images. suggest: true sends the replace as suggestions for a person to accept or reject in Docs, and never asks for confirmLoss: nothing is lost until a person accepts, and rejecting brings back the text, images, tables and comments as they were. It needs a path that already names something (a new doc or tab cannot be a suggestion), refuses a table column width (Docs cannot suggest one) before anything is sent, and lists the suggestion ids in |
| driveA | Navigate and reorganise Google Drive with shell commands: ls, find, mkdir, cp, mv. Arguments are positional and follow the usual shell forms. ls [path] — list a folder (default My Drive root). find [-type d|f] — search everything by name, including files no path can reach. mkdir [-p] — create a folder. cp — duplicate a file (preserves headers/footers, image sizing and exact formatting, which a markdown round-trip cannot rebuild). mv — move and/or rename, as on a filesystem: an existing folder as means "into it", anything else means "to that name". Paths start with / or ~ (My Drive); /shared/ is a shared drive, /shared-with-me the files others shared with you, and /lost+found the files you own that are in no folder at all. Anything not starting with / or ~ is read as a Drive id or URL, so ids from any other tool can be pasted straight in. Drive permits two files with the same name in one folder and folds case when matching, unlike any real filesystem — a path that matches more than one thing is refused with the candidates listed, never guessed. A doc is a folder of tabs: ls lists its tabs, ls shows each doc with its tab count, and a path continues into tabs (/Work/Contract/Part 2/Ch.4; a tab step may also be a tabId). mv on a tab renames it, nests it (dst is another tab, or a new name under one) or un-nests it (dst is the doc), and |
| list_permissionsA | List the permissions on a Google Doc (people, groups, domain, anyone-with-link) with their roles. Each entry carries a |
| share_docA | Grant access to a Google Doc. With |
| unshare_docA | Revoke a grant on a Google Doc. Pass |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 19 tools
Most tools target clearly distinct resources or actions: document reading, snippet editing, comments, suggestions, permissions, page setup, and Drive navigation are well separated. The main potential confusion is between write_doc and edit_doc for writing markdown, and read_doc versus export_doc, though the descriptions make the intended boundaries mostly clear.
Nearly all tools use a consistent snake_case verb_noun pattern such as read_doc, edit_doc, list_comments, add_comment, and share_doc. The single noun-only tool, drive, is a deliberate command multiplexer but is the one clear deviation from the pattern.
At 19 tools the surface is slightly heavier than the ideal compact set, but the server covers a broad Google Docs domain including editing, comments, suggestions, sharing, page setup, export, Drive navigation, and configuration. Each tool corresponds to a meaningful operation, and drive usefully bundles several filesystem commands.
The tool set covers the core document lifecycle well: create, read, edit, replace, export, comments, suggestions, sharing, page setup, images, and Drive navigation. Notable gaps remain around deleting documents, tabs, or comments and around revision history, but these are relatively minor for the main Docs workflows.