Files
mcp/mcp_docx_server.py
2026-02-12 16:47:20 +08:00

180 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
基于 mcp_docx.py 封装的 MCP 服务器。
暴露两个主要工具:
- list_docx_images列出 DOCX 中的图片信息
- edit_docx: 进行文本替换 / 关键字上色 / 图片替换
支持两种传输方式:
- stdio默认本地使用
- sse远程调用通过 HTTP SSE 协议)
用法:
# 本地 stdio 模式
python mcp_docx_server.py
# SSE 远程模式(默认 0.0.0.0:8080
python mcp_docx_server.py --transport sse
python mcp_docx_server.py --transport sse --host 0.0.0.0 --port 8080
# 客户端连接地址:
# SSE 端点: http://<host>:<port>/sse
# 消息端点: http://<host>:<port>/messages/
注意:底层仍然完全复用 mcp_docx.py 中的逻辑,只是通过 MCP SDK 对外提供。
"""
import argparse
import os
from typing import Any, Dict, List, Optional
from mcp.server.fastmcp import FastMCP
from mcp_docx import get_images_info, process, _parse_span_replacement
mcp = FastMCP(
"docx-editor",
version="0.1.0",
description="DOCX 文本和图片编辑工具(基于 mcp_docx.py 封装)",
)
@mcp.tool()
async def list_docx_images(docx_path: str) -> List[Dict[str, Any]]:
"""
列出指定 DOCX 文件中的所有图片信息。
参数:
- docx_path: DOCX 文件的路径(相对或绝对)
返回:
- 图片信息列表,每一项包含:
- index: 图片在文档中的顺序(从 1 开始)
- media_file: DOCX 内部的资源路径
- ext: 图片扩展名
- docpr_name: Word 内部的图片名称
- width_cm / height_cm: 近似尺寸(厘米),可能为 None
"""
if not os.path.exists(docx_path):
raise FileNotFoundError(f"DOCX 文件不存在: {docx_path}")
imgs = get_images_info(docx_path)
# 为了避免泄露容器内部路径,屏蔽 abs_path 字段
for img in imgs:
img.pop("abs_path", None)
return imgs
@mcp.tool()
async def edit_docx(
input_docx: str,
output_docx: str,
replacements: Optional[List[Dict[str, str]]] = None,
image_replacements: Optional[List[Dict[str, Any]]] = None,
) -> Dict[str, Any]:
"""
使用原始 mcp_docx 逻辑对 DOCX 文件进行编辑。
支持:
- 纯文本替换
- 通过 <span color=\"FF0000\">关键字</span> 语法设置关键字颜色
- 替换指定序号的图片
参数:
- input_docx: 输入 DOCX 文件路径
- output_docx: 输出 DOCX 文件路径
- replacements: 文本替换规则列表,例如:
[
{\"old\": \"旧标题\", \"new\": \"<span color='#FF0000'>新标题</span>\"},
{\"old\": \"原文\", \"new\": \"新文\"}
]
- image_replacements: 图片替换规则列表,例如:
[
{\"index\": 1, \"file\": \"new_chart.png\"},
{\"index\": 2, \"file\": \"new_photo.jpg\"}
]
返回:
- {\"output_path\": 生成的 DOCX 绝对路径}
"""
if not os.path.exists(input_docx):
raise FileNotFoundError(f"输入 DOCX 文件不存在: {input_docx}")
if replacements is None:
replacements = []
if image_replacements is None:
image_replacements = []
# 解析文本替换与颜色关键字(复用 CLI 逻辑)
rep_pairs = []
color_keywords = []
for item in replacements:
old = item.get("old")
new_raw = item.get("new")
if not old:
continue
if new_raw is None:
new_raw = ""
new_plain, spans = _parse_span_replacement(new_raw)
rep_pairs.append((old, new_plain))
color_keywords.extend(spans)
# 处理图片替换参数
img_pairs = []
for item in image_replacements:
try:
idx = int(item.get("index"))
except (TypeError, ValueError):
continue
path = item.get("file")
if not path:
continue
if not os.path.exists(path):
raise FileNotFoundError(f"图片文件不存在: {path}")
img_pairs.append((idx, path))
# 复用原始处理函数
process(
input_docx=input_docx,
output_docx=output_docx,
replacements=rep_pairs,
image_replacements=img_pairs,
color_keywords=color_keywords,
)
return {"output_path": os.path.abspath(output_docx)}
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="DOCX MCP 服务器")
parser.add_argument(
"--transport",
choices=["stdio", "sse"],
default="stdio",
help="传输方式stdio本地或 sse远程 SSE",
)
parser.add_argument(
"--host",
default="0.0.0.0",
help="SSE 模式监听地址(默认 0.0.0.0",
)
parser.add_argument(
"--port",
type=int,
default=8080,
help="SSE 模式监听端口(默认 8080",
)
args = parser.parse_args()
if args.transport == "sse":
# SSE 远程模式:通过 HTTP 暴露 MCP 服务
mcp.settings.host = args.host
mcp.settings.port = args.port
print(f"🚀 MCP SSE 服务器启动中 → http://{args.host}:{args.port}/sse")
mcp.run(transport="sse")
else:
# 本地 stdio 模式
mcp.run(transport="stdio")