Docs Bridge
Allows agents to read, write, format, fill, replace, and human-like type in Google Docs through a signed-in Chrome session. Supports markdown, document structure/outlines, templates, sections, tables, lists, styles, find-and-replace, creating/copying/exporting/renaming/listing/opening docs, and verification of changes against the saved document.
Allows agents to read, build, edit, fill, type into, and export Google Slides decks. Supports outlines, numbered shapes and roles, slide creation/duplication/moving/deletion, body markdown to real Slides lists, speaker notes, find-and-replace, formatting, menu commands, and verification against the saved deck or exported .pptx.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Docs Bridge fill the {{client}} placeholders in my proposal template doc"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Docs Bridge
Docs Bridge is an MCP server that lets agents read, write, format, and fill in Google Docs — and read, build, edit, fill and export Google Slides decks — as you. It runs through your own signed-in Chrome, so it needs no API keys, no OAuth app, no Google Cloud project, and never copies cookies.
It works the Docs editor the way a person does. It selects text, types, presses the shortcuts, and uses the toolbar and menus, all in a background tab that never takes focus. So it can do what you can: headings in the document's own styles, bullet and numbered lists, tables, fonts, colors, page breaks, any menu command, and templates.
It has two parts:
extension/is a Manifest V3 Chrome extension that runs in your real Chrome profile.server/is a zero-dependency Node MCP server (stdio). Every MCP client on the machine can launch it. They all share one loopback hub, and the extension connects to that hub.
Install
Needs Node 20+ and Chrome 121+ (or another Chromium browser that loads
unpacked MV3 extensions). The server has no dependencies, so there is nothing
to npm install unless you want the end-to-end tests.
Clone the repo:
git clone https://github.com/dylansantwani/docs-bridge.gitIn
chrome://extensions, turn on Developer mode, click Load unpacked, and pick theextension/folder. The extension id is pinned tonkfcgpojlaedgadaoopckngjoheifiedby the manifest's public key, and the server accepts only that origin. After pulling new code, click the extension's reload icon (or runnode server/index.js --reload-extension).Register the server with your MCP clients. For Claude Code:
claude mcp add docs-bridge -s user -- node /path/to/docs-bridge/server/index.jsFor clients configured with JSON (Claude Desktop, Cursor, and others):
{ "mcpServers": { "docs-bridge": { "command": "node", "args": ["/path/to/docs-bridge/server/index.js"] } } }Check the connection:
node /path/to/docs-bridge/server/index.js --health
Docs Bridge was built and verified live on macOS. Shortcuts map Cmd to Ctrl on other systems, but Windows and Linux have not been tested against the live editor.
Related MCP server: Google Docs & Gmail MCP Server
Tools
Tool | What it does |
| Reads a doc as markdown, text, or html. |
| Types markdown in the document's own styles. Modes: |
| Formats existing text, a section, or the whole doc: bold, italic, underline, strikethrough, super/subscript, font, size, color, highlight, link, heading/title/subtitle/normal style, alignment, lists, indent, line spacing |
| Runs a sequence of human-style steps: find/select, move the caret, select paragraphs or sections, type, delete, press keys, format, run any menu command by path (e.g. |
| Runs Docs' own Find and replace |
| Types like a person: one keystroke at a time at a human pace, with rhythm, thinking pauses, and typos fixed with Backspace. Same positions as |
| Status, list, wait, pause, resume, or cancel |
| Fills a template: text replacements (placeholders or sample text, keeping their formatting) plus whole sections replaced by heading |
| Lists Google's template gallery (resumes, letters, proposals, meeting notes, newsletters…) |
| Creates a blank doc (with an optional markdown body), or a named copy of a gallery template or any doc |
| Makes a copy of any doc with a new title |
| Lists recent docs, or runs a Drive search |
| Rename a doc; save it as docx/pdf/odt/rtf/epub/md/txt/html; open it for you; check the connection |
Google Slides
Tool | What it does |
| Reads a deck as saved in Drive. |
| Adds slides (layout, title, subtitle, body, notes) or changes existing ones: any of those, other shapes by number, skip, move, duplicate, delete. Body markdown bullets, numbering and nesting become real Slides lists, typed in the theme's own styles |
| Creates a deck — blank or copied from any template deck — and fills it with slides in the same call |
| Slides' own Find and replace; |
| Human steps for anything else: go to a slide, select a shape (by number or role), select text in it, type, format (bold, italic, size, font, colour, lists, alignment), keys, any menu command ( |
| Types into a title, subtitle, body, any shape or the speaker notes like a person — keystroke by keystroke, same rhythm/pause/typo model and profiles as |
| pptx, pdf, odp, txt, or one slide as png/jpeg/svg |
| As for docs |
Every tool takes account, either an index as in /u/N/ URLs or an email
address, for a second signed-in account such as school.
A typical template flow:
docs_create { title: "Weekly sync 10/1", template: "Meeting notes (Tropic)" }
docs_read { doc: <id>, format: "structure" } # see its sections and sample text
docs_fill { doc: <id>,
replace: { "Annual Board Meeting": "Weekly Team Sync", "Friday, 09.04.20XX": "Wednesday, Oct 1" },
sections: { "Attendees": "Dylan Santwani\n\nPat Doe", "Action Items": "- [ ] Ship the bridge" } }
docs_format { doc: <id>, text: "Ship the bridge", format: { bold: true, color: "red" } }Every change is verified. After a write, the extension polls the document as saved in Drive until it shows the change. For formatting, it also checks the formatting itself: bold, sizes, fonts, colors, links, paragraph styles, alignment, and lists are read back from the saved copy. If something doesn't show up, the result says NOT verified and names what's missing.
A typical Slides flow:
slides_create { title: "Q4 kickoff", slides: [
{ title: "Q4 kickoff", subtitle: "Team sync · Oct 14" },
{ title: "Goals", body: "- Ship Slides support\n - read, write, type\n- Fix the backlog", notes: "Keep it short" },
{ layout: "Title and two columns", title: "Now vs next", shapes: { "2": "**Now**\n- …", "3": "**Next**\n- …" } } ] }
slides_read { deck: <id> } # numbered shapes, roles, notes
slides_write { deck: <id>, slides: [ { slide: 2, body: "- Ship it" }, { after: 2, layout: "Section header", title: "Details" } ] }
slides_replace { deck: <id>, replacements: { "{{name}}": "Dylan", "{{date}}": "Oct 14" } }
slides_edit { deck: <id>, steps: [ { slide: 2 }, { shape: "body" }, { selectText: "Ship it" }, { format: { bold: true, color: "red" } } ] }
slides_type { deck: <id>, slide: 3, shape: "notes", mode: "append", text: "Typed like a person." }Slide changes are checked against the deck as saved in Drive: the exported .pptx, parsed in the extension, must show the typed text in the right shape of the right slide, the speaker notes, the slide count and layouts; formatting, moves and menu commands must change the saved deck.
Typing like a person
docs_type puts text in the way a person at the keyboard would, instead of
pasting it. Every character is a real key press in the editor, so Docs'
own autocorrect (smart quotes, list and link detection, capitalisation)
applies, and the document's revision history fills in keystroke by
keystroke.
docs_type { doc: <id>, mode: "append", markdown: "## Notes\n\nFirst **draft** of the intro…" }
docs_type { doc: <id>, text: "…", profile: "careful", wpm: 40, pauses: 1.5 }
docs_typing { action: "status" } # progress, ETA, verification
docs_typing { action: "pause" } # stops at the end of the current word
docs_typing { action: "resume" }Rhythm. A base interval from
wpm(5 keys per word) with log-normal jitter and a slow drift. Common letter pairs are faster; capitals, digits, and punctuation are slower.Pauses. After sentences and commas, before each paragraph (the longest), and the odd hesitation mid-sentence or before a long word.
pausesscales them (0 turns them off).Typos. A neighbouring key, swapped letters, a doubled or skipped letter. The typist notices after 0–3 more letters, backspaces and retypes. A typo is always fixed before its word ends, because Docs autocorrects a misspelled word when its space is typed.
Formatting. Headings and lists use Docs' shortcuts, bold, italic, and strikethrough are toggled with Cmd+B, Cmd+I, and Cmd+Shift+X while typing. Links, code, and emoji can't be typed, so they are pasted.
Tables. A tab in
markdownpresses the Tab key, which moves to the next table cell. To fill an empty table, put a placeholder in its first cell andreplace_textit with the cells separated by tabs ("Parameter\tUnits\t…"); continue later withreplace_texton the last cell typed ("8.5\tpH\t…"), retyping it so the text never starts with a tab (markdown would read that as code).textstill turns tabs into spaces. Pasted tables get full-width columns and borders, so an empty table is ready to type into.Profiles.
natural(55 wpm, 2% typos),careful(38 wpm, 0.8%),fast(85 wpm, 3%),steady(60 wpm, no typos, few pauses).wpm,typos(false or a rate per letter),pauses, andseedoverride them.Long text. Under two minutes of typing, the call waits and reports the verified result. Longer text runs as a job in the extension and keeps going after the call returns, even if the MCP client exits. It types in chunks of up to 90 s. Each fresh background tab gets about four minutes before Chrome throttles it, so the job moves to a new tab and finds its place again: at the end of the document, or by Find on the text typed so far in the paragraph. Before it leaves a tab, it waits for Drive to save. Jobs are saved after every chunk. If the extension restarts in the middle of one, the job shows as interrupted and can be resumed.
Verified. When a job finishes, the saved document must contain its text. Letters and digits are compared, since autocorrect changes quotes and dashes.
Don't edit the spot being typed into while a job runs. Other docs_* calls on the same document are fine: they run between chunks, and the job finds its place again afterwards.
How it works
Everything happens in a background tab that is never activated. These tabs are kept in a collapsed "Docs Bridge" tab group.
Typing in the document's styles. New content is typed block by block. Each paragraph gets its style with the real shortcut (Cmd+Alt+2 for Heading 2), lists are started with Cmd+Shift+8/7/9 and nested with Tab, and text arrives as an inline paste. That way it takes the document's own heading, body, and list styles, which matters for templates. Pasting whole blocks of HTML would instead bring in browser-default styling.
Selecting like a person. Text is selected through Docs' own Find and replace. Paragraph moves and selections use Alt+Up/Down.
Toolbar and menus. These respond to synthetic mouse events. The toolbar also reports the caret's style, font, size, and list state.
Reading. Reads use Docs' export endpoint, fetched from the service worker. Writes are checked against the saved copy at
/mobilebasic.Slides. The same editor family: keys and pastes go to the same hidden input, shapes are SVG groups (
#editor-<objectId>) that select on a synthetic click, Enter puts the caret in a shape's text, and Slides' own copy handler, fed a syntheticcopyevent with a private DataTransfer, returns the exact text of what is selected — so every write is read back without touching your clipboard, and nothing is pasted unless the caret is confirmed to be in text (a stray paste would create a new text box). Slides are reached through the filmstrip, layouts through Slide > Apply layout, notes through Cmd+Alt+Shift+S. Reads parse the exported .pptx (a small zip and XML reader, no dependencies).
AGENTS.md lists every Docs behavior this depends on. All of them were
verified live, including the background-tab timer throttling the code works
around.
Security
The hub listens on 127.0.0.1 only.
The
/extendpoint accepts only the pinned extension origin, so web pages can't connect.Peer servers on
/mcpneed the 0600 token in~/.docs-bridge/token, and any request that carries an Origin header is refused.Non-loopback Host headers are refused.
The extension's host access is limited to docs.google.com, drive.google.com, and googleusercontent.com.
Limits
No comments yet, and no switching to suggesting mode. If your mode in a doc is Suggesting, edits land as suggestions.
Sections that contain a table can't be replaced as a whole. Edit them with anchors, or with
docs_editplus Tab between cells.Colors and fonts outside the palette or font menu are applied by re-pasting the found text, which drops other formatting inside that text.
Speed: each anchored step takes about 1–3 s, because Chrome aligns background-tab timers to one-second boundaries.
Typing jobs need Chrome running with the extension. If a tab hangs mid-chunk, the job is interrupted. Resuming it may retype the last few words from that chunk, so read the document first.
Drive storage: if your Drive is full, new docs and copies fail.
Slides: no images, charts, new text boxes or shape positioning yet (use
slides_editwith menus for what the menus can do). Shapes are addressed by number and role; the export renumbers object ids, so ids from the editor are not shown. Replacing a box whose old text began with manual bold keeps that bold for the first new word (the caret's style after deleting). Google rate-limits exports under heavy use; reads and checks retry with backoff. Speaker notes are verified from the saved deck, since the notes panel can be collapsed.
Development
npm test # 275 unit/protocol tests, no browser
npm run test:e2e # real Chromium + the extension + live docs.google.com (signed out, public doc and deck)
node scripts/page-harness.mjs write > /tmp/h.js # self-tests to run inside a SCRATCH doc
node scripts/page-harness.mjs template > /tmp/h.js # …inside a copy of "Meeting notes (Tropic)"
node scripts/page-harness.mjs type > /tmp/h.js # human typing, chunk stop + resume by Find
node server/index.js --call docs_type '{"doc":"<id>","text":"hello"}' # any tool from the shell
node server/index.js --op slides_deck '{"id":"<deck id>"}' # one raw extension operation, as JSON
node server/index.js --reload-extension # load new extension code (refused while a typing job runs)A harness is too large to paste in one go, so load it through a file input.
With openbrowser: add an <input type=file> to the page, attach the file with
browser_upload, then (0, eval) its text. AGENTS.md describes the steps.
Available Tools
27 toolsdocs_copyB
Make a copy of a Google Doc (Docs' own "Make a copy") with a new title. Returns the copy's URL.
Inputs: doc (required), title, account.
docs_createA
Create a new Google Doc with a title — blank with an optional markdown/text body, or from a template: a gallery template name (see docs_templates, e.g. "Meeting notes" or "Resume (Coral)") or any document to copy. Fill a template afterwards with docs_fill.
Inputs: title (required), text, account, markdown, +1 more.
docs_editA
Edit a Google Doc as a sequence of human steps in the real editor: select text (find) or move the caret, select paragraphs/sections, type markdown or inline text, delete, press keys (Tab moves between table cells), format, run any menu command by path, undo. Use it for anything docs_write/docs_format do not cover — table rows and columns, page breaks, table of contents, headers, etc. Steps run in order in one tab; the result reports each step and whether Drive shows the changes.
Inputs: doc (required), steps (required), account.
docs_exportA
Download a Google Doc to a local file as docx, pdf, odt, rtf, epub, markdown, text or html.
Inputs: doc (required), path (required), format (required), account, +1 more.
docs_fillA
Fill in a template document. replace: exact text → new text for placeholders or sample text (every occurrence, keeping its formatting). sections: heading text → markdown that replaces everything under that heading, typed in the template's styles. Reports each item.
Inputs: doc (required), account, replace, sections, +1 more.
docs_formatA
Format existing text in a Google Doc like a person would: select a target (exact text, a section under a heading, or the whole document) and apply bold/italic/underline/strikethrough, font, size, colour, highlight, link, paragraph style, alignment, list, indent or line spacing. Verified against the saved document.
Inputs: doc (required), format (required), all, text, +4 more.
docs_listA
List Google Docs: recent documents, or a Drive search when query is given. Returns titles, ids, owners and modified dates.
Inputs: limit, query, account.
docs_openA
Open a Google Doc in a foreground Chrome tab for the user to look at. Doesn't change the document.
Inputs: doc (required), account.
docs_readA
Read a Google Doc: markdown (default), text, html, or "structure" — an outline of titles, headings/sections, list items, tables with cells and placeholders, for planning edits. Long documents are paged with offset/maxChars.
Inputs: doc (required), format, offset, account, +1 more.
docs_renameB
Rename a Google Doc (change its title as shown in Drive).
Inputs: doc (required), title (required), account.
docs_replaceA
Find and replace across a whole Google Doc using Docs' own Find and replace (keeps surrounding formatting). Returns how many were replaced.
Inputs: doc (required), find (required), replace (required), regex, +2 more.
docs_statusA
Check that the Chrome extension is connected and report the bridge state. Call this first when another docs_* tool fails with a connection error.
Inputs: no named parameters.
docs_templatesA
List Google Docs' template gallery (resumes, letters, reports, proposals, meeting notes, newsletters, …) with names and styles, for docs_create's template.
Inputs: account.
docs_typeA
Type into a Google Doc like a person: one keystroke at a time in the real editor, at a human pace with natural rhythm, pauses between sentences and paragraphs, and occasional typos corrected with Backspace. Same positions as docs_write (append, prepend, replace_document, insert_after/insert_before/replace_text an anchor, replace_section). Markdown headings, lists and quotes are set with Docs' own shortcuts, bold/italic/strikethrough are toggled with Cmd+B/I/Shift+X as you type; links, code and emoji are pasted. Short text finishes before this returns; longer text keeps typing in the background (in Chrome, even if this call ends) — the result gives a job id for docs_typing and an ETA. Speed: 55 wpm types ~275 characters a minute.
Inputs: doc (required), wpm, mode, seed, +11 more.
docs_typingA
Check or control docs_type jobs: status (progress, ETA, verification), list, pause, resume, cancel. A paused or interrupted job resumes where it stopped. Without job, acts on the most recent one.
Inputs: job, action.
docs_writeA
Write markdown (or plain text) into a Google Doc, typed in the document's own styles. Modes: append, prepend, replace_document (overwrites the body), insert_after / insert_before / replace_text (relative to an exact anchor snippet; replace_text with empty text deletes it), replace_section (anchor = heading text; replaces everything under that heading up to the next heading of the same or higher level). Markdown: headings, bold/italic/code/links, bullet/numbered/task lists with nesting, quotes, code blocks, tables, rules, images (), and \pagebreak on its own line. The result says whether Drive has the change.
Inputs: doc (required), mode (required), text, anchor, +5 more.
slides_copyC
Make a copy of a presentation with a new title.
Inputs: deck (required), title, account.
slides_createB
Create a Google Slides presentation, optionally from a template deck (any deck URL or id: it is copied), and optionally fill it with slides in the same call. For a new blank deck the first entry fills its existing title slide (give it a layout to change that), the rest are added after it.
Inputs: title (required), slides, account, template.
slides_editA
Edit a presentation with human steps, for what slides_write does not cover: go to a slide, select a shape (by number or role), select text inside it, type over it, format it (bold, italic, size, font, colour, lists, alignment), press keys, run any menu command ("Slide > Change background", "Arrange > Order > Bring to front"), undo. Steps run in order in one editor tab; changes are verified against the saved deck.
Inputs: deck (required), steps (required), account.
slides_exportA
Save a presentation to a local file: pptx, pdf, odp or txt — or one slide as png, jpeg or svg (pass slide).
Inputs: deck (required), path (required), format (required), slide, +2 more.
slides_listA
List Google Slides presentations: recently opened, or a Drive search when query is given.
Inputs: limit, query, account.
slides_openA
Open a presentation (optionally at a slide) in a new foreground Chrome tab for the user to see.
Inputs: deck (required), slide, account.
slides_readA
Read a Google Slides presentation as saved in Drive. "outline" (default): each slide with its layout, numbered shapes (role: title/subtitle/body/…, position in points, text as markdown with bullet nesting), tables, images and speaker notes — the shape numbers are what slides_write and slides_edit take. "text": plain text slide by slide. "json": the parsed structure.
Inputs: deck (required), format, offset, slides, +2 more.
slides_renameC
Rename a presentation.
Inputs: deck (required), title (required), account.
slides_replaceA
Slides' own Find and replace across every slide (shapes and tables). Pass find + replace, or replacements: {find: replace, …} to fill a template's placeholders in one call. occurrence replaces only the Nth match. Verified against the saved deck.
Inputs: deck (required), find, regex, account, +4 more.
slides_typeA
Type text into a slide like a person: one keystroke at a time at a human pace (default ~55 wpm), with rhythm, thinking pauses and typos fixed with Backspace — into the title, subtitle, body, any shape by number, or the speaker notes. mode replace (default) clears the shape first; append adds paragraphs after its text. Bullets ("- "), numbering and nesting become real lists; bold / italic are toggled with Cmd+B/I while typing. Long text is typed in parts of up to ~90 s, each verified against the saved deck; the call returns when everything is typed.
Inputs: deck (required), slide (required), wpm, mode, +8 more.
slides_writeB
Add slides or change existing ones, in the deck's own layouts and theme. Each entry is one slide: without slide it adds a new slide (layout, title, subtitle, body, notes); with slide: N it changes slide N (any of those, other shapes by number, skip, move, duplicate, delete). Body text is markdown lines: bullets, numbering and nesting become real Slides lists. Verified against the saved deck.
Inputs: deck (required), slides (required), account.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 27 tools
Tools have overlapping editing capabilities (docs_write, docs_type, docs_edit, docs_format; slides equivalents) that require careful reading to select the right one. Descriptions clarify boundaries, but the large set can still confuse an agent about which tool to use for a given edit task.
All tools follow a consistent snake_case pattern with a resource prefix (docs_ or slides_) followed by a verb or noun. No mixed conventions appear, making names predictable and easy to parse.
27 tools is high for a single server, and while the dual docs/slides domain justifies many operations, there is redundancy among editing tools (write/type/edit/fill), making the set heavier than necessary.
Core CRUD is covered for content (create, read, update via multiple tools, rename), but missing delete operations for both Docs and Slides, as well as sharing/permissions and comment management, leaving notable gaps in the lifecycle.
Maintenance
Related MCP Connectors
Give AI agents a real cloud Chrome: open sessions, navigate, read pages, click, type and screenshot.
Let AI agents use your real, signed-in Chrome: tabs, clicks, forms, screenshots and video.
Control a real browser from AI agents: navigate, click, type, screenshot, read the page.
Let your AI agent operate any website through a real, logged-in browser session.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to create, read, and modify Google Slides, Sheets, Docs, and Drive documents programmatically. Supports file management, content editing, and version history retrieval.1,276 npmMIT
- AlicenseAqualityDmaintenanceEnables AI agents to create and edit Google Docs and draft Gmail emails through natural language.7ISC
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants and terminal users to control a logged-in Chrome browser, performing actions like opening pages, searching, filling forms, and taking screenshots without re-authentication.MIT
- AlicenseNot gradedqualityBmaintenanceEnables agents to perform typed, site-specific actions across a signed-in Chrome browser, interacting with services like Gmail, Reddit, Drive, and Amazon through natural language requests.1MIT