Pod

Yes, this is on purpose. Pod is built for agents, so the default page is plain HTML.
Human? View the normal website.
Agent? You probably prefer /mcp/verified-googledocs-mcp/issues.md or /mcp/verified-googledocs-mcp/issues.json, or Pod over MCP.

Reported issues for verified-googledocs-mcp

Pod holds 21 of 27 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

Back to verified-googledocs-mcp.

Most discussed

Markdown writes + tab diff

The highest-risk milestone: markdown writes with verification that can actually catch what excerpts cannot.

Write direction (markdown → batchUpdate)

Verification (range/markdown evidence family)

Read the thread · 2026-06-12 · closed · 4 comments

Comments and suggestions: unified open-items list, verified resolve

Close the two comment-layer failures: false resolves and invisible suggested edits.

Read the thread · 2026-06-12 · closed · 4 comments

Verification kernel + verified replace_text

The core of the project: a verification layer every mutating tool passes through, proven first on replace_text.

Kernel (verify.py)

Read the thread · 2026-06-12 · closed · 4 comments

Secondary-tab writes report applied:true but write no content (false success)

Summary

append_markdown and replace_tab_markdown targeting a secondary (non-first) tab return applied: true but write no content. The post-write structural check reports post_blocks: 0 and a subsequent read_document of that tab returns empty. Writes to the first tab (t.0) work correctly.

This is a false success: applied: true while nothing was written is exactly the failure mode the verified-write contract is meant to eliminate.

Reproduction

On a doc with two tabs (`t

Read the thread · 2026-06-14 · closed · 2 comments

Live acceptance pass: exercise all 14 tools and all 12 error codes against a real document (release gate)

The offline unit suite (364 tests) proves the logic against synthetic documents.get fixtures and an in-memory MCP client. It does not prove the verified-write contract holds against the real Google Docs and Drive APIs. Before anyone is told to install this, every tool and every guarantee needs to be exercised once, end to end, against a live document — and the result recorded.

This is the pre-release gate. It blocks #6 and depends on #1 (seeded scratch doc, captured fixtures, reso

Read the thread · 2026-06-13 · closed · 2 comments

Auth and read path: OAuth entry point, tab-scoped reads, Docs JSON to markdown

Foundation milestone: OAuth, the stdio server skeleton, and the tab-scoped read path.

Auth

Read the thread · 2026-06-12 · closed · 2 comments

Table/markdown writes miscompute indices on docs with smart quotes / NBSP / soft hyphens — silent partial corruption; dry_run does not catch it

Summary

insert_table, replace_table_row, and replace_tab_markdown miscompute document indices when the tab contains common special characters — smart/curly quotes, non-breaking spaces (U+00A0), or soft hyphens (U+00AD). The live write lands at the wrong index and partially mutates the document (table inserted mid-word, or a trailing fragment duplicated), even though the pre-write dry_run for the same request reports success.

This is high-impact: **Google Docs enables smart (

Read the thread · 2026-07-22 · closed · 1 comment

find_sections returns heading-only ranges; replace_range_markdown then replaces only the heading

Summary

find_sections returns a range covering only the heading text, not the heading-through-end-of-section body. A caller that feeds that range into replace_range_markdown (the documented pairing — "takes a find_sections range") replaces only the heading line and leaves the section body in place.

Reproduction

Doc tab t.0 content:

## Approach

Bellese has operated this kind of system for years.
  1. find_sections(tab_id="t.0", heading="Approach") → `{"matches":

Read the thread · 2026-06-14 · closed · 1 comment

Most recent

replace_tab_markdown drops list nesting and ordered-list numbering: all sub-items write at level 0, and the doc is left mutated with no rollback

Summary

replace_tab_markdown compiles nested list items correctly but writes them all at nesting level 0. Ordered lists are also written as unordered bullets. The structural verifier correctly detects the mismatch and returns VERIFICATION_FAILED with applied: false, but the document has already been mutated and there is no rollback, so the tab is left in a state the tool itself flags needs_manual_restore: true.

Two distinct defects, same call path:

  1. **List structure is lost on wr

Read the thread · 2026-08-13 · closed · 0 comments

Add a verified format_text tool: apply character styling (bold/italic/underline) to a matched string, no content mutation

Problem

The server currently has no way to style text. replace_text compiles every edit into deleteContentRange + insertText (visible in its own error surface: "Invalid requests[1].insertText: Insert text requests must specify text to insert."). The Docs API's insertText is plain characters only — styling is a separate updateTextStyle request the tool never issues — and the replacement string is not parsed as markdown.

Empirically confirmed 2026-08-09 (live production do

Read the thread · 2026-08-09 · closed · 0 comments

main() / mcp.run() dispatch has zero test coverage

Summary

src/verified_googledocs_mcp/server.py:1002-1014 is the sole transport entry point:

def main() -> None:
    if len(sys.argv) > 1 and sys.argv[1] == "auth":
        from .auth import run_auth_flow
        run_auth_flow()
        return
    mcp.run()

It is reachable three ways — the verified-googledocs-mcp console script, python -m verified_googledocs_mcp, and uv run verified-googledocs-mcp in .mcp.json — and is exercised by no test. Grepping tests/ for `main

Read the thread · 2026-07-27 · closed · 0 comments

test_tool_manifest asserts inputSchema but never outputSchema — the middleware's bare-dict evidence assumption is unguarded

Summary

EvidenceEnforcementMiddleware decides whether a mutating tool returned real evidence by intersecting _EVIDENCE_KEYS against result.structured_content.keys() (src/verified_googledocs_mcp/middleware.py:74-76). That depends on structured_content being the bare tool dict, so "applied" sits at the top level. The assumption is stated in a comment at middleware.py:79 but asserted nowhere.

tests/unit/test_tool_manifest.py:63-67 checks that every tool has an inputSchema

Read the thread · 2026-07-27 · closed · 0 comments

Unbounded fastmcp>=3.0 dependency will break end-user installs when FastMCP 4 ships stable

Summary

pyproject.toml declares fastmcp>=3.0 with no upper bound. uv.lock pins 3.4.2 for this repo's CI and local dev, but the lock does not constrain end users installing from PyPI or via uvx. server.json advertises "runtimeHint": "uvx", so the published install path resolves FastMCP fresh on every run.

FastMCP 4 is currently in alpha (4.0.0a1 2026-07-21, 4.0.0a2 2026-07-24) and depends on mcp==2.0.0b2 / mcp-types==2.0.0b2. Prereleases are excluded from default reso

Read the thread · 2026-07-27 · closed · 0 comments

Add verified table tools and PDF export

The server has no table tools, and no way to export a rendered PDF. The retired incumbent server (@a-bonus/google-docs-mcp) provided both, and the proposal workflow depends on them: prose syncs via replace_range_markdown, but tables currently require manual paste, and page-limit checks require rendering the doc to PDF.

Measured real usage across 321 session transcripts (actual tool_use invocations, not tool listings):

Incumbent tool Real calls Need
`replaceTableRo

Read the thread · 2026-07-17 · closed · 0 comments

Release v0.1.0: PyPI publish + MCP registry listing (carved out of #6)

Carved out of #6 (which is otherwise complete and closed). These are the remaining release steps, blocked only on a one-time pypi.org action by the maintainer.

Read the thread · 2026-06-14 · closed · 0 comments

replace_range_markdown structural_match still false-negatives: re-export slice over-captures adjacent paragraphs

Found by the #23 retest, after #36/#42 landed. Distinct root cause from #36; blocks #6.

Summary

#42 fixed the blank-line separation in to_markdown (#36), and replace_tab_markdown's structural_match now passes. But replace_range_markdown's structural_match still false-negatives, for a different reason: assemble_range_markdown_evidence re-exports too wide a slice of the post-write body.

Root cause

The re-export end is max(approx_end, end_index) where `approx_end =

Read the thread · 2026-06-13 · closed · 0 comments

append_markdown fuses appended content into the trailing paragraph (garbled output)

Found by the #23 live acceptance pass. Produces exactly the garbled-artifact failure this project exists to prevent (PRD §2.6).

Summary

append_markdown inserts at tab_end - 1 (before the tab's final newline), which is inside the last paragraph. The appended block-level markdown therefore fuses with the existing trailing paragraph instead of starting a new block.

Evidence

Appending "## Appended\n\nAPPENDED_MARKER paragraph.\n" to t.0 produced a trailing paragraph that re

Read the thread · 2026-06-13 · closed · 0 comments

insert_image inline_object_confirmed is a false negative — verifier checks the wrong paragraph

Found by the #23 live acceptance pass. The image inserts correctly; the verification reports failure.

Summary

insert_image successfully inserts the image (applied: true, the inlineObjectElement is present in the post-read), but the structural evidence reports inline_object_confirmed: false.

Root cause

The insert creates an intermediate empty paragraph. For anchor "Duplicate sentence test:" (paragraph end index 150), insert_image inserts "\n" at index 150 — creating

Read the thread · 2026-06-13 · closed · 0 comments

replace_range/tab_markdown structural_match is a false negative — to_markdown omits blank lines between blocks

Found by the #23 live acceptance pass. The write is correct; the verification is not — which undermines the verified-write contract for markdown.

Summary

replace_tab_markdown (and replace_range_markdown) write the document correctly, but their own structural_match evidence reports false on valid input.

Live check — replace_tab_markdown(tab="t.0", markdown="# Synced Document\n\nFirst paragraph after sync.\n\nSecond paragraph after sync.\n"):

Read the thread · 2026-06-13 · closed · 0 comments

Extend the seeded acceptance fixture: heading-styled paragraphs and a nested tab

Found by the #23 live acceptance pass. These fixture gaps block parts of §1 and §3 from being exercised against the canonical fixture.

The seeded doc (1Zm_6bAwA7UH1DKkGVL3kg9XcQ6rIZHmUFcQPTcoJb6Y) is missing live substrate that #23 needs:

1. No heading-styled paragraphs

find_sections returns [] for every query on both tabs — "Text Hazards" / "Unicode Hazards" are not HEADING_*-styled. This blocks:

Read the thread · 2026-06-13 · closed · 1 comment

audit_excerpts=false redaction is implemented but unreachable through any tool or config

Found by the #23 live acceptance pass. Blocks the §6 audit-redaction check.

Summary

verify.append_audit(..., audit_excerpts: bool = True) redacts before/after to "[redacted; N chars]" when audit_excerpts=False. But every call site passes the default True (mutations.py, comments.py), and there is no tool parameter, environment variable, or server setting that flips it. The redaction path is dead code from the tool surface.

Impact

PRD §10 / README plan (#6) and #2

Read the thread · 2026-06-13 · closed · 0 comments

The remaining reports are on the project's issue tracker.