#!/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://:/sse # 消息端点: http://:/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 文件进行编辑。 支持: - 纯文本替换 - 通过 关键字 语法设置关键字颜色 - 替换指定序号的图片 参数: - input_docx: 输入 DOCX 文件路径 - output_docx: 输出 DOCX 文件路径 - replacements: 文本替换规则列表,例如: [ {\"old\": \"旧标题\", \"new\": \"新标题\"}, {\"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")