内容
# 报告-mcp
用户上传的文档格式(DOCX / HWP / HWPX / PDF)中,填充由聊天机器人生成的內容,并保持原始格式、表格和图片不变,以文件的形式保存。[Model Context Protocol](https://modelcontextprotocol.io/) 服务器。
- **输入**: 用户附加的空白模板文件 + 聊天机器人的回答
- **输出**: 按照模板设计保存的报告文件(DOCX→DOCX,HWP/HWPX→HWPX)
- **核心价值**: "重新生成" 而不是直接修改原始 IR。字体大小、颜色、表格、图片和页面布局不会受损。
## 工作流程
```
用户附件模板.hwpx 聊天机器人生成的回答文本
↓ ↓
describe / inspect ←──→ 目录·单元格·长度限制 파악
list_template_targets
↓ ↓
编辑列表(target_id,new_text)
↓
fill_and_save → 结果.hwpx(保持原始格式,仅替换内容)
```
## 公开工具(7个)
| 工具 | 用途 |
|---|---|
| `register_template(template_b64, template_filename)` | 在服务器上缓存模板,获取 `template_id`。对于同一文件多次调用,避免重复上传 base64 编码。 |
| `unregister_template(template_id)` | 解除缓存(自动过期 1 小时) |
| `describe_template(...)` | 概要 - 格式、页面·表格·图片数量、顶级段落 |
| `inspect_template(..., start, limit)` | 分页查看段落 |
| `list_template_targets(..., target_kinds, start, limit)` | 所有可编辑位置 + target_id + 文本哈希 + 长度信息 |
| `fill_and_save(..., edits, ...)` | 验证 → 过滤 → 应用 → 保存 |
| `convert_to_hwpx(...)` | HWP/HWPX/HWTX → HWPX 转换(无编辑) |
## 输入·输出模式(文件系统隔离应对)
所有工具都通过 **两种方式** 之一接收模板:
- **`template_path`** — 服务器运行的机器上的文件路径(例如 `C:/Users/.../template.hwpx`)。快速且无复制成本。
- **`template_b64` + `template_filename`** — base64 编码的原始字节 + 原始文件名(例如 `template_b64="UEsDBBQ...", template_filename="template.hwpx"`)。当聊天机器人会话和 MCP 服务器位于不同的文件系统上时使用(例如 Anthropic 沙盒 ↔ 用户 Windows)。
`fill_and_save` 还额外支持:
- **`output_path`** — 在服务器机器上保存结果文件
- **`return_output_bytes=True`** — 在响应中包含 `output_b64`(base64 字节)+ `output_size_bytes`。聊天机器人可以直接传递给用户。
### 聊天机器人会话(沙盒)调用示例
```python
import base64
file_bytes = open("template.hwpx", "rb").read()
b64 = base64.b64encode(file_bytes).decode("ascii")
# 1. 模板分析
desc = describe_template(template_b64=b64, template_filename="template.hwpx")
# 2. 查询可编辑位置
targets = list_template_targets(template_b64=b64, template_filename="template.hwpx")
# 3. 聊天机器人构造 edits 后应用
result = fill_and_save(
template_b64=b64,
template_filename="template.hwpx",
edits=[...],
return_output_bytes=True,
)
output_bytes = base64.b64decode(result["output_b64"])
# 将 output_bytes 作为附件传递给用户
```
## 安装
### 前置要求
- **Python 3.13+** (依赖 document-processor)
- **JDK 11+** (仅在 HWP 或 PDF 输入时需要。如果仅使用 DOCX·HWPX,可以省略)
- **git** (直接从 git 获取 document-processor)
### 项目安装
```powershell
git clone https://github.com/jaykim429/report-mcp.git
cd report-mcp
py -3.13 -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .
```
document-processor 的已知 `_edited` 累积错误通过 `apply_library_patches()` 在导入时自动 monkey-patch,因此无需额外处理。如果需要更永久的修复,可以应用 [`patches/document_processor_edited_cumulation.patch`](patches/document_processor_edited_cumulation.patch)。
## MCP 客户端注册
### Claude Code(项目级)
[`.claude/mcp_servers.json`](.claude/mcp_servers.json) 已包含,在此文件夹中运行 Claude Code 时会自动识别。
### Claude Desktop(全局)
在 `%APPDATA%\Claude\claude_desktop_config.json` 中添加:
```json
{
"mcpServers": {
"report-mcp": {
"command": "C:\\path\\to\\report-mcp\\.venv\\Scripts\\python.exe",
"args": ["-m", "report_mcp"],
"env": { "PYTHONIOENCODING": "utf-8" }
}
}
}
```
保存后重启 Claude Desktop,工具菜单中将显示 4 个工具。
## 聊天机器人接收的响应标准
所有工具都返回一个包含以下字段的字典:
```
status : ok / dry_run_ok / 其他 13 种失败状态
recovery_hint : 失败时,聊天机器人下次执行的操作(失败 target_id + 当前哈希)
```
### 定义的状态
| 状态 | 情况 |
|---|---|
| `ok` | 正常应用 |
| `dry_run_ok` | 仅验证通过(未写入文件) |
| `not_found` | 模板路径不存在 |
| `bad_argument` | 参数错误(负数 start,错误 target_kinds,目录路径等) |
| `edit_parse_failed` | edits 架构错误 |
| `duplicate_target_id` | 相同的 target_id 进行两次编辑 |
| `style_field_target_mismatch` | 属性 paragraph target(或相反) |
| `validation_failed` | 哈希不匹配等(failed_targets 中有详细信息) |
| `output_extension_mismatch` | 输出扩展名与模板格式不匹配 |
| `format_not_writable` | PDF 输出等 |
| `format_requires_java` | PDF·binary HWP 输入时 Java 未安装 |
| `file_error` / `permission_error` | OS 级文件问题 |
| `apply_failed` / `runtime_error` | 其他库异常 |
## 自身吸收的陷阱(聊天机器人无需关注)
1. **容器/子编辑冲突自动解决** — 同时编辑段落和单元格(或其中的 run)时,根据优先级决定冲突项,并将 `skipped_redundant_edits` 告知。
2. **重复 target_id 预检查** — 聊天机器人发送相同位置两次时,立即返回 `duplicate_target_id`。
3. **输出扩展名验证** — 错误发送 `.pdf` 时,安全拒绝 `output_extension_mismatch`。
4. **防御性类型处理** — `edits=None` / `edits="string"` 均正确处理。
5. **EAW 认知长度警戒线** — 一个韩文字符计算为 2 个显示单元格,准确反映在 `length_warnings` 中。
6. **document-processor `_edited` 累积错误 monkey-patch** — 即使重新安装 pip,也能保持幂等性。
7. **就地覆盖** — 在 `template_path == output_path` 情况下,通过临时文件安全处理。
## 项目结构
```
report-mcp/
├── src/report_mcp/
│ ├── server.py FastMCP 接线 + 4 个工具定义
│ ├── documents.py TemplateReader 类(读取 API)
│ ├── pipeline.py FillPipeline 类(验证→过滤→应用)
│ ├── length.py LengthGuardrail 类(EAW 宽度计算)
│ ├── errors.py ExceptionClassifier 类
│ ├── responses.py ok/error/not_found 工厂
│ └── patches.py document-processor monkey-patch
├── tests/ 10 个探针·测试套件
├── archive/ 一次性演示脚本
├── patches/ document-processor 补丁文件
└── .claude/ Claude Code MCP 注册设置
```
## 测试
```powershell
.\.venv\Scripts\Activate.ps1
foreach ($f in Get-ChildItem tests\*.py) { python $f.FullName }
```
10 个测试套件:
- `verify_patch_no_batching.py` — 库补丁验证(32 次编辑,一次调用)
- `probe_edge_cases.py` — 空编辑 / 重复 / 未知 target / 原地覆盖等 10 项
- `probe_pdf_input.py` — 无 Java 时 PDF 输入的干净拒绝
- `probe_round_two/three/four/five.py` — describe + StructuralEdit + StyleEdit + MCP transport + stdout 清洁等累计验证
- `probe_real_defects.py` — 6 个本质缺陷回归防止
- `test_mcp_production_ready.py` — 服务器指令 / 工具文档字符串 / batching / 单元格冲突等门控
- `test_length_guardrail.py` — EAW 长度警告
## 已知限制
- **HWP (二进制,.hwp)**:需要 Java 11+。仅支持输出为 HWPX。
- **PDF**:仅支持输入,不支持输出(库不支持)。建议请求保存为 DOCX。
- **图片删除**:当前不支持。库中无 `remove_image` 结构编辑。
- **显示宽度启发式**:`max_recommended_chars` 基于 EAW 近似。在非等宽字体中可能存在精度限制。
## 许可证 / 依赖库
该项目核心功能依赖 [CGINSIDE-ROOKIES/document-processor](https://github.com/CGINSIDE-ROOKIES/document-processor)。需要内部仓库访问权限。
## 相关文档
- [Model Context Protocol 官方](https://modelcontextprotocol.io/)
- [Anthropic FastMCP SDK](https://github.com/modelcontextprotocol/python-sdk)