office-mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
office-mcp
一个 MCP 服务器:让 AI agent 能读 Word、Excel、PPT、PDF。
模型能读代码、能读网页,但读不了你的 .docx。这个项目用 MCP 协议把办公文档接给 agent——接上之后,一句"看看这份报告讲了什么"就能直接出结论。
为什么是 MCP
方案 | 问题 |
写个脚本让 agent 调 | 每个 agent 都要单独适配 |
把文档转成 txt 再喂 | 丢结构(表格、标题层级、备注全没了) |
MCP 服务器 | 一次实现,任何支持 MCP 的客户端都能用 |
MCP(Model Context Protocol)是标准协议,stdio 上跑 JSON-RPC 2.0。接一次,Claude Desktop / Cline / VS Code Copilot / DeepSeek Harness 都能用。
Related MCP server: MinerU Document Explorer
架构
┌─────────────┐ JSON-RPC over stdio ┌──────────────┐
│ AI agent │ ◀─────────────────────▶ │ office-mcp │
│ (MCP 客户端) │ initialize/tools/call │ server.py │
└─────────────┘ └──────┬───────┘
│
┌──────────┴──────────┐
▼ ▼
python-docx openpyxl
python-pptx pymupdf四个工具
工具 | 输入 | 输出 |
|
| Markdown:标题、段落、列表、表格(按原文顺序) |
|
| 列出所有工作表,指定表转 Markdown 表格(取公式计算结果) |
|
| 按页输出标题、正文要点、表格、演讲者备注 |
|
| 按页范围提文本;扫描件会明确说"没有文字层" |
所有输出都有截断上限,防止 300 页的文档把上下文撑爆。
快速开始
1. 装依赖
pip install -r requirements.txt四个库各管一种格式,只读 Word 就只装 python-docx。
2. 自检
python server.py --selftest "D:\某处\报告.docx"会列出工具清单,并真的读一次那份文档。
3. 接进 MCP 客户端
配置形如(各客户端字段名略有差异):
{
"mcpServers": {
"office": {
"command": "python",
"args": ["D:\\path\\to\\office-mcp\\server.py"]
}
}
}注意:
command要用装了上述依赖的那个 Python。如果系统 Python 没装库,就填虚拟环境或其它解释器的绝对路径。
4. 手动验证协议
python examples/test_client.py它会把完整对话跑一遍:initialize → tools/list → 三次 tools/call(真实文档)→ 两个错误场景。
实测输出:
[id=1] initialize -> {'name': 'office-mcp', 'version': '1.0.0'} 协议 2024-11-05
[id=2] tools/list -> 4 个工具: ['doc_read', 'sheet_read', 'slide_read', 'pdf_extract']
[id=3] ✅ 返回 631 字符:
# 家庭用电分析报告.docx
(家庭用电分析报告.docx:53 段、3 表)
| 报告名称 | 家庭用电情况分析报告 |协议实现说明
不用官方 SDK,手写不到 200 行,好处是协议长什么样一目了然:
# 一条请求进来
{"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "doc_read", "arguments": {"path": "报告.docx"}}}
# 一条响应出去
{"jsonrpc": "2.0", "id": 3,
"result": {"content": [{"type": "text", "text": "# 报告.docx\n…"}], "isError": false}}三个容易踩的点:
stdout 只能出 JSON。任何
print调试都会污染协议流,日志必须走stderr。通知没有
id,不能回复。notifications/initialized回了就会让客户端困惑。工具异常不能弄死服务器。工具里任何异常都转成
isError: true的响应,循环继续。
接入 DeepSeek Harness(实测记录)
我把这个服务接进 DSH 时踩了两个坑,都修好了,记录在这里省得别人再踩。
抓到的真实协议流
DSH 内置的 MCP 客户端比 2024-11-05 规范要新,握手时会先探测一个 server/discover:
IN <<< {"method":"server/discover","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28", ...}}}
OUT >>> {"error":{"code":-32601,"message":"不支持的方法: server/discover"}}
IN <<< {"method":"initialize","params":{"protocolVersion":"2025-11-25", ...}}
OUT >>> {"protocolVersion":"2024-11-05","capabilities":{"tools":{}}, ...}
IN <<< {"jsonrpc":"2.0","method":"notifications/initialized"}
IN <<< {"method":"tools/list","jsonrpc":"2.0","id":1}
OUT >>> {"id":1,"result":{"tools":[{"name":"doc_read", ...}]}}好消息:回 2024-11-05 它仍然接受,向下兼容。拒掉 server/discover 也不影响握手。
坑一:Windows 上中文变乱码,还会崩
接上后工具描述显示成 ��ȡ Word。原因是 Python 连管道时默认用 GBK,而客户端按 UTF-8 解码。
更麻烦的是会直接崩——文档里有 ✅ 这种 GBK 编不出来的字符:
'gbk' codec can't encode character '\u2705' in position 22双保险修法(server.py 里的 _force_utf8 + _dumps):
for stream in (sys.stdout, sys.stderr):
stream.reconfigure(encoding="utf-8", errors="replace", newline="\n")
# 万一 reconfigure 没生效,就退化成纯 ASCII 输出(中文变 \uXXXX 转义)
ascii_only = (sys.stdout.encoding or "").lower().replace("-", "") != "utf8"
json.dumps(payload, ensure_ascii=ascii_only)JSON 客户端解析转义后会还原成正常中文,所以任何控制台编码下都不会崩。
坑二:回复"通知"会被判违规
JSON-RPC 规定没有 id 的消息是通知,不能回复。我早期对未知通知也回了一条 id: null 的错误,客户端直接判定协议违规断开。
is_notification = "id" not in request
...
if is_notification:
return None坑三:残留多个子进程 → 工具调用永远超时(最坑的一个)
症状:握手、tools/list 全正常,工具也确实注册上了,但一调用就 Request timed out 或 Connection closed,服务端日志里根本收不到 tools/call。
排查过程(值得记下来):
以为编码问题 → 修了,没用
以为协议不兼容 → 抓包发现握手完全正常
以为要重启 DSH → 重启了,还是超时
最后用任务管理器数进程,发现同时有 2 个
server.py在跑
结论:调试时反复开关插件、手动杀进程,会留下多个实例;工具调用绑在最早那个已经死掉的实例上,请求发进了一个没有读者的管道——所以服务端永远收不到,客户端只能等到超时。
修法:把所有 server.py 进程全部结束(客户端会自动重连拉起一个干净的),再调用就通了。
一句话教训:MCP 是"一个连接一个进程"的模型,调试时只留一个实例,别靠反复开关插件去撞状态。
DSH 里不需要写插件代码,一个纯配置文件就能挂上(样例见 examples/dsh-bundle/):
- insert:
- id: office-mcp
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: office
transport: stdio
command: '<装了依赖的那个 python 绝对路径>'
args:
- '<server.py 的绝对路径>'
failOnStartupError: true装好后工具名是 mcp__office__doc_read 这种格式。
接入后的实测结果
四个工具在真实文档上都跑通了:
工具 | 实测对象 | 结果 |
| 家庭用电分析报告.docx | 53 段 / 3 表,表格按原位置还原 |
| 家庭用电数据分析.xlsx | 识别 3 个工作表,正确读出月度用电表 |
| 家庭用电情况分析.pptx | 7 页全部输出,含正文要点 |
| 一份 1 页简历 PDF | 整页文字完整提取 |
一个实际暴露的体验问题:Excel 里算出来的 13.290322580645162 会原样进表格,模型没法用。已在 _cell() 里收敛到 4 位小数(13.2903),整数不带 .0,日期转 ISO。
调试建议
给 bundle 加一个环境变量就能看协议原文,排查编码/协议问题非常有用:
env:
OFFICE_MCP_DEBUG: '1'之后每次收发都会追加到 %TEMP%\office-mcp-debug.log,形如:
IN <<< {"method":"tools/call", ...}
OUT >>> {"jsonrpc":"2.0","id":2,"result":{"content":[...]}}实现细节
Word 按原顺序输出
document.paragraphs 和 document.tables 是两个独立列表,分别遍历会丢掉表格和段落的相对位置。所以直接遍历 XML body:
for child in document.element.body.iterchildren():
tag = child.tag.split("}")[-1]
if tag == "p": ...Paragraph(child, document)
elif tag == "tbl": ...Table(child, document)Excel 取公式结果而不是公式
openpyxl.load_workbook(path, data_only=True)代价:如果文件是程序生成、从未被 Excel 打开过,公式没有缓存值,读出来是 None。这是 Excel 的机制,不是 bug。
截断要说清楚
不是静默截断,而是明确告诉模型:
…(已截断,原文 24311 字符,只返回前 8000 字符)这样模型知道"我没看到全部",不会拿半份内容下结论。
已知限制
只读。写入工具还没做——写坏原文件是最糟的失败模式,要单独设计(先写副本、变更前备份)。
不支持旧格式
.doc/.xls,请先另存为新格式。扫描件 PDF 提不出文字(没有文字层),需要 OCR,本项目不做。
复杂排版(艺术字、SmartArt、文本框嵌套)读不干净,只保证正文、表格、备注。
slide_read不输出图表里的数据(图表是图片级对象)。
Roadmap
doc_write:Markdown → Word(先写副本,不覆盖原文件)sheet_append:往工作表追加行office_convert:docx ↔ md ↔ pdf批量:一次读整个目录的文档并汇总
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Convert PDFs, Office files, spreadsheets and images to clean Markdown, sized for agent context.
Convert, create and edit Word, PowerPoint, Excel and PDF documents from any AI agent.
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Document conversion and OCR for AI agents: PDF, Office docs, images to text.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to read documents in Excel, DOCX, PDF, and TXT formats via MCP protocol.1155 PyPI23MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to search, deep-read, and build knowledge bases from Markdown, PDF, DOCX, and PPTX documents via MCP tools for retrieval, document navigation, and ingestion.25 npm650MIT
- AlicenseAqualityAmaintenanceConvert PDF, DOCX, HTML, and URLs into clean, LLM-ready markdown with tables preserved and boilerplate stripped, through three MCP tools (URL, local file, or raw bytes). Hosted API with no local dependencies; 50 free conversions with a self-serve key, then $0.002 per call.359 npmMIT
- AlicenseAqualityAmaintenanceEnables LLMs to read, search, edit, and create Excel, Word, and PowerPoint files through MCP, including sheet/table operations, slide and chart creation, text replacement, and automatic backups.29MIT