首页/新闻资讯/正文详情

从零开发Excel MCP Server:让AI真正操作表格的完整实战指南

发布时间:2026/11/3 12:16:35 来源:云帆数科 栏目:资讯中心
从零开发Excel MCP Server:让AI真正操作表格的完整实战指南
1. 从手工搬砖到智能流水线我为什么要自己写一个 MCP去年年底我接手了一个数据清洗的活儿客户丢过来 37 个 Excel 文件每个文件里 8 到 12 个 sheet字段命名五花八门有的叫客户名称有的叫客户名还有的写甲方单位。我一开始用 Python 的 pandas 硬怼写了 400 多行脚本跑一遍要改一遍改到最后我自己都记不清哪个函数处理哪个文件了。那段时间我每天早上打开电脑的第一件事就是对着满屏的 traceback 发呆。后来我接触到了 MCP 这个概念。MCP 全称是 Model Context Protocol翻译过来叫模型上下文协议。你可以把它理解成一套标准化的插座以前你的 AI 助手想调用外部工具得给每个工具单独写一套对接代码就像每个电器都得配一个专属插头有了 MCP 之后所有工具都统一成一种接口AI 想用哪个就插哪个。这个协议最早是 Anthropic 提出来的现在已经被越来越多的开发者和平台采纳成了 AI Agent 领域一个绕不开的基础设施。那为什么我要拿 Excel 处理来练手原因很实在Excel 是绝大多数职场人每天都在用的东西但它的自动化程度极低。你让一个不懂编程的同事去合并 20 个表格他可能得干一整个下午你让 AI 直接操作 Excel它又没有手只能给你输出一段代码让你自己去跑。MCP 恰好补上了这个缺口——它让 AI 真正拥有了操作 Excel 的手而且这只手是按标准协议接上去的换一个 AI 客户端照样能用。这篇文章适合三类人看第一类是有一定 Python 基础、想入门 MCP 开发但不知道从哪下手的开发者第二类是天天跟 Excel 打交道、想用 AI 把自己从重复劳动里捞出来的职场人第三类是对 AI Agent 工作流感兴趣、想搞清楚 MCP 到底怎么回事的技术爱好者。我会从零开始把整个开发过程拆开揉碎讲清楚包括我踩过的坑、试过的错、以及最后跑通的完整方案。2. 动手之前先想清楚MCP 到底解决什么问题2.1 没有 MCP 的世界是什么样的在 MCP 出现之前如果你想让 AI 帮你处理 Excel通常有这么几条路第一条路是让 AI 生成代码你自己跑。比如你问 ChatGPT帮我写一段 Python 合并 Excel 的代码它给你一段你复制到本地装依赖改路径跑。问题是每次需求变了你都得重新问一遍而且 AI 看不到你的实际数据生成的代码经常因为列名不对、编码不对、sheet 名不对而报错。第二条路是用平台自带的工作流工具。像 Coze 工作流、n8n 工作流这类平台确实可以拖拽式地搭建自动化流程也能对接 Excel。但问题是你的数据得上传到人家的平台上公司内部的数据合规过不了而且平台的能力边界是固定的你想加一个自定义的处理逻辑对不起不支持。第三条路是自己写一个 Agent把 Excel 操作封装成函数。这条路最灵活但工作量也最大。你得自己定义函数签名、自己写调用逻辑、自己处理 AI 返回的参数解析。而且你写的这套东西只对你自己的 Agent 有效换一个 AI 客户端就得重写一遍。我三条路都走过。第一条路太累第二条路太死第三条路太慢。MCP 的出现本质上是把第三条路标准化了——你只需要按照协议写一次工具所有支持 MCP 的客户端都能用。2.2 MCP 的核心机制三个角色各干各的MCP 的架构其实不复杂核心就三个角色Host宿主就是你用的 AI 客户端比如某个支持 MCP 的桌面应用或者 IDE 插件。它负责跟用户对话决定什么时候需要调用工具。Client客户端宿主内部的一个组件负责跟 Server 建立连接、发送请求、接收响应。你可以把它理解成宿主和服务器之间的翻译官。Server服务器就是你写的那个程序它暴露了一组工具Tools、资源Resources和提示模板Prompts等着客户端来调用。三者之间的关系是Host 决定要做什么Client 负责怎么传话Server 负责实际干活。这种分工的好处是Server 完全不知道 Host 是谁Host 也不关心 Server 内部怎么实现双方只通过标准协议通信。2.3 为什么选 Excel 作为第一个 MCP 项目我选 Excel 作为练手项目有三个考虑第一需求足够具体。读取 Excel、写入 Excel、合并多个 sheet这些操作边界清晰不像帮我分析一下数据那么模糊。边界清晰意味着工具定义好写测试也好测。第二反馈足够直观。你写完一个工具跑一下打开 Excel 文件一看数据对不对一目了然。不像做一些抽象的系统集成出了问题得层层排查。第三复用价值足够高。Excel 处理是典型的一次开发、到处使用的场景。你今天写好了读取工具明天可以用它做数据清洗后天可以用它做报表生成大后天可以用它做简历筛选工作流。投入产出比很高。提示如果你之前没接触过 MCP建议先去官网把协议规范大致翻一遍重点看 Tools 和 Resources 这两部分的定义。不用背有个印象就行实际写的时候再回来查。3. 环境搭建把地基打牢再盖楼3.1 Python 环境准备MCP 的官方 SDK 目前对 Python 的支持是最好的所以我们的 Server 用 Python 来写。如果你还没装 Python去官网下载 3.10 以上的版本。为什么强调 3.10因为 MCP SDK 用到了不少新版本的语法特性3.9 及以下会报一些莫名其妙的错。装完 Python 之后我强烈建议你用虚拟环境。我见过太多人因为全局环境里包版本冲突调了半天以为是代码问题结果是环境问题。创建虚拟环境的命令很简单python -m venv mcp-excel-env source mcp-excel-env/bin/activate # Windows 用 mcp-excel-env\Scripts\activate激活之后你的命令行前面会出现一个括号里面是环境名说明你已经进到虚拟环境里了。接下来装依赖pip install mcp openpyxl pandas这里解释一下三个包的分工mcp是官方 SDK提供协议实现openpyxl负责读写 xlsx 文件它能保留格式和公式pandas负责数据处理做筛选、聚合、透视表特别方便。有人会问为什么不只用 pandas因为 pandas 写出去的 Excel 会丢掉原有格式而 openpyxl 可以做到只改数据不动样式。3.2 开发工具的选择写 MCP Server 用什么编辑器都行但我推荐 VS Code原因是它的 Python 插件对类型提示支持很好而 MCP SDK 大量使用了类型注解有提示写起来会顺畅很多。配置的时候注意选对解释器一定要选你刚才创建的虚拟环境里的那个 Python别选成全局的了。如果你用的是 PyCharm也没问题在项目设置里把解释器指向虚拟环境即可。关键是别混用我见过有人终端里激活了虚拟环境但编辑器里用的还是全局解释器结果装包装到了全局跑代码的时候又找不到包。3.3 验证环境是否就绪装完之后跑一段最简单的代码验证一下import mcp import openpyxl import pandas as pd print(mcp version:, mcp.__version__ if hasattr(mcp, __version__) else unknown) print(openpyxl version:, openpyxl.__version__) print(pandas version:, pd.__version__)如果三行都能正常打印出版本号说明环境没问题。如果报ModuleNotFoundError八成是解释器选错了回去检查一下。注意不要在生产环境里用pip install直接装到系统 Python 里。我有个朋友图省事结果系统里一堆包版本打架最后重装了系统。虚拟环境多花两分钟能省你两小时。4. 核心工具设计让 AI 真正会用Excel4.1 工具划分的原则写 MCP Server 最容易犯的错误就是想把所有功能塞进一个工具里。比如搞一个handle_excel工具参数里传一个action根据 action 的值决定是读还是写还是合并。这种设计看起来省事实际上 AI 用起来特别容易出错——它得先猜 action 该填什么再猜其他参数怎么配合出错率极高。我的经验是一个工具只做一件事工具名要能自解释。比如read_excel_sheet就是读一个 sheetwrite_excel_cell就是写一个单元格merge_excel_files就是合并多个文件。AI 看到工具名和描述基本就知道该在什么场景下调用它。按照这个原则我设计了六个核心工具工具名功能关键参数list_sheets列出 Excel 文件里所有 sheet 名file_pathread_sheet读取指定 sheet 的数据file_path, sheet_name, max_rowswrite_cell写入单个单元格file_path, sheet_name, cell, valuewrite_range批量写入一个区域file_path, sheet_name, start_cell, datamerge_files合并多个 Excel 文件file_paths, output_path, key_columnfilter_rows按条件筛选行file_path, sheet_name, column, condition这六个工具覆盖了 80% 的日常 Excel 操作。你可能会问为什么不做排序、透视表、图表因为这些操作要么可以用 pandas 在读取之后处理要么实现起来太复杂、AI 调用时参数太多容易出错。工具设计要克制宁可少而精不要多而杂。4.2 工具描述怎么写才有效MCP 工具的 description 字段非常关键它是 AI 决定要不要调用这个工具的主要依据。很多人写描述就一句话读取 Excel 文件这种描述 AI 看了跟没看一样。好的描述应该包含四个要素做什么、什么时候用、参数含义、返回什么。举个例子mcp.tool() def read_sheet(file_path: str, sheet_name: str, max_rows: int 100) - str: 读取 Excel 文件中指定 sheet 的数据。 当用户需要查看某个 Excel 文件的内容、或者需要基于表格数据做分析时使用此工具。 如果用户没有指定 sheet 名先用 list_sheets 工具获取所有 sheet 名。 Args: file_path: Excel 文件的绝对路径支持 .xlsx 和 .xls 格式 sheet_name: 要读取的 sheet 名称区分大小写 max_rows: 最多返回多少行数据默认 100避免返回数据过大 Returns: 以 Markdown 表格格式返回的数据内容包含表头和前 max_rows 行 这段描述里当用户需要查看...告诉 AI 什么时候用如果用户没有指定...告诉 AI 前置步骤Args部分解释每个参数Returns说明返回格式。AI 读完这段描述基本不会用错。4.3 返回值格式的选择MCP 工具的返回值可以是字符串、可以是 JSON、也可以是结构化内容。我试过几种格式最后发现Markdown 表格是最适合 Excel 数据的。为什么因为 AI 读 Markdown 表格的能力很强它能直接理解表头和数据行的对应关系。如果你返回 JSONAI 也能理解但 JSON 的嵌套结构在对话里展示出来很占篇幅用户看着也累。如果你返回纯文本用逗号分隔AI 容易把数据里的逗号当成分隔符解析出错。Markdown 表格还有个好处是用户直接复制粘贴到文档里就能用不需要额外转换。这一点在做报表场景下特别实用。实操心得返回数据的时候一定要限制行数。我有一次忘了限制读了一个 5 万行的表返回的字符串直接把上下文撑爆了AI 后面的对话全部失效。后来我加了 max_rows 参数默认 100用户需要更多可以自己调。5. 完整实现从零写出可运行的 MCP Server5.1 项目结构先把项目骨架搭起来mcp-excel-server/ ├── server.py # 主程序 ├── tools/ │ ├── __init__.py │ ├── reader.py # 读取相关工具 │ ├── writer.py # 写入相关工具 │ └── merger.py # 合并相关工具 ├── utils/ │ ├── __init__.py │ └── excel_helper.py # 通用辅助函数 └── requirements.txt有人会问一个文件写完不行吗行但不好维护。工具多了之后一个文件几百行改一个地方得翻半天。拆成模块之后读取的问题去 reader.py 找写入的问题去 writer.py 找定位快很多。5.2 主程序入口server.py 负责初始化 MCP Server 并注册所有工具from mcp.server.fastmcp import FastMCP from tools.reader import register_reader_tools from tools.writer import register_writer_tools from tools.merger import register_merger_tools mcp FastMCP(excel-processor) register_reader_tools(mcp) register_writer_tools(mcp) register_merger_tools(mcp) if __name__ __main__: mcp.run()这里用的是 FastMCP它是官方提供的一个高层封装比直接用底层 API 简单很多。mcp.run()默认使用 stdio 传输方式也就是通过标准输入输出跟客户端通信。这种方式的好处是不需要开端口本地跑最安全。5.3 读取工具的实现reader.py 里实现 list_sheets 和 read_sheetimport openpyxl from mcp.server.fastmcp import FastMCP def register_reader_tools(mcp: FastMCP): mcp.tool() def list_sheets(file_path: str) - str: 列出 Excel 文件中所有 sheet 的名称。 当用户提到某个 Excel 文件但不确定里面有哪些 sheet 时先用此工具查看。 Args: file_path: Excel 文件的绝对路径 Returns: 所有 sheet 名称的列表每行一个 try: wb openpyxl.load_workbook(file_path, read_onlyTrue) names wb.sheetnames wb.close() return \n.join(f- {name} for name in names) except FileNotFoundError: return f错误找不到文件 {file_path} except Exception as e: return f错误{str(e)} mcp.tool() def read_sheet(file_path: str, sheet_name: str, max_rows: int 100) - str: 读取 Excel 文件中指定 sheet 的数据以 Markdown 表格返回。 try: wb openpyxl.load_workbook(file_path, read_onlyTrue, data_onlyTrue) if sheet_name not in wb.sheetnames: return f错误sheet {sheet_name} 不存在可用的有{, .join(wb.sheetnames)} ws wb[sheet_name] rows [] for i, row in enumerate(ws.iter_rows(values_onlyTrue)): if i max_rows: break rows.append(row) wb.close() if not rows: return 该 sheet 为空 header rows[0] md | | .join(str(h) if h is not None else for h in header) |\n md | | .join(--- for _ in header) |\n for row in rows[1:]: md | | .join(str(c) if c is not None else for c in row) |\n return md except Exception as e: return f错误{str(e)}注意data_onlyTrue这个参数它的作用是读取公式的计算结果而不是公式本身。如果你不加这个参数读出来的单元格值可能是SUM(A1:A10)这样的公式字符串AI 看了没法用。5.4 写入工具的实现writer.py 里实现 write_cell 和 write_rangeimport openpyxl from mcp.server.fastmcp import FastMCP def register_writer_tools(mcp: FastMCP): mcp.tool() def write_cell(file_path: str, sheet_name: str, cell: str, value: str) - str: 向 Excel 指定单元格写入一个值。 Args: file_path: Excel 文件路径 sheet_name: sheet 名称 cell: 单元格坐标如 A1、B3 value: 要写入的值 Returns: 操作结果说明 try: wb openpyxl.load_workbook(file_path) if sheet_name not in wb.sheetnames: wb.create_sheet(sheet_name) ws wb[sheet_name] ws[cell] value wb.save(file_path) wb.close() return f已成功将 {value} 写入 {sheet_name}!{cell} except Exception as e: return f错误{str(e)} mcp.tool() def write_range(file_path: str, sheet_name: str, start_cell: str, data: list) - str: 从指定起始单元格开始批量写入二维数据。 Args: file_path: Excel 文件路径 sheet_name: sheet 名称 start_cell: 起始单元格如 A1 data: 二维列表每个子列表代表一行 Returns: 操作结果说明 try: wb openpyxl.load_workbook(file_path) if sheet_name not in wb.sheetnames: wb.create_sheet(sheet_name) ws wb[sheet_name] start_col openpyxl.utils.column_index_from_string( .join(c for c in start_cell if c.isalpha()) ) start_row int(.join(c for c in start_cell if c.isdigit())) for r_offset, row in enumerate(data): for c_offset, val in enumerate(row): ws.cell( rowstart_row r_offset, columnstart_col c_offset, valueval ) wb.save(file_path) wb.close() return f已成功写入 {len(data)} 行数据到 {sheet_name}!{start_cell} except Exception as e: return f错误{str(e)}这里有个细节值得说write_cell里如果 sheet 不存在我选择自动创建而不是报错。为什么因为 AI 调用工具的时候它不一定知道 sheet 存不存在。如果报错AI 得再调一次 list_sheets再调一次 write_cell多一轮交互。自动创建虽然看起来越权了但实际使用体验好很多。5.5 合并工具的实现merger.py 实现 merge_filesimport pandas as pd from mcp.server.fastmcp import FastMCP def register_merger_tools(mcp: FastMCP): mcp.tool() def merge_files(file_paths: list, output_path: str, key_column: str None) - str: 合并多个 Excel 文件到一个文件。 Args: file_paths: 要合并的 Excel 文件路径列表 output_path: 输出文件路径 key_column: 可选的合并依据列名如果指定则按此列做外连接否则纵向堆叠 Returns: 操作结果说明 try: dfs [] for path in file_paths: df pd.read_excel(path) df[_source_file] path.split(/)[-1] dfs.append(df) if key_column: result dfs[0] for df in dfs[1:]: result pd.merge(result, df, onkey_column, howouter) else: result pd.concat(dfs, ignore_indexTrue) result.to_excel(output_path, indexFalse) return f已合并 {len(file_paths)} 个文件共 {len(result)} 行输出到 {output_path} except Exception as e: return f错误{str(e)}合并的时候我加了一个_source_file列记录每行数据来自哪个文件。这个列在后续排查数据问题时特别有用——你发现某行数据不对一看来源文件就知道该去找谁。5.6 配置到客户端Server 写完了得让 AI 客户端知道它的存在。以常见的 MCP 客户端配置为例在配置文件里加一段{ mcpServers: { excel-processor: { command: python, args: [/absolute/path/to/server.py], env: {} } } }注意command和args里的路径一定要写绝对路径。我见过有人写相对路径结果客户端启动的时候工作目录不对找不到 server.py报了一堆错。配置完之后重启客户端如果一切正常你应该能在工具列表里看到我们定义的六个工具。这时候你就可以试着跟 AI 说帮我看看 /data/sales.xlsx 里有哪些 sheet它应该会自动调用 list_sheets 工具并返回结果。6. 实战演练三个真实场景的完整流程6.1 场景一多文件数据汇总假设你手上有 12 个月的销售数据每个月一个 Excel 文件格式一样现在要合并成一张总表。第一步先让 AI 确认文件结构。你跟 AI 说帮我看看 /data/sales_2024_01.xlsx 里有哪些 sheet。AI 调用 list_sheets返回Sheet1。第二步读取一个文件看看列结构。你说读一下这个文件的 Sheet1看前 5 行。AI 调用 read_sheetmax_rows 设为 5返回一个 Markdown 表格你能看到列名是日期、产品、销量、金额。第三步执行合并。你说把 /data/ 目录下所有 sales_2024_*.xlsx 合并到 /data/sales_2024_all.xlsx。AI 调用 merge_files传入文件列表和输出路径。几秒钟后返回已合并 12 个文件共 3650 行。整个过程你只说三句话剩下的都是 AI 在调工具。这就是 MCP 的价值——把写代码-调试-运行的循环变成了说需求-看结果的循环。6.2 场景二按条件筛选并生成新表客户给你一个 5000 行的订单表要你筛出金额大于 10000 的订单并且按客户名称排序。第一步读取数据。你说读一下 /data/orders.xlsx 的订单表。AI 返回前 100 行你能看到列名有订单号、客户名称、金额、日期。第二步筛选。你说筛出金额大于 10000 的行。这里有个问题——我们的工具集里没有专门的筛选工具。怎么办有两个方案。方案一是让 AI 用 read_sheet 读出全部数据然后在对话里做筛选再把结果用 write_range 写回去。这个方案适合数据量小的情况5000 行以内没问题。方案二是扩展一个 filter_rows 工具用 pandas 在服务端做筛选。这个方案适合数据量大的情况。我实际用下来5000 行以内用方案一就够了AI 的上下文完全能处理。超过 1 万行建议用方案二否则上下文会被撑爆。第三步写回结果。你说把筛选结果写到 /data/orders_filtered.xlsx 的 Sheet1。AI 调用 write_range把数据写进去。6.3 场景三批量修改单元格格式这个场景稍微复杂一点。客户要求把所有金额列的单元格加上千分位分隔符并且负数标红。MCP 工具本身不直接支持格式修改但我们可以通过 openpyxl 的样式功能来实现。你需要扩展一个format_range工具from openpyxl.styles import Font, NumberFormatDescriptor mcp.tool() def format_range(file_path: str, sheet_name: str, cell_range: str, number_format: str None, font_color: str None) - str: 对指定区域应用格式。 Args: file_path: 文件路径 sheet_name: sheet 名 cell_range: 区域如 A2:A100 number_format: 数字格式如 #,##0.00 font_color: 字体颜色如 FF0000 表示红色 try: wb openpyxl.load_workbook(file_path) ws wb[sheet_name] for row in ws[cell_range]: for cell in row: if number_format: cell.number_format number_format if font_color: cell.font Font(colorfont_color) wb.save(file_path) wb.close() return f已对 {sheet_name}!{cell_range} 应用格式 except Exception as e: return f错误{str(e)}这个工具加进去之后你跟 AI 说把 /data/orders.xlsx 的订单表里 C2:C5000 区域设置成千分位格式负数标红。AI 就会调用 format_range传入对应的参数。实操心得格式类的工具参数比较多AI 有时候会填错。我的做法是在工具描述里给出具体的参数示例比如number_format 常用值#,##0.00 表示千分位保留两位小数0% 表示百分比。有了示例AI 填错的概率会低很多。7. 踩坑记录与排查手册7.1 常见问题速查表问题现象可能原因解决方法客户端看不到工具配置文件路径错误检查 command 和 args 是否为绝对路径调用工具报 ModuleNotFoundError解释器选错确认客户端使用的 Python 是虚拟环境里的读取的单元格是公式字符串没加 data_onlyload_workbook 时加 data_onlyTrue写入后文件打不开文件被占用关闭 Excel 再写入或写入副本中文乱码编码问题确保文件路径和内容都用 UTF-8返回内容太长导致对话中断没限制行数给读取工具加 max_rows 参数合并后列对不上各文件列名不一致先用 read_sheet 检查每个文件的表头写入日期变成数字日期格式丢失写入时用 datetime 对象而非字符串7.2 三个我踩过的深坑第一个坑文件被 Excel 占用。有一次我让 AI 写入数据一直报 PermissionError。查了半天发现是我自己开着那个 Excel 文件没关。Windows 下 Excel 会锁定文件openpyxl 写不进去。后来我养成了一个习惯写入之前先检查文件是否被占用如果被占用就提示用户关闭。第二个坑大文件读取超时。有个客户给了个 50MB 的 Excel里面 20 万行。read_sheet 一读就卡死。后来我改成了流式读取用iter_rows而不是ws.rows并且强制限制 max_rows。如果用户确实需要读全部数据建议先用 pandas 在服务端做聚合只返回汇总结果。第三个坑sheet 名有特殊字符。有个客户的 sheet 名叫2024年1月(最终版)里面有括号。AI 调用工具的时候把括号转义了导致找不到 sheet。后来我在工具里加了一层处理对 sheet 名做精确匹配匹配不到再做模糊匹配返回最接近的几个候选让 AI 选择。7.3 性能优化的几个技巧技巧一read_only 模式。读取的时候用load_workbook(read_onlyTrue)内存占用能降低 60% 以上。这个模式下的 workbook 是只读的不能修改但读取速度很快。技巧二批量写入代替逐格写入。如果你要写 1000 个单元格用 write_range 一次写完比调用 1000 次 write_cell 快几十倍。因为每次 write_cell 都要打开文件、保存文件IO 开销很大。技巧三缓存 workbook 对象。如果你的 Server 会连续处理同一个文件的多个操作可以在内存里缓存 workbook 对象避免反复打开关闭。但要注意缓存失效的问题文件被外部修改后缓存要更新。技巧四用 pandas 做重活。涉及筛选、聚合、透视的操作交给 pandas 处理它底层是 C 实现的比 openpyxl 逐行遍历快得多。openpyxl 只用来做最终的读写。8. 从能用到好用几个值得加的扩展8.1 加一个预览工具read_sheet 默认返回 100 行但有时候用户只想看前 5 行确认一下结构。可以加一个 preview 工具固定返回前 5 行响应更快mcp.tool() def preview_sheet(file_path: str, sheet_name: str) - str: 快速预览 sheet 的前 5 行用于确认数据结构。 return read_sheet(file_path, sheet_name, max_rows5)8.2 加一个统计工具用户经常问这个表有多少行、金额列的总和是多少。与其让 AI 读全部数据自己算不如在服务端算好返回mcp.tool() def describe_sheet(file_path: str, sheet_name: str) - str: 返回 sheet 的基本统计信息行数、列数、各列的数据类型和缺失值情况。 df pd.read_excel(file_path, sheet_namesheet_name) info f行数{len(df)}\n列数{len(df.columns)}\n\n info 各列信息\n for col in df.columns: info f- {col}: 类型{df[col].dtype}, 非空{df[col].notna().sum()}, 缺失{df[col].isna().sum()}\n return info这个工具特别实用AI 拿到统计信息之后能更准确地决定下一步该怎么做。8.3 加一个模板填充工具很多报表场景是固定模板、动态数据。可以做一个 fill_template 工具读取模板文件把数据填到指定位置mcp.tool() def fill_template(template_path: str, output_path: str, sheet_name: str, data: dict) - str: 用数据填充 Excel 模板。 Args: template_path: 模板文件路径 output_path: 输出文件路径 sheet_name: 要填充的 sheet data: 字典key 是单元格坐标value 是要填的值 import shutil shutil.copy(template_path, output_path) wb openpyxl.load_workbook(output_path) ws wb[sheet_name] for cell, value in data.items(): ws[cell] value wb.save(output_path) wb.close() return f已填充 {len(data)} 个单元格到 {output_path}有了这个工具做月报、周报这类重复性工作就非常轻松了。你只需要维护一个模板每次把数据传进去就行。8.4 关于安全性的考虑MCP Server 运行在本地理论上只能访问本机文件。但如果你把 file_path 参数暴露给 AIAI 理论上可以读取任意文件。所以有几个安全措施值得加第一限制可访问的目录。在工具里加一个白名单检查只允许访问指定目录下的文件import os ALLOWED_DIR /data/excel def check_path(file_path: str) - bool: real_path os.path.realpath(file_path) return real_path.startswith(os.path.realpath(ALLOWED_DIR))第二写入操作前做备份。在 write_cell 和 write_range 里写入之前先把原文件复制一份到备份目录万一写错了还能恢复。第三敏感操作加确认。对于删除 sheet、覆盖整个文件这类操作可以在返回结果里加一句此操作不可逆请确认让 AI 转达给用户。提示如果你打算把这个 Server 分享给同事用一定要把路径白名单加上。我见过有人写了个 MCP Server 结果被 AI 误操作删了重要文件虽然最后从备份恢复了但吓出一身冷汗。9. 我对 MCP 工作流的一些个人看法写完这个 Excel MCP Server 之后我最大的感受是MCP 真正改变的不是能不能自动化而是自动化的门槛。以前你要自动化一个 Excel 处理流程得会 Python、会 pandas、会 openpyxl还得会调试。现在你只需要会描述需求剩下的交给 AI 和 MCP Server。这个门槛的降低意味着很多以前只有程序员能做的事现在普通职场人也能做了。但我也要说句实话MCP 不是银弹。它适合的是操作明确、步骤固定、数据量大的场景。如果你的需求是帮我分析一下这个数据有什么洞察那 MCP 帮不上太多忙因为分析本身需要判断力不是调几个工具就能解决的。MCP 解决的是手的问题不是脑的问题。另外工具的设计比工具的实现更重要。我见过很多人花大量时间写代码但工具描述写得一塌糊涂结果 AI 根本不知道怎么用。我的经验是写工具之前先想清楚AI 在什么场景下会调用它然后把这个场景写进描述里。描述写好了实现反而是最简单的一步。最后分享一个小技巧如果你不确定某个工具该怎么设计可以先手动模拟一遍 AI 的调用过程。假设你是 AI看到用户的需求你会怎么拆解需要哪些信息按什么顺序调用把这个过程写下来工具的设计自然就出来了。这个方法我用了很多次比直接写代码再改要高效得多。这个 Excel MCP Server 我后来又扩展了几个工具比如批量重命名 sheet、跨文件查找数据、生成数据透视表。每次扩展都是因为实际用的时候发现这个操作 AI 做不了。工具集是长出来的不是设计出来的。你先跑通最小可用版本然后在用的过程中慢慢加这样加出来的工具才是真正有用的。

相关推荐

从零开发MCP服务:重构Excel处理工作流实战
从零开发MCP服务:重构Excel处理工作流实战

Excel 处理这件事,说它是职场里最容易被低估的重复劳动一点都不夸张。我见过太多人每天花两三个小时在复制粘贴、格式调整、跨表匹配上,做完还容易出错。这两年 AI 工具爆发之后,大家都在想能不能让 AI 直接帮我操作 Excel,而不是… · 2026/11/3 12:16:35

Android Studio Panda2环境部署与性能优化指南
Android Studio Panda2环境部署与性能优化指南

1. Android Studio Panda2 环境部署全指南 作为谷歌官方推出的Android应用开发IDE,Android Studio Panda2(2024.2.2版本)在编译速度、智能代码补全和跨平台支持方面都有显著提升。最近在开发者社区看到不少同行在环境配置环节踩坑&#xff0c… · 2026/11/3 12:16:35

解决Dify平台模型供应商下载失败的六大根源与方案
解决Dify平台模型供应商下载失败的六大根源与方案

1. Dify模型供应商下载失败问题概述最近在本地部署Dify平台时,不少开发者遇到了模型供应商下载失败的问题,特别是安装openai-api-compatible组件时频繁报错。作为一个刚完成Dify企业级部署的技术顾问,我完整经历了这个"踩坑"过程。… · 2026/11/3 12:15:32

GitHub热榜拆解:agent框架、computer-use与自托管环境的5个开源项目
GitHub热榜拆解:agent框架、computer-use与自托管环境的5个开源项目

每隔几天我都会把GitHub热榜从头到尾翻一遍,九成的时候是在找“这周又冒出什么新框架”,剩下的一成是在验证一个判断:agent框架、computer-use、自托管环境这三个词,是不是真的已经成了开源领域的新基建。9月22号这期热榜恰好给了… · 2026/11/3 13:35:26

AI决策系统生产落地:架构分层、性能优化与版本安全
AI决策系统生产落地:架构分层、性能优化与版本安全

1. 从"概念验证"到"生产可用"之间,隔着一条什么河 做过AI决策系统的人大概都有这种体会:Demo跑通的那一刻特别爽,模型在测试集上指标漂亮,业务流程在PPT里画得清清楚楚,汇报的时候领导点头、同事鼓… · 2026/11/3 13:35:26

STM32G474 FDCAN原理与实战:从CAN2.0迁移的关键三步校准
STM32G474 FDCAN原理与实战:从CAN2.0迁移的关键三步校准

简介:本资源是面向嵌入式开发工程师与STM32进阶学习者的FDCAN通信专项技术指南,聚焦STM32G474等主流型号的CAN-FD外设实战应用。文档系统解析CAN-FD协议原理、相较传统CAN 2.0在数据长度(最高64字节)、比特率切换(数据… · 2026/11/3 13:35:26

STM32G474 FDCAN详解:CAN-FD协议原理与硬件配置实战
STM32G474 FDCAN详解:CAN-FD协议原理与硬件配置实战

简介:本资源是面向嵌入式开发工程师与STM32进阶学习者的FDCAN通信专项技术指南,聚焦STM32G474等主流型号的CAN-FD外设实战应用。文档系统解析CAN-FD协议原理、相较传统CAN 2.0在数据长度(最高64字节)、比特率切换(数据… · 2026/11/3 13:35:26

Paperclip:面向 React 与 OpenClaw 的本地 AI 运行时协调器
Paperclip:面向 React 与 OpenClaw 的本地 AI 运行时协调器

1. 项目概述:Paperclip 不是回形针,而是一个被严重低估的 AI 工具链枢纽“Paperclip”这个词在开发者社区里最近半年突然密集出现,但和 Office 文档里的那个金属小物件毫无关系——它不是 UI 组件库,不是前端工具链插件&#xff0… · 2026/11/3 13:35:26

分布式无人机监控系统:架构设计与工程实践
分布式无人机监控系统:架构设计与工程实践

1. 项目概述:无人机监控系统的分布式革新 去年参与某智慧园区项目时,客户要求对20公顷的开放区域实现动态监控。传统方案需要部署37个固定摄像头,不仅存在监控死角,布线成本更是高达80万元。当我们尝试用大疆M300搭载H20T云台相机… · 2026/11/3 13:34:22

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码