内容
# MCP Word — MCP 服务器 + Office 加载项
**版本**: 0.1.0
**日期**: 2025-08-13
**语言**: 仅限中文
使用本地 MCP 服务器(stdio)桥接至 Office.js 任务窗格,通过 Socket.IO 实现 HTTPS 连接。本项目构建了一个 MCP 服务器(`node server.js`)和一个 Office.js Word 加载项客户端,以实现 AI 驱动的文档编辑工作流。
## 架构
```mermaid
flowchart LR
A[Codex CLI] -->|stdio| B[MCP 服务器]
B -->|WebSocket| C[Office.js]
```
## 组件
### MCP 服务器 (`server.js`)
1. 从 `@modelcontextprotocol/sdk/server/mcp.js` 导入 `McpServer`
2. 从 `@modelcontextprotocol/sdk/server/stdio.js` 导入 `StdioServerTransport`
3. 通过 `registerTools` 动态加载工具,默认为 `tool.js` 或 `--simple` 时为 `tool_simple.js`
4. 工具模式遵循 `schema.json` 且为简单枚举(无 `anyOf`)
5. 将 MCP 工具负载(JSON)转发给 Socket.IO 客户端
6. 向 Office 加载项发出 `io.emit(toolName, toolParams)`
### Office 加载项 (`public/`)
- **`manifest.xml`**: 定义加载项 ID、版本、提供商、显示名称、描述。主机:文档;权限:读写文档
- **`taskpane.html`**: 加载 Office.js 和 Socket.io 客户端,包含 `taskpane.js`,渲染按钮或自动启动行为
- **`taskpane.js`**: 使用 `Office.onReady()` 进行 Word 主机检测,通过 `io()` 建立 WebSocket 连接,监听 MCP 工具事件,通过 `Word.run()` 调用 Word 函数,实现错误处理
- **`taskpane.yaml`**: 用于 Script Lab 代码片段导入,包含 Socket.io 等库
### 代码片段上传
通过 `package.json` 脚本上传到 gist:
```bash
npm run snippet # 运行:cd public && gh gist edit 5b44e6ba1c99baae62ebc0783e1469da --add taskpane.yaml
```
## 工作流程
1. **安装 MCP 服务器**: `npm install`
2. **启动服务器**: 使用 Codex CLI 的 stdio 或模拟主站,使用 Unix 管道提供输入
3. **侧载加载项**: 在 Word 中加载 `manifest.xml`
4. **发送 EditTask 请求**: 通过 Codex CLI 或其他服务发送请求,例如 `{ content: '...' }`
5. **实时编辑**: 加载项客户端实时接收编辑并将其应用于文档
## 先决条件
- Node.js 18.17+
- 启用侧载的 Microsoft Word(桌面版)
- 本地 HTTPS 证书受您的操作系统/Office 信任(自签名证书在开发环境中可用)
## 安装
```bash
npm install
```
## 运行服务器(需要 HTTPS)
服务器需要 TLS。使用 PEM 密钥/证书或 PFX 捆绑包启动服务器。
```bash
# PEM 密钥/证书
node server.js --key path/to/key.pem --cert path/to/cert.pem --port 3000
# 或 PFX/P12
node server.js --pfx path/to/cert.pfx --passphrase "your-passphrase" --port 3000
# 可选的详细日志记录
node server.js --key key.pem --cert cert.pem --port 3000 --debug
# 简单模式(用于流程测试,钩取 tool_simple.js)
node server.js --key key.pem --cert cert.pem --port 3000 --simple
```
提示:
- 在开发环境中使用自签名证书,并将其标记为受信任,以便 Office/浏览器接受 `https://localhost:3000`。
- 静态文件从 `public/` 目录提供服务。
- 端点:
- 健康检查:`GET https://localhost:3000/healthz`
### 创建本地开发证书
```bash
openssl req -x509 -newkey rsa:2048 -sha256 -days 365 -nodes \
-keyout key.pem -out cert.pem \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
# 可选的 PFX/P12 捆绑包
openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem -passout pass:your-passphrase
```
在您的操作系统密钥链中信任该证书,以便 Word 和浏览器接受它。
## 配置 MCP 客户端
通过 Node 将您的 MCP 客户端指向运行 `server.js`。
**Codex CLI** (`.codex/config.toml`):
```toml
# 放在 ./.codex/config.toml(项目)或 ~/.codex/config.toml(用户)
[mcp_servers.mcp_word]
command = "node"
args = [
"/absolute/path/to/server.js",
"--key", "/abs/path/to/key.pem",
"--cert", "/abs/path/to/cert.pem",
"--port", "3000"
]
cwd = "/absolute/path/to/project"
# 可选:环境变量
env = { NODE_ENV = "production" }
```
注意:
- 使用绝对路径以确保可靠性。
- 如果使用 PFX/P12 捆绑包:请将 `--key/--cert` 替换为 `--pfx /abs/cert.pfx --passphrase "your-passphrase"`。
- 在保存配置后重启 Codex 客户端;工具 `ping` 和 `editTask` 应该可用。
**Claude Desktop** (设置摘录):
```json
{
"mcpServers": {
"mcp-word": {
"command": "node",
"args": ["/absolute/path/to/server.js", "--key", "/abs/key.pem", "--cert", "/abs/cert.pem", "--port", "3000"],
"cwd": "/absolute/path/to/project"
}
}
}
```
**Claude CLI**:
```bash
claude mcp add mcp-word -- node /absolute/path/to/server.js --key /abs/key.pem --cert /abs/cert.pem --port 3000
```
## Office 加载项
连接 Word 到服务器的两种方法:
**1) 侧载 manifest**
- 打开 Word → 加载项 → 侧载 `public/manifest.xml`
- manifest 指向 `public/taskpane.html`
- 确保相同的宿主/端口和受信任的证书
**2) Script Lab(替代方案)**
- 选项 A(粘贴 JS):安装 Script Lab,创建一个新脚本并粘贴 `public/taskpane.js`,并添加库 `https://cdn.socket.io/4.7.5/socket.io.min.js`。
- 选项 B(导入 YAML):在 Script Lab 中,从 https://gist.github.com/WangChengYeh/5b44e6ba1c99baae62ebc0783e1469da 导入
## 工具
### editTask
- **目的**: 通过 Socket.IO(事件名称 `editTask`)向加载项发送编辑指令
- **模式**: 遵循 `schema.json` 规则且为简单枚举(无 `anyOf` 模式)
- **参数**:
- `content`(字符串,必填):要插入/替换的文本
- `action`("insert" | "replace" | "append",默认为 "insert")
- `target`("cursor" | "selection" | "document",默认为 "selection")
- `taskId`(字符串,可选)
- `meta`(对象,可选)
JSON-RPC 示例(MCP stdio 帧):
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "editTask",
"arguments": {
"content": "Hello from MCP",
"action": "insert",
"target": "selection"
}
}
}
```
### ping
- **目的**: 健康检查;回声 `message` 或返回 `"pong"`
- **模式**: 简单工具注册,无复杂模式
## 调试
- `--debug`: 将详细日志和错误输出到 `debug.log`
- 记录 stdio 流输入/输出到 `debug.log`
- 在启用调试时为 stdin 和 stdout 添加管道以记录和转发
- 记录 `debug.log` 中的 JSON 字符串,Socket.IO 发送前和接收后
- 健康检查端点:`GET https://localhost:3000/healthz` 显示已连接的客户端
- `debug.log` 中的流日志记录:
- `[time][stdin] json string`: 接收的原始 MCP stdio 帧
- `[time][stdout] json string`: 原始 MCP stdio 响应
- `[time][socket:send] json string`: 转发的工具调用到 Socket.IO
- `[time][socket.recv] json string`: 从加载项接收(例如,`edit-complete`)
## 测试
### 测试模式
- 简单模式:`server.js --simple` 钩取 `tool_simple.js`(流程测试)
- 单元测试:`npm run test:simple`
- 集成测试:`npm run test:int:simple`
- 正常模式:`server.js`(无 `--simple`)钩取 `tool.js`(常规使用)
- 单元测试:`npm test`
- 集成测试:`npm run test:int`
### 单元测试
- `test.sh`: 使用模拟 stdio 进行单元测试,用于 MCP 客户端和 Office 的套接字连接
- 使用 shell 管道提供输入
- 生成测试 JavaScript 作为套接字客户端
- 在测试前准备 `package.json`
- 默认测试端口:3100(3000 保留用于正常使用)
- `test_simple.sh`: 使用 `tool_simple.js` 测试 `server.js --simple` 模式
通过 npm 命令运行:
```bash
# 简单模式单元测试
npm run test:simple
# 完整单元测试
npm test
```
### 集成测试
- `test.js`: 结合 MCP 客户端 + MCP 服务器(`server.js`)的集成测试
- 使用 `@modelcontextprotocol/sdk/client/index.js` 中的 `Client`
- 列出工具并调用工具(例如,`ping`、`editTask`)
- `test_simple.js`: 测试 `server.js --simple` 模式
通过 npm 命令运行:
```bash
# 简单模式集成测试
npm run test:int:simple
# 完整集成测试
npm run test:int
```
### 端到端测试
使用提供的脚本验证端到端行为。它自动生成开发证书,启动服务器,打开 Socket.IO 客户端,并通过 stdio 发送 MCP 帧。
```bash
# 默认烟雾测试
./test.sh
# 管道自定义 MCP JSONL(每行一个 JSON 对象)
echo '{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"editTask","arguments":{"content":"PipeMsg","action":"insert","target":"selection"}}}' | ./test.sh
# 多行
cat <<'EOF' | ./test.sh
{"jsonrpc":"2.0","id":11,"method":"tools/call","params":{"name":"ping","arguments":{"message":"hello"}}}
{"jsonrpc":"2.0","id":12,"method":"tools/call","params":{"name":"editTask","arguments":{"content":"FromSTDIN","action":"insert","target":"selection"}}}
EOF
```
注意:
- 代理发出名为 MCP 工具的 Socket.IO 事件。对于 `editTask`,事件是 `editTask`,有效载荷是工具参数对象。
- 脚本从第一个 `editTask` 行中提取预期内容。
- 为测试方便,接受自签名证书。
## 可扩展性
- 支持额外的 `EditTask` 类型(表格、图像、格式)
- 添加 WebSocket 身份验证、日志记录和错误跟踪
## 项目结构
```
mcp_word/
├── server.js # MCP stdio + Socket.IO 桥接(HTTPS)
├── tool.js # MCP 工具注册 + Socket.IO 转发
├── tool_simple.js # 简化的工具集用于流程测试(--simple)
├── public/
│ ├── manifest.xml # Office 加载项清单
│ ├── taskpane.html # 最小任务窗格
│ ├── taskpane.js # 通过 Office.js 应用编辑命令
│ └── taskpane.yaml # Script Lab 代码片段用于导入
├── test.sh # 端到端测试运行器(JSONL over stdio)
├── test_simple.sh # 单元测试运行器,用于 --simple
├── test.js # 集成测试(正常模式)
├── test_simple.js # 集成测试(简单模式)
├── SPEC.md # 精炼规范
└── README.md
```
## 文档要求
本 README 遵循 SPEC 要求,并按顺序包含以下内容:
- 先决条件:Node.js 版本、Microsoft Word 和受信任的 HTTPS 证书说明
- 安装:`npm install`
- 运行服务器:HTTPS 启动示例(PEM 和 PFX),以及 `--debug`
- 创建本地开发证书:OpenSSL 命令生成 PEM 和 PFX
- 配置 MCP 客户端:通过 `.codex/config.toml` 设置 Codex 客户端
- Office 加载项:两种选项(侧载 manifest 或 Script Lab 代码片段)
- 工具:文档 `editTask` 和 `ping` 工具及其参数和示例
- 调试:`--debug` 和 `debug.log` 详细信息
- 测试:如何通过 npm 命令运行测试
- 项目结构和许可证
## 许可证
请参阅 LICENSE。