ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零开发第一个MCP服务:用AI Agent自动处理Excel

从零开发第一个MCP服务:用AI Agent自动处理Excel Excel 处理这件事几乎每个和数据打交道的岗位都绕不开。财务对账、运营拉报表、HR 整理花名册、研发导测试数据场景不同痛点却出奇一致重复、琐碎、格式千奇百怪而且每次都要手动来一遍。过去我们靠 Python 脚本硬扛写一个pandas脚本处理一类表格问题是脚本越攒越多改一个需求就得翻代码非技术同事根本接不住。这两年 AI Agent 火起来之后我一直在想一个问题能不能让 AI 直接接管Excel 处理这件事我只需要用自然语言描述需求它自己去读表、算数、写回、生成新文件答案就是 MCP。这篇内容我会完整复盘我开发第一个 MCP 服务的全过程——从理解 MCP 到底解决什么问题到用 Python 把 Excel 读写能力封装成 AI 可调用的工具再到实际跑通一个按关键词统计求和并生成新表的真实工作流。适合有 Python 基础、想入门 AI 工具开发、或者被 Excel 重复劳动折磨过的朋友零基础也能跟着走一遍。1. 先搞清楚 MCP 到底在解决什么麻烦1.1 从AI 只会聊天到AI 能动手干活的鸿沟大模型刚普及那会儿大家用得最多的是对话你问它答它给你一段代码、一段文案、一个思路。但真到干活的时候你会发现它给的建议再漂亮最后那一下动手还是得你自己来。比如你说帮我把这个 Excel 里所有含华东的行金额加起来它会告诉你用SUMIF或者写个pandas脚本但表还得你自己打开、公式还得你自己填、结果还得你自己复制。这个鸿沟的本质是模型有能力理解意图但没有通道去操作你本地的文件和软件。它像一个知识渊博但被关在玻璃房里的顾问看得见、说得出就是伸不出手。MCPModel Context Protocol模型上下文协议要解决的就是这个伸手的问题。你可以把它理解成一套标准化的插座协议AI 应用客户端是插头你的能力服务服务端是插座只要双方都遵守这套协议插上就能用。以前每接一个工具都要写一套私有对接代码现在有了统一协议工具可以像 USB 设备一样即插即用。这里有个概念容易混MCP 是软件协议不是硬件协议。硬件领域类似的概念叫总线标准比如 USB、PCIe软件领域 MCP 扮演的就是能力总线的角色。理解这一点很关键因为它决定了你开发 MCP 时的心态——你不是在写一个孤立的脚本而是在造一个符合标准的、任何支持 MCP 的 AI 客户端都能调用的能力模块。1.2 为什么 Excel 是练手 MCP 的最佳场景我选 Excel 作为第一个 MCP 项目不是随便挑的理由很实在第一需求密度高。Excel 处理的痛点几乎人人都有做出来的工具有真实使用价值不是玩具。你做完能立刻用在自己的工作里正反馈来得快。第二边界清晰。Excel 操作无非读、写、算、格式转换这几类功能边界好定义不像做通用 Agent 那样容易失控。对新手来说能快速看到一个完整闭环比做一半卡住强太多。第三验证成本低。你造好工具随便拿个表格就能测不需要复杂环境。数据对不对打开文件一看便知调试反馈非常直接。第四技术栈友好。Python 生态里openpyxl、pandas这些库成熟稳定文档齐全你不需要从零造轮子专注在如何把能力暴露给 AI这件事上。提示新手做第一个 MCP最忌讳一上来就搞全能型服务。功能越多工具描述越难写清楚模型越容易调错。先把一个垂直场景做透比做十个半成品有价值得多。1.3 MCP 服务端、客户端、工具三者的关系在动手之前必须把这三个角色的关系理顺否则写代码时容易懵。MCP 客户端就是那个 AI 应用它负责理解用户意图、决定调用哪个工具、把参数传过去。你不需要开发客户端用现成的支持 MCP 的 AI 工具即可。MCP 服务端这是你要开发的东西。它对外暴露一组工具Tools每个工具就是一个具体能力比如读取 Excel 某列、按条件求和、写入新表。工具Tool服务端里的最小功能单元。每个工具要有名字、描述、参数定义。描述写得好不好直接决定模型能不能正确调用。打个比方客户端是餐厅服务员服务端是厨房工具是菜单上的菜。服务员根据客人用户的需求点菜厨房按单做菜。菜单写得清不清楚决定了服务员会不会点错。这个类比后面讲工具描述时还会用到先记住。2. 动手前的环境准备与依赖选型2.1 Python 环境与虚拟环境的必要性我假设你已经装了 Python如果还没装去官网下 3.10 以上的版本安装时记得勾选Add Python to PATH这一步漏了后面命令行会各种找不到命令。装完在终端敲python --version能出版本号就说明成了。接下来是虚拟环境。很多人图省事直接全局装包我强烈建议不要。原因很简单MCP 相关的库更新快不同项目依赖版本可能冲突全局装迟早把环境搞乱。用venv建一个独立环境干净利落python -m venv mcp-excel-env # Windows mcp-excel-env\Scripts\activate # macOS / Linux source mcp-excel-env/bin/activate激活后命令行前面会出现(mcp-excel-env)字样说明你在这个环境里操作装什么包都不会污染全局。这个习惯养成了以后做任何 Python 项目都受益。2.2 核心依赖MCP SDK 与 Excel 处理库这个项目需要两类依赖一类是 MCP 协议相关的一类是 Excel 处理相关的。MCP 官方提供了 Python SDK装它就行pip install mcpExcel 处理我选openpyxl而不是pandas这里要解释一下为什么。pandas强在数据分析和批量计算但它读写 Excel 时会丢失部分格式信息而且对单元格级的精细操作不友好。openpyxl是专门操作.xlsx的库能精确保留格式、支持单元格读写、公式、样式更适合做工具型的 Excel 操作。当然如果你要做复杂统计pandas更顺手实际项目里两者可以配合用。pip install openpyxl如果你打算做更复杂的统计聚合可以再加一个pip install pandas依赖装完可以用pip list确认一下看到mcp和openpyxl都在列表里就对了。2.3 目录结构怎么规划才不返工新手最容易犯的错是文件乱放写到后面自己都找不到。我建议一开始就按这个结构来mcp-excel/ ├── server.py # MCP 服务端主文件 ├── excel_tools.py # Excel 操作逻辑封装 ├── requirements.txt # 依赖清单 └── test_data/ # 测试用的 Excel 文件把协议层和业务逻辑层分开好处是以后你想换 Excel 处理库只改excel_tools.pyserver.py不用动想加新工具也只在对应层加。这种分层思维在 MCP 开发里特别重要因为工具会越加越多不分层后期维护是灾难。requirements.txt里写上mcp openpyxl pandas这样别人拿到你的项目一条pip install -r requirements.txt就能复现环境。3. 把 Excel 能力封装成 AI 能听懂的工具3.1 工具设计的核心原则一个工具只干一件事这是整个项目里我最想强调的一点。很多人设计工具时喜欢大而全比如搞一个process_excel工具参数一大堆既能读又能写还能算。结果模型调用时经常传错参数或者理解不了这个工具到底该在什么场景用。正确的做法是单一职责一个工具只做一件事名字直白参数精简。我这次设计了四个工具工具名功能关键参数read_excel读取指定工作表数据文件路径、工作表名sum_by_keyword按关键词筛选并求和文件路径、列名、关键词、求和列write_excel将数据写入新表数据、输出路径list_sheets列出所有工作表名文件路径你看每个工具职责清晰模型一看名字和描述就知道什么时候该用哪个。list_sheets这种看似简单的工具其实很有用——模型在不确定表结构时可以先调它探路再决定后续操作这就是给 AI 留探索空间。3.2 工具描述怎么写模型才不会调错工具描述description是模型判断该不该用这个工具的唯一依据写得好坏直接决定成败。我踩过的坑是描述写得太技术化模型理解不了业务含义。举个例子sum_by_keyword最初的描述是对指定列进行条件求和结果模型经常在不需要求和的场景也调它。后来我改成统计 Excel 中某一列包含指定关键词的所有行并对另一列的数值求和。例如统计地区列含华东的所有行的金额列总和。加上具体例子后调用准确率明显提升。写描述的三条经验说清什么时候用而不只是是什么。加上典型使用场景模型才知道触发时机。参数说明要具体。不要写列名要写要筛选的列名如地区、部门。给出输入输出示例。模型对示例的敏感度远高于抽象描述。注意工具描述不是写给人看的文档是写给模型看的使用说明书。判断标准只有一个——模型能不能仅凭这段描述就正确调用。3.3 用 Python 实现 Excel 读写逻辑先写excel_tools.py把纯业务逻辑封装好这部分和 MCP 无关是标准的 Python 代码import openpyxl from openpyxl import Workbook def read_excel(file_path, sheet_nameNone): 读取 Excel 数据返回二维列表 wb openpyxl.load_workbook(file_path, data_onlyTrue) ws wb[sheet_name] if sheet_name else wb.active data [] for row in ws.iter_rows(values_onlyTrue): data.append(list(row)) return data def list_sheets(file_path): 列出所有工作表名 wb openpyxl.load_workbook(file_path, read_onlyTrue) return wb.sheetnames def sum_by_keyword(file_path, filter_col, keyword, sum_col, sheet_nameNone): 按关键词筛选后对指定列求和 data read_excel(file_path, sheet_name) if not data: return 0 header data[0] try: filter_idx header.index(filter_col) sum_idx header.index(sum_col) except ValueError as e: raise ValueError(f列名不存在: {e}) total 0 for row in data[1:]: cell row[filter_idx] if cell is not None and keyword in str(cell): value row[sum_idx] if isinstance(value, (int, float)): total value return total def write_excel(data, output_path, sheet_nameSheet1): 将二维数据写入新 Excel wb Workbook() ws wb.active ws.title sheet_name for row in data: ws.append(row) wb.save(output_path) return output_path这段代码有几个细节值得说。data_onlyTrue很关键它让openpyxl读取公式的计算结果而不是公式本身否则你求和时拿到的是字符串公式会出错。read_onlyTrue在只读场景下能大幅提升大文件读取速度。求和时判断isinstance(value, (int, float))是为了跳过空单元格和文本避免类型错误。3.4 用 MCP SDK 把函数暴露成工具接下来是server.py这是 MCP 的核心。用官方 SDK 的FastMCP写法最简洁from mcp.server.fastmcp import FastMCP import excel_tools mcp FastMCP(excel-processor) mcp.tool() def read_excel(file_path: str, sheet_name: str None) - list: 读取 Excel 文件内容。当需要查看表格数据时使用。 参数 file_path 为文件绝对路径sheet_name 可选不传则读第一个工作表。 return excel_tools.read_excel(file_path, sheet_name) mcp.tool() def list_sheets(file_path: str) - list: 列出 Excel 文件中所有工作表名称。当不确定表结构时先调用此工具。 return excel_tools.list_sheets(file_path) mcp.tool() def sum_by_keyword(file_path: str, filter_col: str, keyword: str, sum_col: str, sheet_name: str None) - float: 统计某列包含关键词的所有行并对另一列数值求和。 例如统计地区列含华东的行的金额总和。 return excel_tools.sum_by_keyword(file_path, filter_col, keyword, sum_col, sheet_name) mcp.tool() def write_excel(data: list, output_path: str, sheet_name: str Sheet1) - str: 将二维列表数据写入新的 Excel 文件返回输出路径。 return excel_tools.write_excel(data, output_path, sheet_name) if __name__ __main__: mcp.run()mcp.tool()装饰器是关键它自动把普通 Python 函数注册成 MCP 工具函数的类型注解和 docstring 会被 SDK 解析成工具的参数定义和描述。所以类型注解一定要写全file_path: str这种不能省否则模型不知道参数类型。docstring 就是前面说的工具描述重要性不再重复。4. 跑通第一个真实工作流关键词统计求和4.1 准备一份贴近真实的测试数据工具写完了得用真实数据验证。我造了一份销售数据表sales.xlsx结构如下地区产品金额日期华东-上海A12002024-01-05华南-广州B8002024-01-06华东-杭州A15002024-01-07华北-北京C9002024-01-08华东-南京B11002024-01-09这份数据故意设计成地区列带前缀模拟真实业务里常见的复合字段。这样测试sum_by_keyword时用华东作为关键词就能匹配到三行验证包含逻辑是否生效。4.2 在 AI 客户端里配置并连接 MCP 服务MCP 服务端写好后需要在支持 MCP 的 AI 客户端里配置连接。不同客户端配置方式略有差异但核心都是告诉客户端怎么启动你的服务端。以常见的配置文件为例通常是这样的结构{ mcpServers: { excel-processor: { command: python, args: [/绝对路径/mcp-excel/server.py] } } }这里有个大坑路径一定要用绝对路径。我一开始用了相对路径客户端启动服务端时工作目录不对直接报文件找不到。改成绝对路径后一次通过。另外command要确保是当前虚拟环境里的 python如果你在虚拟环境里装的依赖但配置里用的是系统 python会报模块找不到。配置保存后重启客户端如果连接成功客户端会列出你注册的四个工具。这时候你就可以用自然语言下指令了。4.3 用自然语言触发工具调用的完整过程我在客户端里输入帮我统计 sales.xlsx 里地区包含华东的所有订单金额总和。接下来发生的事情很有意思值得拆开看意图理解模型识别出用户要按条件统计求和匹配到sum_by_keyword工具。参数提取从自然语言里抽出file_path、filter_col地区、keyword华东、sum_col金额。工具调用客户端把参数传给服务端服务端执行 Python 函数。结果返回服务端返回3800120015001100模型用自然语言回复用户。整个过程用户只说了一句话背后完成了参数映射、函数执行、结果组织。这就是 MCP 的价值——把人操作软件变成人描述意图AI 操作软件。如果模型第一次没调对比如把filter_col传成了华东别急着改代码先看工具描述是不是不够清楚。多数调用错误都是描述问题不是模型问题。4.4 结果验证与常见调用失败排查结果出来后一定要人工核对。我拿计算器加了一遍3800 没错。但真实场景里验证不能只看一个数要抽查几行原始数据确认筛选逻辑符合预期。调用失败常见就三类我整理成表方便对照现象可能原因排查方向模型不调用工具工具描述与用户意图不匹配优化 description加使用场景调用报参数错误类型注解缺失或参数名歧义检查类型注解参数名写具体执行报文件错误路径非绝对路径或文件不存在确认绝对路径检查文件权限求和结果为 0列名不匹配或数值是文本格式打印 header 核对列名检查单元格类型提示调试 MCP 时养成先单独跑excel_tools.py里函数的习惯。业务逻辑单独验证通过再接入 MCP能把问题范围缩小一半。5. 让工具更稳的几个实战改进5.1 处理大文件时的性能取舍第一版跑小表没问题我拿一个 5 万行的表测试读取明显变慢。原因是openpyxl默认会把整个工作簿加载进内存。改进方法是读的时候用read_onlyTrue写的时候用write_onlyTrue这两个模式是流式的内存占用大幅下降。但要注意read_only模式下不能随机访问单元格只能顺序遍历所以如果你的逻辑需要反复跳转读取就不适合。这是个典型的取舍顺序处理用流式随机访问用普通模式。做工具时要根据实际场景选别盲目追求高性能。另外如果只是做统计求和其实用pandas的read_excel加条件筛选会更快更简洁。我的建议是简单读写用openpyxl复杂统计用pandas两者按场景切换不必强求统一。5.2 错误处理别让一个异常搞崩整个服务MCP 服务端是个常驻进程如果某个工具抛异常没被捕获可能导致整个服务挂掉后续所有请求都失败。所以每个工具函数都要做好异常处理。我的做法是在excel_tools.py里统一捕获返回结构化的错误信息而不是直接抛def safe_sum_by_keyword(file_path, filter_col, keyword, sum_col, sheet_nameNone): try: return {success: True, result: sum_by_keyword(...)} except FileNotFoundError: return {success: False, error: 文件不存在请检查路径} except ValueError as e: return {success: False, error: str(e)}返回结构化结果的好处是模型能读懂错误信息并据此调整策略——比如文件不存在时它可以提示用户重新提供路径而不是直接报错卡死。这比抛异常优雅得多。5.3 工具描述迭代从能调到调得准工具上线不是终点描述优化是个持续过程。我记录了几次迭代第一版sum_by_keyword描述只有一句条件求和模型经常在纯读取场景误调。第二版加了当用户需要按条件统计数值总和时使用误调减少。第三版加了具体例子如统计地区含华东的金额总和准确率基本稳定。这个过程说明工具描述要像产品文案一样反复打磨。我的经验是每次发现模型调错先别改代码改描述八成能解决。如果改了描述还不行再考虑是不是工具拆分得不够细。5.4 安全边界文件操作必须限制范围Excel 工具涉及文件读写安全边界必须划清楚。几个原则只允许操作指定目录下的文件。不要让工具能读写任意路径否则模型一旦理解偏差可能误删或覆盖重要文件。可以在工具里加路径校验判断目标路径是否在允许的根目录下。写操作默认不覆盖。write_excel如果目标文件已存在应该报错或自动改名而不是直接覆盖。数据无价这个保护必须有。敏感数据脱敏。如果表格里有身份证、手机号等字段读取工具要考虑是否做脱敏处理避免数据在对话中被完整暴露。这些不是过度设计而是工具真正投入使用时必须考虑的。我见过太多 demo 跑得飞起、一上生产就出事的案例安全边界是区分玩具和工具的分水岭。6. 从这一个 MCP 能延展出的更多可能6.1 把多个 Excel 工具串成工作流单个工具解决单点问题真正的效率提升来自工作流。比如每月报表自动化这个场景可以串成list_sheets探明结构 →read_excel读取原始数据 →sum_by_keyword做多维度统计 →write_excel生成汇总表。用户只需要说一句帮我生成本月华东区销售汇总背后自动跑完整个链路。这种串联不需要你写额外的编排代码模型会根据工具描述自动规划调用顺序。你要做的是把每个工具的描述写清楚让模型知道什么时候该用哪个。这也是 MCP 相比传统脚本的优雅之处——编排逻辑交给模型你专注把每个能力做好。6.2 扩展到其他办公场景的思路Excel 只是起点这套方法论可以平移到很多场景Word 文档处理用python-docx封装读取、替换、生成工具做合同批量填充。PDF 提取用pymupdf封装文本提取、表格识别工具做发票信息抽取。邮件自动化封装邮件读取、分类、回复草稿工具做客服工单处理。核心思路完全一致找到重复劳动场景 → 用 Python 库实现核心逻辑 → 用 MCP 暴露成工具 → 用自然语言驱动。你掌握了一个就掌握了一类。6.3 新手继续深入的学习路径如果你跟着做完了这个项目想继续深入我建议这个顺序先把工具描述优化练熟。这是 MCP 开发最核心也最容易被忽视的技能值得单独花时间。学 MCP 的资源Resources和提示Prompts。工具只是 MCP 三大能力之一资源和提示能让你做更复杂的交互。研究多工具协作。试着做三五个工具让模型自己编排体会能力组合的威力。关注错误处理和边界。从 demo 到可用差距全在细节里。最后分享一个我自己的体会做 MCP 最大的收获不是学会了某个库而是思维方式变了。以前遇到重复劳动第一反应是写个脚本现在第一反应是这个能力能不能封装成工具让 AI 来调。这个转变一旦发生你会发现身边到处都是可以自动化的场景而 MCP 就是把这些场景变成现实的桥梁。第一个 MCP 不用做得完美跑通闭环、建立信心比什么都重要。
返回列表