first commit
This commit is contained in:
136
mcp_docx_server.py
Normal file
136
mcp_docx_server.py
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
基于 mcp_docx.py 封装的 MCP 服务器。
|
||||
|
||||
暴露两个主要工具:
|
||||
- list_docx_images:列出 DOCX 中的图片信息
|
||||
- edit_docx: 进行文本替换 / 关键字上色 / 图片替换
|
||||
|
||||
注意:底层仍然完全复用 mcp_docx.py 中的逻辑,只是通过 MCP SDK 对外提供。
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from mcp.server.fastmcp import FastMCPServer
|
||||
|
||||
from mcp_docx import get_images_info, process, _parse_span_replacement
|
||||
|
||||
|
||||
server = FastMCPServer(
|
||||
"docx-editor",
|
||||
version="0.1.0",
|
||||
description="DOCX 文本和图片编辑工具(基于 mcp_docx.py 封装)",
|
||||
)
|
||||
|
||||
|
||||
@server.tool()
|
||||
async def list_docx_images(docx_path: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
列出指定 DOCX 文件中的所有图片信息。
|
||||
|
||||
参数:
|
||||
- docx_path: DOCX 文件的路径(相对或绝对)
|
||||
|
||||
返回:
|
||||
- 图片信息列表,每一项包含:
|
||||
- index: 图片在文档中的顺序(从 1 开始)
|
||||
- media_file: DOCX 内部的资源路径
|
||||
- abs_path: 解包后的绝对路径(仅用于调试)
|
||||
- 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
|
||||
|
||||
|
||||
@server.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__":
|
||||
# 通过 stdio 运行 MCP 服务器
|
||||
server.run()
|
||||
Reference in New Issue
Block a user