# Reported issues for mcp-gee-sweet

Pod holds 23 of 139 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.

Back to [mcp-gee-sweet](/mcp/mcp-gee-sweet).

## Most discussed

### qa: dedicated QA Google account, calendar, and pollution cleanup

Consolidates #225, #226, #249 — all three are the same underlying fix: QA runs currently use a personal Google account and primary calendar, which pollutes real Drive/Calendar with stray artifacts and blocks safe share/permission testing. One dedicated account (and the OAuth-scope follow-on) solves all three angles together.

- [ ] **Dedicated QA account** — create `mcp-gee-sweet-qa@` (OAuth) for QA runs, plus a second `mcp-gee-sweet-qa-2@` account for share/permission tests (replaces…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/304) · 2026-07-14 · open · 3 comments

### Markdown-to-Doc conversion silently keeps GitHub/GitLab-style #slug anchor links as dead hyperlinks instead of resolving to Docs-native internal links

## Context

Source markdown (GitLab Pages-published policy docs) uses standard GitHub/GitLab-style heading-anchor links for internal cross-references, e.g.:

```markdown
Approved encryption algorithms are contained in [Appendix A](#appendix-a---approved-hashing-algorithms).
```

These render correctly as in-page jump links on GitLab Pages (which auto-generates heading slugs), but after `create_doc_from_file` conversion, the resulting Google Doc has "Appendix A" as a styled hyperlink (blue,…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/409) · 2026-07-24 · closed · external user · 2 comments

### markdown-to-Doc conversion silently drops images; no path from local files to inline images

## Context

Follow-up split-out from #332, focused specifically on the markdown-to-Doc image gap.

create_doc and write_doc_content support content_format="markdown" for headings, lists, links, tables, etc., but standard markdown image syntax (`![alt](path)`) is silently dropped/ignored during conversion. There's no way to reference a local file path or even a relative path from the caller's working directory - only insert_inline_image supports images, and only via a public HTTPS URL or an…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/333) · 2026-07-16 · closed · external user · 2 comments

### feat(calendar): list_all_events — query all subscribed calendars in parallel

## Summary

Add a `list_all_events` tool that fans out `list_events` calls across all subscribed calendars in parallel and returns a unified result, eliminating the need to call `list_events` once per calendar.

## Motivation

Currently querying multiple calendars requires one `list_events` call per calendar. During QA for #155 this was done manually with 8 parallel tool calls. A single tool that handles fan-out internally is faster and more convenient.

## Proposed API

```python…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/194) · 2026-06-25 · closed · 2 comments

### decision-needed: evaluate deprecating share_spreadsheet in favor of share_file

## Why

Surfaced during architecture review for `docs/decisions/decision-comments-first-class.md` (#661), as a parallel instance of the same pattern that motivated that doc: `share_spreadsheet` (`tools/drive/sharing.py`) is the project's original tool (PR #1, predating Drive having its own domain). `share_file`, added later, is a **strict superset** of its capability — `share_spreadsheet`'s always-`type=user` email+role shape is fully expressible as `share_file(file_id=spreadsheet_id,…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/665) · 2026-08-29 · open · 1 comment

### sync_folder dry_run response exceeds 40k-char cap on moderately-sized folders (deterministic, not size-related to the actual folder size)

## Summary

`sync_folder(dry_run=True)` fails with a hard error once a folder's file count pushes the response past a 40,000-character safety cap. Hit this today syncing a Drive folder with 303 local files / 280 Drive files (upload direction):

```
Error executing tool sync_folder: sync_folder: the response is 40119 characters,
over the 40000-character safety cap. Recursive syncs can produce very large
result lists. Narrow folder_id, direction, or recursive scope, or set
MAX_TOOL_RESPONSE_CHARS…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/512) · 2026-08-03 · closed · external user · 1 comment

### Unsupported/dropped markdown constructs collapse their paragraph into adjacent content instead of preserving block-level structure

## Context

Both #333 (dropped images) and #399 (dropped thematic breaks) exhibit the same underlying behavior: when the markdown-to-Doc converter can't represent a construct, it deletes that construct's *entire paragraph* rather than leaving an empty block in its place.

This breaks fidelity with how every standard CommonMark-compliant viewer (GitHub, GitLab Pages, VS Code preview, etc.) degrades. In those renderers, block-level separation is preserved regardless of whether a specific inline…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/401) · 2026-07-22 · closed · external user · 1 comment

### create_doc_from_file / markdown conversion silently drops thematic breaks (---), worse than design doc anticipated

## Context

While converting a batch of policy markdown files to Google Docs via `create_doc_from_file`, found that a `---` thematic break (used as a visual section divider directly under the doc title in every source file) is completely dropped during conversion — no paragraph, no `<hr>`-equivalent, no trace at all in the resulting Doc's structure.

Repro:
```markdown
# Title

---

## Heading
```
Converts to a Doc where the "Title" heading and "Heading" paragraph sit immediately adjacent (the…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/399) · 2026-07-22 · closed · external user · 1 comment

## Most recent

### Decide + test intended rendering for min_depth>=2 isolated bullet runs (behavior change from PR #711)

### Summary

PR #711 (issue #439) changed how an *isolated* contiguous bullet run — every `BulletItem` at `depth > 0` with no `depth == 0` sibling in the same `createParagraphBullets` call — is rendered. The fix wraps such a run with a throwaway 0-tab anchor paragraph so the real items land at their true `nestingLevel`. For a `min_depth == 1` run this produces `nestingLevel 1` (the intended #439 fix). For a `min_depth >= 2` run it now produces an **absolute** `nestingLevel` of 2+ — i.e.…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/714) · 2026-09-09 · open · 0 comments

### create_paragraph_bullets collapses an all-nesting_level>=1 run to nestingLevel 0 (same #439 shape, unfixed path in style.py)

### Summary

`create_paragraph_bullets` (`src/mcp_gee_sweet/tools/docs/style.py`) implements the same "leading-tab characters + one `createParagraphBullets` call per contiguous run" mechanism that `emitter.py`'s deferred bullet pass uses, but it did **not** receive the #439 fix (PR #711, `emitter.py` only). The same collapse-to-`nestingLevel 0` bug is still reachable through this tool.

### Mechanism

`style.py` (~L697-717): for each unit it emits `insertText` of `"\t" * nesting_level` at the…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/713) · 2026-09-09 · open · 0 comments

### find_free_slots per-calendar error shape is less detailed than list_all_events for the same failure mode

\`find_free_slots\` inlines a bad calendar ID as \`busy["<id>"] = [{"error": "notFound"}]\` (a bare reason string), whereas \`list_all_events\` inlines \`{calendar_id, calendar_summary, error: "<full HttpError repr>"}\` for the identical failure. Both handle the failure gracefully (no abort) — this is a consistency/detail-level gap, not a crash.

**Expected:** align the two tools' per-calendar error shape, or document why they intentionally differ.

Found during the v0.9.0 QA pass…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/691) · 2026-09-05 · open · 0 comments

### download_file with a non-existent trailing-slash directory creates a clobbering file instead of the directory

\`download_file(file_id, local_path="/some/new/dir/", ...)\` where \`/some/new/dir/\` doesn't exist yet creates a plain *file* at that literal path (not a directory containing the downloaded file), and reports \`local_path\` as if it had saved the file inside a directory. Every subsequent download to the same \`local_path\` silently overwrites that file with no warning. Once the directory already exists, all directory-target behavior is correct.

**Expected:** create the directory (\`mkdir…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/690) · 2026-09-05 · open · 0 comments

### list_folders with no parent ignores DRIVE_FOLDER_ID, hardcodes personal My-Drive root

\`tools/drive/files.py\` \`list_folders(parent_folder_id=None)\` appends \`q += " and 'root' in parents"\` unconditionally when no parent is given — unlike \`create_folder\`/\`create_spreadsheet\`, which resolve a missing parent from \`lc.folder_id\` (= \`DRIVE_FOLDER_ID\`). On a Shared-Drive deployment (\`DRIVE_FOLDER_ID\` set) \`list_folders(None)\` therefore lists the OAuth user's *personal* My-Drive root, not the configured default; for a pure service-account deployment there is no personal…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/689) · 2026-09-05 · open · 0 comments

### list_files/list_spreadsheets/list_folders: folder-listing cache key omits max_results — silent truncation + cache poisoning

The folder-listing cache (shared by \`list_files\`, and transitively \`list_spreadsheets\`/\`list_folders\`) keys its cached entries without \`max_results\` as part of the key. Two live-reproduced consequences:

1. A call with a smaller \`max_results\` than a prior cached call for the same folder gets served the prior (larger, unfiltered) cached result and *ignores* its own limit — e.g. \`list_files(FOLDER_ID, max_results=2)\` returned 5 items because an earlier default-size call had already…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/688) · 2026-09-05 · closed · 0 comments

### share_spreadsheet fails with "File not found" on any Shared Drive file — missing supportsAllDrives=True

\`tools/drive/sharing.py\`'s \`share_spreadsheet._share_one\` calls \`drive_service.permissions().create(fileId=spreadsheet_id, ...)\` with no \`supportsAllDrives=True\` — the only permission-mutating call in the file missing it (\`update_permission\`, \`remove_permission\`, \`list_permissions\`, \`transfer_ownership\`, and \`share_file._share_one\` all pass it). On a Shared Drive item, the Drive API returns "File not found" for a \`permissions().create()\` call that omits this flag, so…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/687) · 2026-09-05 · closed · 0 comments

### docs image-sharing failure paths: unrevocable anyone:reader grant + missing folder-cache invalidation in _replace_doc_content

## Summary

Two non-blocking cleanup gaps in the inline-image sharing failure paths, surfaced by `/code-review high` during QA of PR #652 (#649) and judged non-blocking for that PR (the primary #649 fix — surface the orphan file id — works). Related dedup is tracked separately in #511.

### 1. Post-share failure carries `file_id` but not `permission_id` — public grant can be left unrevocable

All three call sites wrap `permissions().create()` **and** `files().get(webContentLink)` in one `try`:…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/666) · 2026-08-29 · open · 0 comments

### feat(drive): full comments/replies CRUD parity (delete, reply, reopen, get, update)

## Why

Per `docs/decisions/decision-comments-first-class.md` (#661): the Drive `comments`/`replies` resource fully supports `create`/`get`/`list`/`update`/`delete` on both (confirmed live against the real API discovery doc), but this codebase only implements `list`/`create` for comments and a resolve-flavored `create` for replies. `delete_doc_comment` was explicitly out of scope for #151 per its own QA docs — this closes that gap along with the rest.

Depends on #663 (generalization/rename)…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/664) · 2026-08-29 · open · 0 comments

### feat(drive): generalize comment tools to tools/drive/comments.py

## Why

Per `docs/decisions/decision-comments-first-class.md` (#661): `list_doc_comments`/`add_doc_comment`/`resolve_doc_comment` (`tools/docs/comments.py`, #151) already call the generic Drive `comments()`/`replies()` resource against any `fileId` — confirmed live against a real Spreadsheet with zero code changes. The only thing scoping them to Docs is naming and module placement.

## What this needs

- Move the implementation to `tools/drive/comments.py`. Retire `tools/docs/comments.py`.
-…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/663) · 2026-08-29 · open · 0 comments

### sync_folder reports "in sync" when mtimes match but content differs (rename-in-place); use_checksum can't catch it

## Problem

`sync_folder` silently reports **"in sync"** for a name whose content differs on the two sides, whenever the two mtimes happen to agree. The most reliable way to produce this is a **rename-in-place**: `mv` preserves mtime, so renaming `Pt 6.png` → `Pt 3.png` locally changes what's behind the name `Pt 3.png` while leaving its mtime exactly as it was. Drive's `Pt 3.png` still holds the *old* `Pt 3` content, the mtimes match, and the sync skips it — permanently, since nothing will ever…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/659) · 2026-08-25 · open · external user · 0 comments

### Add /roadmap-status command — role-based "what's left, who's doing it" report

## Why

Kai currently reconstructs "what's left and who owns it" by hand each time (cross-referencing `gh issue list` by label, worktree state, open PRs) — there's no repeatable command for it. Requested by the user 2026-08-18 while doing a v0.9 role assessment (dev vs. QA vs. doc vs. prompt vs. design throughput) — that assessment found the bottleneck wasn't dev throughput but QA-infra decisions and an unowned design gap (#588), which took manual cross-referencing across several `gh issue…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/622) · 2026-08-19 · closed · 0 comments

### get_doc_as_markdown: silent content loss on two narrow edge cases

Two narrow edge cases in the new `get_doc_as_markdown` tool (#300, PR #591) silently drop real content with no error, no placeholder, and no trace — found during PR #591's QA round 1 code review and confirmed live.

## 1. Image dropped when mixed into an all-Courier-New paragraph

`ast_to_markdown.py`'s `_is_code_block` filters `node.runs` to `Run` items only before checking `font_family`, so an `Image` node sitting in a paragraph whose text runs are all styled `font_family="Courier New"` is…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/594) · 2026-08-15 · closed · 0 comments

### observability: _timed logs 200 status for tool calls that catch their own exception and return {error: ...}

## Context

Raised during PR #577 (issue #494) code review. `server.py`'s `_timed` wrapper logs whatever status the tool call returns; a tool that catches its own exception internally and returns `{"error": ...}` (the established convention for `search_files`, `search_spreadsheets`, and now `list_shared_with_me`/`list_recent_files` per #494) never raises, so `_timed` logs a 200 for it same as a genuine success.

## Impact

A real Drive/Sheets/Docs API outage on one of these tools produces an…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/579) · 2026-08-12 · open · 0 comments

### Inline-image pre-validation only checks the 25-megapixel limit, not Google's 50MB file-size limit (#400 follow-up)

Live-discovered during PR #554's QA round 2 (issue #400, oversized inline-image handling).

`docs/images.py`'s own module docstring cites both of Google Docs' documented `insertInlineImage` limits: "the ceiling as 25 megapixels (also 50MB, PNG/JPEG/GIF only)." But `check_dimensions`/`check_image_bytes` only implement the megapixel check — there's no byte-size check anywhere in the module.

**Confirmed live:** a real, Pillow-decodable PNG under 25 megapixels but with a large byte size…

[Read the thread](https://github.com/khuisman/mcp-gee-sweet/issues/562) · 2026-08-10 · closed · 0 comments

The remaining reports are on [the project's issue tracker](https://github.com/khuisman/mcp-gee-sweet/issues).
