# Reported issues for che-word-mcp

Pod holds 24 of 161 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 [che-word-mcp](/mcp/che-word-mcp).

## Most discussed

### P0 CRITICAL: save_document lossy re-serialization of document.xml — strips 32/34 namespace decls, wipes all bookmarks, drops text content

## Problem

`save_document` re-serializes `word/document.xml` in a **lossy** way — produces malformed XML and drops substantial content. All other parts are preserved (42/42), but `document.xml` itself becomes invalid and loses bookmarks + text content whenever a mutation forces re-serialization.

This is **worse than #42** — #42 only hit headers/footers via `update_all_fields`. This one hits the document body itself via any mutating operation that dirties `document.xml` (e.g., `insert_paragraph

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/56) · 2026-04-24 · closed · 13 comments

### P2 bug: MCP insert_equation tool bypasses lib InsertLocation overload + silently clamps bad index (post-#91 verify follow-up F4)

## Problem

> **From verification of #91** (Regression Reviewer R1 + Devil's Advocate rebuttal):
> 「The MCP `insertEquation` tool (Server.swift:8843-8971) **does not call `WordDocument.insertEquation(at: InsertLocation, latex:, displayMode:)` at all**. Instead it builds an `eqPara: Paragraph` containing a raw-XML OMML run, then routes through `doc.insertParagraph(eqPara, at: ...)` directly. **Worse**: MCP's catch-all branch (Server.swift:8964) calls non-throwing `insertParagraph(eqPara, at: inse

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/98) · 2026-04-29 · closed · 8 comments

### export_script: self-produced docx yields 0% DSL ratio (all parts raw carryPart)

## Problem

`export_script` 對 che-word-mcp **自己建立**的 docx 匯出 `.mdocx.swift` 時，沒有任何 part 升級成 typed DSL——全部 11 個 XML part 都走 raw `carryPart` channel。名義上的「typed DSL 升級」對自產文件完全沒有發生，產出的 `.mdocx.swift` 只是 raw XML 封存（byte-equal floor 正常，但不可讀不可編輯）。

> **Original evidence**（2026-07-18 session，逐字工具回傳）:
> - `export_script` → `{"dsl_parts":[],"form_gaps_empty":false,"slot_count":0}`
> - `get_script_coverage` → `aggregate_ratio: 0`；11 個 part 全部 `channel:"raw"`、`dsl_ratio:0`（含 `word/document.xml` 239,958 byte

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/173) · 2026-07-18 · closed · 7 comments

### P2: insert_paragraph / insert_equation lack after_text/before_text anchors — paragraph_index alone unreliable in real-world docx

## Problem

`insert_image_from_path` already supports rich anchor parameters (`after_text`, `before_text`, `text_instance`, `after_image_id`, `into_table_cell`, `paragraph_index`) and works smoothly even on complex docx with tables, sections, SDTs, and headers. But `insert_paragraph` and `insert_equation` only accept `paragraph_index` — and that index is **opaque body-level numbering** that can't be reliably computed by an AI agent from the raw docx XML.

## Repro

Tested on a real-world Chinese

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/61) · 2026-04-26 · closed · 7 comments

### insert_equation: `display_mode` string fail-open coercion

## Problem

> **From verification of #98**:
> 「`display_mode` string mistype silently fails-open to `true`, bypassing the new inline pre-check.」
> — Source: team:logic (P2)

`args["display_mode"]?.boolValue` returns nil if the caller passes `"true"` (string) instead of `true` (bool). The default `?? true` then routes the call as a display-mode insert, silently bypassing the inline-mode pre-check.

For an AI agent that misinterprets the schema and passes `"display_mode": "false"` (string), the ca

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/107) · 2026-05-01 · closed · 6 comments

### insert_equation: silent precedence when both `components` and `latex` provided

## Problem

> **From verification of #98**:
> 「Silent precedence when both `components` and `latex` are passed (components wins, latex dropped without warning).」
> — Source: team:logic (P2)

`insertEquation(args:)` checks `args["components"]` first, then falls through to `args["latex"]`. If a caller (or buggy AI agent) passes BOTH, the handler silently uses `components` and discards `latex` without surfacing the conflict.

This violates the same anti-pattern that #71/#80 fixed for anchor conflic

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/106) · 2026-05-01 · closed · 6 comments

### P2 bug: update_all_fields fails to detect top-level paragraph SEQ fields with pStyle=Normal — partial scope of #94 leaves rescue-pipeline-generated SEQ unreachable

## Problem

> **Original observation** (v3.17.5 verification on rescue-swift-v317.docx, 2026-04-30):
> 「v3.17.5 ships #94 fix that adds `.table` / `.contentControl(_, children:)` recursion to the body walker. But our rescue v317 docx has VALID SEQ Figure fields at **top-level body paragraphs** (not inside containers) — yet `update_all_fields` still returns 'no SEQ fields found'. The pre-fix behavior already processed top-level `.paragraph` BodyChild, so #94 didn't introduce the regression — ther

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/104) · 2026-04-29 · closed · 6 comments

### P3 enhancement: extend flattenedDisplayText OMML walk to hyperlinks/fieldSimples/AC paths (post-#85 follow-up)

## Problem

> **From verification of #85** (Logic §2.3 + Devil's Advocate §2.3):
> The v0.21.5 fix to `Paragraph.flattenedDisplayText()` (`Sources/OOXMLSwift/Models/InsertLocation.swift:247-277`) walks OMML in the top-level `runs` loop only. The `hyperlinks` / `fieldSimples` / `alternateContents` / `contentControls` paths still use `runs.map { $0.text }.joined()` and silent-drop OMML inside those wrappers.
> — Source: `team:logic` + `team:devils-advocate`

Real-world impact: rare but real. Inlin

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/92) · 2026-04-29 · closed · 6 comments

## Most recent

### bug: format_text false values are reported as success but ignored

## Problem

`format_text(paragraph_index: ..., bold: false)` reports success but leaves existing `<w:b/>` formatting unchanged. The handler builds a fresh `RunProperties`, assigns `bold = false`, and calls `Document.formatParagraph`; the current upstream merge applies only true values, so false is indistinguishable from an omitted argument.

The same ambiguity affects `italic: false` and `underline: false` at the public tool boundary.

## Type

bug

## Expected

- Omitted formatting arguments le

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/197) · 2026-08-31 · open · 1 comment

### bug: refuse release when source tree changes during build

## Problem

> Tracking umbrella: [PsychQuant/macdoc#163](https://github.com/PsychQuant/macdoc/issues/163)

`che-word-mcp/scripts/release.sh` checks repository cleanliness only before a long release build. If HEAD or a source file changes while `swift build -c release` is running, the script can sign and notarize bytes that do not correspond to the release tag's commit.

## Type
bug

## Expected

Capture the source revision at preflight and, immediately after build but before codesign, refuse the

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/195) · 2026-08-23 · open · 5 comments

### feat: address and update individual paragraphs inside table cells

## Problem

> Tracking parent: [PsychQuant/macdoc#156](https://github.com/PsychQuant/macdoc/issues/156)

che-word-mcp cannot address an individual paragraph inside a table cell. The only cell write path replaces the whole cell and collapses multiple paragraphs; body paragraph tools deliberately exclude table-cell paragraphs; global text replacement affects every matching row when text is duplicated.

## Type
enhancement

## Expected

Provide a discoverable, zero-based table-cell paragraph addres

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/194) · 2026-08-23 · open · 1 comment

### tool 回傳沒有 advisory 通道 —— 非致命警告只寫 stderr，呼叫端永遠看不到 (sister concern from #189)

## Problem

MCP tool 目前**沒有任何管道**把「非致命的建議 / 警告」交還給呼叫端。Server.swift 裡既有的
`Warning: ...` 全部寫進 `FileHandle.standardError`（`Sources/CheWordMCP/Server.swift` ~L452 /
L476 / L485 / L538），而在 MCP stdio transport 下 **stderr 進的是 client 的 log 檔**
（例如 `~/Library/Logs/Claude/mcp-server-<display name>.log`），不會出現在 tool result 裡。

也就是說：**呼叫端（模型或使用者）永遠看不到這些警告。**

## Type
bug

## 具體的既有失效

`storeDocument` 的 autosave checkpoint 失敗時：

```swift
} catch {
    FileHandle.standardError.write(
        Data("Warning: auto

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/192) · 2026-08-21 · open · 0 comments

### bug: update_cell 寫入的 run 無 rPr —— 內容字型落到 docDefaults，與表單主字型（標楷體）不一致

## Problem

**`update_cell` 寫入的 run 不帶任何 rPr**——新內容的字型落到 docDefaults，忽略該 cell／表格原本的主字型。

## Type
bug

## 重現（公開官方範本 REC-P-011）

範本全文主字型為標楷體（`w:rFonts eastAsia=標楷體` ×890）、docDefaults 為新細明體。以 `update_cell(table_index=1, row=16, col=1, text='本研究旨在…')` 填入計畫目的後，讀回該 run：

```
run0: '本研究旨在探討消費者購買綠色…'  （無 rPr）
```

→ 渲染落到 docDefaults 的**新細明體**，與表單其餘標楷體文字明顯不一致。使用者開 Word 目視才發現。

## Expected

擇一：(a) 新 run 繼承目標 cell 既有文字（或同表格 dominant run）的 rPr；(b) `update_cell` 加選填 `font`／`inherit_format` 參數；(c) 至少在文件寫明「寫入內

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/191) · 2026-08-21 · open · 0 comments

### bug: replace_text 跨 run 替換把文字併進 run0 —— 後續 run 的字型宣告靜默丟失，標楷體標籤變新細明體

## Problem

**`replace_text` 跨 run 替換時把文字合併進第一個 run，後續 run 的字型宣告被丟棄**——標籤文字吃到第一個 run 的字型，視覺走樣。

## Type
bug

## 重現（公開官方範本 REC-P-011，同 #185/#187/#188/#189 系列）

範本 Table 1 r1c4 原始 run 結構：

```
run0: '□'        rFonts ascii=新細明體,PMingLiU（框框字型）
run1: '免除審查'  rFonts eastAsia=標楷體（標籤字型）
```

執行 `replace_text find='□免除審查' replace='■免除審查'`（跨 run 匹配，v2.1+ 功能）後：

```
run0: '■免除審查'  rFonts ascii=新細明體,PMingLiU eastAsia=None
```

「免除審查」四字從**標楷體變成新細明體**（eastAsia 落空 → docDefaults 新細明體）。使用者開 Word 目視才發現——文字層驗證（ge

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/190) · 2026-08-21 · open · 0 comments

### feat: checkbox 勾選的字形覆蓋指引／偵測 —— ☑ 在 CJK 字型表單經 emoji fallback 走樣，官方慣例是 □→■

## Problem

> **Original text**（使用者，2026-08-21，附截圖）：
> 「他打勾勾不是用原本的格式，你需要辨認原本的格式然後取代成黑色框框，字體也要完全一樣。這代表改動必須要是『維持格式的』（或者這是che-word-mcp的工作）」

以 `replace_text` 把表單的 `□`（U+25A1）換成 `☑`（U+2611）勾選時，**視覺結果與表單原字體完全不一致**：`☑` 渲染成灰底圓角的彩色 emoji 樣式，而非表單細線框的文字字形。

## Type
feature

## 根因（已查明，非 run 格式遺失）

Run 層格式**有**保留（同一 run 內替換字元，字型宣告未變）。問題在**字形覆蓋**：
表單常用的 CJK 字型（新細明體、標楷體等）有 U+25A1（□）與 U+25A0（■）的字形，
但**沒有 U+2611（☑）**——渲染器（Word／macOS 預覽／LibreOffice 轉 PDF）對缺字形的
字元做 font fallback，落到 Apple Color Emoji 之類的 emoji 字型，

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/189) · 2026-08-21 · open · 4 comments

### bug: search/replace 的文字模型丟棄純空白 run —— 檔案原文 0 命中、去空格字串才命中，且無文件揭露

## Problem

> **Original text**（發現脈絡，2026-08-21 REC-P-011 表單代填 session，同 #185）：
> 「`replace_text` Replaced 0 occurrence(s) of '□否 □是 □不適用'」——而該字串**逐字存在**於文件中。

**`search_text`／`replace_text` 的文字模型會丟棄純空白 run**：由多個 run 組成、其中空白字元自成一個 run（或位於 run 邊界）的文句，用「檔案原文」搜尋回 0 命中；把空白拿掉的「正規化字串」才命中。呼叫端無從得知這個正規化規則存在。

## Type
bug

## 重現（公開官方範本，可完整重現）

範本：台大 REC-P-011 新案審查申請書（`https://ord.ntu.edu.tw/WebUPD/ordntu/info/REC-P-011-新案審查申請書-所有類別新案_20260331公告.docx`）。

該檔 Table 1 row 26 內含文句，`w:t` 節點串接後的 codepoint 為（實測 h

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/187) · 2026-08-21 · open · 0 comments

### set_header_row is registered twice with conflicting schemas — the live handler reads a key the advertised schema may not have

## Problem

`set_header_row` is registered **twice** in `tools/list`, with **two different schemas**, and dispatched by **two `case` arms** of the same `switch`. A caller who follows the advertised schema can get a confident success message for an operation that did something else.

Found while verifying PsychQuant/macdoc#158 — the tool list has 245 entries but only 244 distinct names.

## Measured

Against the release build (`3a7b1e9`, shipped as v4.0.5):

```
tools/list raw length : 245
distin

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/186) · 2026-08-21 · open · 0 comments

### bug: 編輯後 save_document 剝掉未觸及列的 vMerge continuation —— 垂直合併靜默斷裂，零編輯 round-trip 卻能保留

## Problem

**編輯後 `save_document` 會剝掉「未觸及列」的 `<w:vMerge/>` continuation 標記**，表格的垂直合併靜默斷裂——Word 開啟時原本合併的標籤欄裂成多個空格。零編輯的 open→save round-trip **不會**發生（vMerge 完整保留），只有 session 內有過 `replace_text` / `update_cell` 編輯時才觸發。

## Type

bug

## 重現（2026-08-21，公開官方範本，可完整重現）

1. 範本：台大 REC-P-011 新案審查申請書（公開下載：`https://ord.ntu.edu.tw/WebUPD/ordntu/info/REC-P-011-新案審查申請書-所有類別新案_20260331公告.docx`），Table 1 為 111 列 ragged 表格，多處縱向合併標籤欄
2. `open_document`（`autosave_every: 0`, `track_changes: false`）
3. 對**部分列**做 ~30 次 `

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/185) · 2026-08-21 · open · 0 comments

### restrict_editing_region is implementable today — permStart/permEnd already round-trip

## Problem

`restrict_editing_region` validates its paragraph range and then fails with not-implemented (#172). Unlike the rest of that group, **this one needs nothing from upstream** — the plumbing already exists.

## The plumbing is already there

- `Paragraph.permissionRangeMarkers` holds `<w:permStart>` / `<w:permEnd>` (ooxml-swift, added for its #56 Phase 4)
- `DocxReader` parses both (`DocxReader.swift:1393`, `:1406`)
- **`Paragraph.toXML` emits both** (`Paragraph.swift:998-1000`)

So a do

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/184) · 2026-08-20 · open · 0 comments

### Let a tool handler set the error flag and still return a JSON body

## Problem

`execute_script` now reports a failing Stage-B verification as a tool error (#180). That fixes the signal, but costs the structured payload: the differing parts travel as text inside the error message instead of as the `broken_parts` array they used to ride in.

A caller that wants to act on *which* parts differ — rather than just display them — now has to parse prose.

## Root Cause

`handleToolCall` renders a thrown error as plain text and returns a JSON body only on the success pa

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/182) · 2026-08-19 · open · 0 comments

### execute_script 無覆寫保護，且破壞性寫入發生在驗證之前

## Problem

兩件相關的事，都關於 `execute_script` 的破壞性寫入：

**(a) 無覆寫保護。** CLI 的 `macdoc word render` 在輸出檔已存在時拒絕執行，除非帶 `--force`：

```swift
guard !FileManager.default.fileExists(atPath: outputURL.path) || force else {
    throw ValidationError("輸出檔案已存在: \(toDocx)（使用 --force 覆寫）")
}
```

`execute_script` 沒有對應參數，`scriptPipelineExecute` 本身也不檢查——直接 `writeAuthoringPackage(to:)`。

緩解：tool schema 有揭露此行為（`Server.swift`：`"輸出 .docx 路徑（已存在則覆寫）"`），所以是**已揭露的差異**而非靜默 clobber。但同 repo 的 `export_script` 對它的覆寫選擇有明確註解說明理由（"e

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/181) · 2026-08-19 · closed · 4 comments

### execute_script 驗證失敗仍回傳成功 — caller 把 byte-inequality 讀成通過

## Problem

`execute_script` 在 byte-equal 驗證**失敗**時仍然回傳成功的 tool result。`verified: false` 只是 payload 裡的一個欄位，MCP 呼叫本身沒有 `isError`。

> `ScriptPipelineTools.swift` — `executeScriptTool` 尾段：
> ```swift
> var payload: [String: Any] = ["written": result.written]
> if let verified = result.verified {
>     // F2: verdict fields ride the response ONLY when verification
>     // actually ran — an unconditional broken_parts: [] reads as a
>     // false green light to clients that only check that field.
> 

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/180) · 2026-08-19 · closed · 5 comments

### 同型截斷 sweep：get_paragraphs / list_footnotes / list_endnotes / list_all_formatted_text 也違反 truncation-policy SHALL（前三者還會宣稱沒發生的省略）

## Problem

#177 修 `get_tables` 時做的 sweep 發現**同一個 spec 違規存在於另外四個工具**。開成獨立 issue 而非塞進 #177 的 PR，理由是本 repo 的 #1 → #5 歷史：那次就是「修了 issue 標題點名的那一處、漏掉同型的其他處」，而剩下的沒人記得。

spec `word-mcp-markdown-export` 的 Truncation policy requirement（normative SHALL）：

> The server SHALL accept a `summarize: Bool` argument (default `false`) **on every tool that returns
> potentially long text**. When `summarize` is `false` or omitted, the server SHALL return
> **complete text with no upper bound**.

## Sweep 結果

排除 3 處合

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/178) · 2026-08-17 · closed · 1 comment

### get_tables 違反 truncation-policy SHALL — 無 summarize 參數，且 3 列/3 欄/15 字截斷中兩種完全不告知

## Problem

`get_tables` **違反 spec 的 normative SHALL**：它不接受 `summarize`，並且無條件截斷輸出。

spec `word-mcp-markdown-export`（住在 macdoc `openspec/specs/`）的 Truncation policy requirement 逐字寫：

> The `che-word-mcp` server SHALL accept a `summarize: Bool` argument (default `false`)
> **on every tool that returns potentially long text**. When `summarize` is `false` or omitted,
> the server SHALL return **complete text with no upper bound**.

`get_tables` 回傳表格內容（顯然屬於 potentially long text），但：

- schema **沒有** 

[Read the thread](https://github.com/PsychQuant/che-word-mcp/issues/177) · 2026-08-17 · closed · 3 comments

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