上个月做月度经营分析,我对着那份38个工作表的销售台账发呆了大半个小时。要按区域拆、按品类聚合、把异常数据抽出来写摘要,最后还得顺手修正几个格式错乱的单元格。我的第一反应当然是"把这活丢给AI就完了"——结果打开AI对话框才发现,它压根看不到我电脑上的文件,我也没法把一个20MB的xlsx完整贴进对话窗口。这个场景我相信不止我一个人遇到过,也正是我动手开发自己第一个MCP的直接契机。
AI大模型处理文本已经很能打了,但它在默认情况下是"没有手"的:看不到本地文件,执行不了操作,最多只能帮你生成一段能跑的Python代码,然后由你自己去跑、去修、去调。一次两次还行,次数多了你会发现,真正耗时间的根本不是写代码,而是"把需求翻译给AI、再把AI的输出搬回我的文件系统"这个来回搬运的过程。MCP(Model Context Protocol,模型上下文协议)就是来解决这个断层面的:它让AI可以通过一套统一协议,直接调用你预先封装好的工具——读取Excel单元格、修改工作表、把表格转成Markdown——而AI完全不需要关心这些工具的底层实现。
这篇文章我会完整复盘我做的这个"Excel工作流MCP服务端":从MCP协议的核心概念讲起,到Python环境下的代码实现,再到接入AI客户端做实测对话,最后是一堆只有真正跑起来才会撞到的坑。适合那些跟我一样,想把AI真正接进自己日常工作流、而不只是把它当"高级搜索框"用的开发者。
1. 为什么AI处理Excel这么费劲:先看清问题在哪
在动手写MCP之前,我先把"AI处理Excel"这件事的底层矛盾拆了一遍。如果你也试过让AI帮你处理表格,你应该能共鸣。
1.1 AI的天生缺陷:只有"嘴"和"脑",没有"手"
对话式AI的推理链路是"文本进、文本出"。你给它一段数据,它在参数空间里做推理,然后吐出一段文本或代码。它没有文件句柄,没有系统调用权,更没有操作系统的进程权限。所以在默认状态下,AI面对本地Excel只有两种选择:要么你手动把数据内容复制成文本喂进去,要么你让它生成一段Python脚本,然后自己复制到终端里执行。
这个模式在数据量小时很爽。比如你有一个5行的表问"哪个产品销售额最高",复制粘贴几秒钟搞定。但一旦涉及真实生产环境里的表——几十个sheet、几万行数据、有合并单元格、有公式缓存、有各种脏数据——复制粘贴这条路就直接堵死了,因为对话窗口根本塞不下,而且粘贴过去还会丢失Excel的格式和结构信息。
1.2 让AI"写代码"的隐性成本:沟通两次、debug两次
有人说,那让AI写脚本不就行了?我用过一段时间,最深切的感受是:这条路不是不能走,而是每次都要做"双重翻译"。第一重,你得把Excel的结构和你的需求翻译成AI能理解的文本描述;第二重,AI生成的脚本跑挂了,你得再把报错信息翻译回去让它改。一来一回,三四轮对话是常态,而且每次都像在打一场新的仗。
更麻烦的是,AI生成的脚本往往不掌握你机器的上下文。它不知道你的文件放在哪个目录、不知道你有哪个版本的Python环境、不知道你的表头在第几行、不知道某个sheet名里有没有空格。于是它在真空中写代码,你在现实中给它填坑。一次两次是新鲜,十次二十次就是纯粹的体力劳动了。
1.3 旧方案为什么都差点意思:函数调用、RAG、代码沙箱
在MCP普及之前,业界尝试过几条路。第一条是"函数调用"(Function Calling),让模型输出一个结构化的调用意图,由应用层去执行。这思路本身没问题,但它是"各家各的方言"——OpenAI有OpenAI的写法,Anthropic有Anthropic的写法,换一个模型就要重新适配一遍,没有统一标准。
第二条是RAG,把Excel数据向量化后交给AI做"基于知识库的问答"。听起来很酷,但Excel不是纯文本,它是有结构、有公式、有跨sheet引用关系的。你把单元格切片丢进向量库里,等于强行把一张麻将牌掰成碎片再拼回去,检索出来经常是形似而神不似。
第三条是代码沙箱,让AI在隔离环境里跑代码。这个方案对数据科学家场景很好用,但它天然和"操作我的本地文件"这件事冲突——沙箱里的文件得先传进去,算完了再传出来,壁垒依然存在。
这所有方案的本质问题只有一个:AI和应用之间的"接口"没有标准化。MCP就是冲着这个来的。
2. MCP到底是什么:一个用"快递柜"就能讲明白的协议
说实在的,MCP刚出来那阵子,各种技术文章把它包装得非常玄乎:什么"AI界的USB-C""大模型的操作系统"……听着很高大上,但回到工程实现层面,它其实没那么复杂。
2.1 协议三件套:Client、Server、Transport
MCP的核心架构就三部分。Client是AI应用的宿主,比如Claude Desktop、Cursor这类工具;Server是你自己实现的一个进程,负责暴露"能力";Transport是Client和Server之间的通信管道,MCP规定了两种:stdio和SSE。
- stdio:Client拉起Server子进程,通过标准输入输出传JSON-RPC消息。这种模式最简单,适合本地工具,启动快、延迟低。
- SSE(Server-Sent Events):Server作为一个HTTP服务跑在某个端口上,Client通过HTTP URL连接。适合远程服务器、多人共用、或者客户端和Server不在同一台机器上的场景。
你可以把MCP想象成快递柜。Client是取件人,Server是快递驿站,而工具(Tools)就是柜子里的包裹。取件人不需要知道包裹是怎么从发货地运来的,不需要知道驿站的仓库长什么样,只需要通过一个标准化的取件码(协议消息)把包裹拿出来。快递柜的规格是统一的,取件码的规则也是统一的,所以无论开哪个驿站的柜子,用户的操作习惯完全一样。
2.2 三大能力:Tools、Resources、Prompts
MCP协议定义了Server可以给Client提供三类能力,我刚开始学的时候经常把它们搞混,这里按我自己的理解捋一遍:
- Tools(工具):这是最常用、也最好理解的一类。工具就是一个可以被AI调用的函数。AI在对话中判断"我需要读取某个单元格",于是调用你定义的read_cell工具,并传入参数。工具的执行权在Server侧,执行结果以文本或结构化数据返回给AI。
- Resources(资源):可以理解为"只读的数据源"。Resources把某些数据(比如一个文件、一段配置、一个数据库查询结果)暴露给Client,AI可以在上下文中引用它。和Tools的区别在于,Resources不承载"执行逻辑",更像是一个"可访问的数据文件"。
- Prompts(提示词模板):定义了一些固定的对话启动模板。比如你可以定义一个"Excel周报分析"的Prompt,让用户一键触发,AI就会按预定套路读取指定文件并生成分析。
在我的Excel场景里,核心工作全在Tools上。Resources偶尔用来暴露"当前有哪些可处理的文件"这样的清单,Prompts目前用处不大,但未来做标准化报告流程时会有价值。
2.3 为什么叫"Model Context"而不是"Function Call"
这个名字其实很讲究。早期函数调用强调的是"模型输出一个调用请求",重点在"调";而MCP强调的"Context"是一种双向的、持续性的上下文扩展。Server不只是被动地被调用,它还可以主动向Client描述自己的能力边界、数据状态、可用资源,AI在决策时会把"我有哪些工具可用、这些工具能干什么"当作决策上下文的一部分。
这一点在实操中感受非常明显。接上MCP之后,AI不再是"你求它帮你写代码",而是"它主动评估现场后决定用什么工具、按什么顺序操作"。这个体验转折是一旦跑通就回不去的。
3. 环境准备与第一个Hello World服务端
理论说再多也不如跑一个demo。我用的技术栈是这样的:Python 3.10 + 官方MCP Python SDK + openpyxl/pandas处理Excel。选Python而不是TypeScript,纯粹是因为数据处理生态太成熟了,Excel处理库随便挑。
3.1 环境搭建与项目结构
首先装依赖,命令就两行:
pip install "mcp[cli]" pip install openpyxl pandas注意,官方SDK里已经内置了FastMCP这个高阶封装,用起来非常舒服,不需要额外装第三方包。装完后建议顺手安装一下MCP Inspector调试工具:
npx @modelcontextprotocol/inspector这个工具是图形界面的调试台,能直接观察Server暴露了哪些工具、手动调用工具看返回结果,调试阶段神器。
项目结构我不会搞太复杂,单文件起步:
excel_mcp/ ├── excel_server.py # MCP服务端主文件 ├── data/ # 测试用Excel文件存放目录 └── requirements.txt3.2 写一个"加法器"服务端
我们先写一个最小可用的MCP Server,不碰Excel,只暴露一个加法工具。目的是跑通"Client发现工具 -> 调用工具 -> 拿到结果"这条链路。
from mcp.server.fastmcp import FastMCP mcp = FastMCP("excel-assistant") @mcp.tool() def add(a: float, b: float) -> float: """计算两个数字的和。""" return a + b if __name__ == "__main__": mcp.run()就这么点代码。FastMCP封装了所有协议细节,一个@mcp.tool()装饰器就把普通函数变成了MCP工具。运行方式也很简单:
python excel_server.py此时进程会通过stdio等待Client的连接。你可能会问:就这样?协议呢?握手呢?JSON-RPC呢?——都被SDK内部处理了。MCP的工程化做得相当好,对应用开发者而言,学习成本被压到了极低。
3.3 用Inspector做第一轮验证
把服务端跑起来后,打开MCP Inspector,连接方式选stdio,再填上启动命令:
python C:/Users/xxx/excel_mcp/excel_server.py连接成功后,Inspector会自动拉取Server的能力清单。你会在工具列表里看到add,点击展开就能看到它的描述和参数Schema,还能直接传参模拟调用。如果看到返回结果"3.0",说明整条链路已经通了。
这一步特别重要,我建议每个新工具写完后都先在Inspector里测一遍,而不是直接上真实AI客户端。因为Inspector能给你非常明确的错误信息,而AI客户端会把错误自己"消化"掉—— 我曾经遇到过AI明明调用工具失败,却在对话里一本正经地编了一个结果的情况。所以"先Inspector后AI"是我的固定习惯,算是用血泪换来的经验。
4. 实战:把Excel处理能力封装成MCP工具集
跑通Hello World之后,我开始设计Excel工具集。这一步是整个项目的灵魂,因为AI能做什么、做到什么程度,完全取决于你给它什么工具。工具设计得差,AI再聪明也白搭。
4.1 工具集的设计原则:文件路径是核心入参
在设计之前,我先想清楚了一个问题:MCP工具是"无状态"的。AI调用工具时,每次都要传入完整参数,Server不会替AI"记住"上次操作的是哪个文件。所以最直观的设计是把file_path作为每个工具的必填参数。
有的教程建议用全局变量维护"当前打开的文件",让AI先open再read。我试过,效果不好——AI的对话轮次一多,或者用户中途切换话题,那个"当前文件"的上下文很容易错乱。宁可每次多传一个路径参数,换来的是每一轮调用都干净利落、可回溯。这算是我的一个设计心法。
另外,我要求所有工具的参数都写上详细的文档字符串(docstring),包括每个参数的含义、单位、格式、示例值。这段文档最终会成为AI决定如何调用工具的说明书——写得不清楚,AI就会瞎猜参数,猜错了报错给你看。
4.2 读写单元格:Hello Excel
先把最基础的读写做出来。读取的难点在于,Excel里可能有公式。用openpyxl加载时有个经典坑:data_only=True会读取"公式计算后的缓存值",但如果这个文件从没被Excel软件打开过、缓存还没生成,读出来就是None。所以我通常提供两种读取模式,并在工具描述里明确说明。
from mcp.server.fastmcp import FastMCP from openpyxl import load_workbook mcp = FastMCP("excel-assistant") @mcp.tool() def read_cell(file_path: str, sheet_name: str, cell: str) -> str: """ 读取Excel指定工作表中某个单元格的值。 参数说明: - file_path: xlsx文件的绝对路径,例如 C:/data/销售表.xlsx - sheet_name: 工作表名称,例如 "Sheet1",必须是已存在的工作表 - cell: 单元格地址,例如 "B3" 返回单元格的文本表示;若为空则返回"空"。 """ wb = load_workbook(file_path, data_only=True) ws = wb[sheet_name] value = ws[cell].value return str(value) if value is not None else "空"写入工具类似,只是多了一步保存:
@mcp.tool() def write_cell(file_path: str, sheet_name: str, cell: str, value: str) -> str: """ 将value写入Excel指定工作表的指定单元格并保存。 参数说明: - value: 要写入的字符串或数字,数字直接传数字,文本加引号 返回"写入成功"或错误信息。 """ wb = load_workbook(file_path) ws = wb[sheet_name] ws[cell] = value wb.save(file_path) return "写入成功"这两个工具看似简单,但它们是整个工作流的地基。AI可以靠read_cell一格格"看"表,靠write_cell一格格"改"表,就像教它用手去触碰物理世界一样。
4.3 让AI"看"懂整张表:区域读取与Markdown转换
只读单个单元格效率太低了,AI要看一张表,一次性把数据全部拿到才合理。我封装了一个"读取区域并转成Markdown表格"的工具。为什么是Markdown?因为AI对Markdown表格的解析能力极强,它能在上下文里快速理解"第几行第几列是什么含义",这比塞给它一段Python列表要直观得多。
@mcp.tool() def read_range_as_markdown(file_path: str, sheet_name: str, start_cell: str, end_cell: str) -> str: """ 读取Excel指定区域的数据,并转换为Markdown表格返回。 参数说明: - start_cell: 起始单元格,如 "A1" - end_cell: 结束单元格,如 "E20",将读取A1到E20构成的矩形区域 返回Markdown格式表格文本,适合让AI直接分析。 """ wb = load_workbook(file_path, data_only=True) ws = wb[sheet_name] rows = list(ws[start_cell:end_cell]) lines = [] for row in rows: cells = [] for cell in row: v = cell.value if v is None: cells.append("") else: cells.append(str(v).replace("\n", " ").replace("|", "\\|")) lines.append("| " + " | ".join(cells) + " |") header = lines[0] sep = "|" + "|".join([" --- "] * len(rows[0])) + "|" return "\n".join([header, sep] + lines[1:])这个小工具上线后,AI处理Excel的体验有了质的飞跃。你只需要说"把C:/报表/6月销售明细.xlsx里'销售明细'表A1:G50区域给我看看",它就会调用这个工具,然后对着Markdown表格进行分析、筛选、汇总,全然一副"熟读报表"的样子。
4.4 处理整表:让AI掌握"全局视角"
区域读取虽然好用,但AI有时需要先扫一遍"这个文件有哪些sheet、每个sheet多大、表头长什么样",才能决定后续怎么处理。于是我加了三个"元信息"工具:
@mcp.tool() def list_sheets(file_path: str) -> str: """列出Excel文件中所有工作表的名称和每个表的行列数。""" wb = load_workbook(file_path, read_only=True) info = [f"{name}: {ws.max_row}行 x {ws.max_column}列" for name, ws in wb.items()] return "\n".join(info)@mcp.tool() def peek_sheet(file_path: str, sheet_name: str, rows: int = 5) -> str: """ 快速预览指定工作表前rows行数据(转为Markdown)。 用于让AI了解表结构,避免一次性读取超大表格。 """ wb = load_workbook(file_path, data_only=True) ws = wb[sheet_name] max_col = min(ws.max_column, 12) rows_data = list(ws.iter_rows(min_row=1, max_row=rows, max_col=max_col, values_only=True)) # 复用上面的Markdown转换逻辑 ...这两个工具相当实用。AI拿到一个陌生文件后,不会直接莽撞地读全表,而是先list_sheets看结构,再peek_sheet看表头,然后才决定真正的读取策略。这套"先侦察后行动"的模式,完全可以在工具描述的引导下像真人操作一样自然。
4.5 进一步:写入整表与自动保存
写操作同样要支持"当前这个表我改了什么、有没有保存"。我设计了一个原则:所有写工具内部都会调用wb.save(),确保每次工具返回时文件都已落盘。这样做的好处是AI的操作不会凭空丢失,坏处是频繁保存效率低。平衡方案是在工具描述里鼓励AI"尽量批量修改单元格后再调用保存工具"。
我还加了一个批量写入工具,接收一个二维数组和起始单元格,一次性写入一个矩形区域:
@mcp.tool() def write_range(file_path: str, sheet_name: str, start_cell: str, data: list) -> str: """ 将二维数组data写入Excel,从start_cell起始,逐行逐列填充。 参数说明: - data: 嵌套列表,如 [["产品", "销量"], ["A", 100]] 覆盖原区域内容,并保存文件。 """ wb = load_workbook(file_path) ws = wb[sheet_name] for row_idx, row_data in enumerate(data): for col_idx, value in enumerate(row_data): cell = ws.cell(row=ws[start_cell].row + row_idx, column=ws[start_cell].column + col_idx) cell.value = value wb.save(file_path) return f"已写入{len(data)}行"到这一步,这个MCP Server已经具备了"读、看、写、改"四类能力,覆盖了Excel日常处理的80%场景。剩下来的就是把它接到真正的AI客户端上跑起来。
5. 接入AI客户端:让模型真正"动手"
工具开发完,剩下的是连接。我用的是Claude Desktop做宿主,这是目前对接本地MCP Server最顺滑的方案之一,下面以它为例讲配置过程。其他支持MCP的客户端原理是相通的。
5.1 Claude Desktop的MCP配置
找到Claude Desktop的配置文件:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
在里面加一个MCP服务器条目:
{ "mcpServers": { "excel-assistant": { "command": "python", "args": ["C:/projects/excel_mcp/excel_server.py"] } } }注意Windows下路径分隔符要用正斜杠或者双反斜杠,我第一次写成了单反斜杠,结果Claude直接报"找不到模块",排查了半天才发现是JSON转义问题。这是新手最容易踩的配置坑之一。
保存配置后重启Claude Desktop,再打开对话框,会看到一个像"扳手"一样的图标,点开能看到excel-assistant下挂着的所有工具列表。到这一步,说明AI客户端已经成功发现并加载了你的Server。
5.2 一次完整的实测对话
配置完成后,我做了次端到端测试。在测试目录放一个6月销售台账.xlsx,里面是几个业务员的分产品销量表。我在对话框里输入:
"帮我看看C:/demo/6月销售台账.xlsx里有哪些工作表,每个表大概什么结构,然后告诉我哪个业务员的销售额最高。"
你观察AI的思考过程会非常有意思。它先调用list_sheets拿到工作表清单,再调用peek_sheet逐表看前五行,接着调用read_range_as_markdown把全表数据拉出来,最后自己完成排序和汇总,给出答案。整个过程不需要你贴任何文本、不需要你手动跑任何脚本,AI像长了手一样在自己的逻辑驱动下一步步完成操作。
我还拿它做过更复杂的任务:"把'销售明细'表里销售额不足1000元的行删掉,同时把'汇总'表C列的空单元格填0,最后在'周报'表末尾补一行本月总计。"这种需要多工具协调、带条件判断的活,在MCP工具集加持下,AI完成得又快又准。我第一次跑通的时候,说实话有点恍惚——这不就是我幻想了好几年的"数字员工"吗。
5.3 远程部署:用SSE把能力暴露出去
如果你不想限制在本地桌面客户端,可以让Server以SSE模式跑起来:
if __name__ == "__main__": mcp.run(transport="sse")启动后Server会监听某个端口(默认HTTP端口),支持MCP的客户端就能通过http://服务器IP:端口/mcp来连接。我最后把这个Server部署在了内网一台机器上,这样团队同事都能在各自的AI客户端里直接用它处理共享盘里的报表。
需要强调的是,SSE模式没有stdio那种"只在本机运行"的天然安全边界,一旦暴露到网络,任何人都可能调用你的工具去读取服务器上的文件。所以远程部署时至少要做两件事:一是限制监听地址,不要用0.0.0.0裸奔,尽可能只在受信网络内使用;二是在工具内部加权限校验,后面第6节我会细说。生产环境如果要用更复杂的鉴权,可以考虑在入口处加一层认证代理,但这就超出这篇入门文章的范围了。
5.4 对话效果之外:什么时候AI比脚本好
用了大概两周,我总结出AI+Excel工具集真正比传统脚本强的几个场景:
- 一次性、探索性的分析任务:你根本不确定最终要什么结果,边走边看、边看边改方向,这种需求写脚本要反复改代码,AI却天然擅长。
- 跨文件、跨sheet的松散整合:几个文件的结构还不完全一样,用脚本得写一堆异常兼容,AI能"随机应变"。
- 非技术人员的操作入口:你封装的MCP Server实际上是把Excel操作能力变成了自然语言接口,业务同事不需要懂Python,直接说需求就能用。
但反过来,如果你每天跑同一个固定报表、格式永远不变,那老老实实写个pandas脚本还是更靠谱——稳定、快、还不用烧token。AI+MCP适合做"前锋"去探索、去试错,定型之后仍然应该固化成常规脚本。这是效率层面的务实判断。
6. 从能用走向好用:安全边界与踩坑实录
最后一个大节,集中说说我跑这个项目时撞过的坑和总结出的实践。这些细节在官方文档里大多不会写,但恰恰是决定Server能不能"长期稳定服役"的关键。
6.1 文件安全:不能让AI乱读乱写
MCP工具本质上就是给AI开了一道"命令行"权限。AI是执刀人,你得想清楚让它动什么、不能动什么。我踩过一个典型的坑:把自己本地的报销单Excel放在一个目录里,结果有次让AI处理工作文件时它差点读到个人报销数据。教训就是:必须在工具内部做文件路径白名单校验。
我的做法是在Server顶部定义一个允许访问的目录列表,每个和文件路径相关的工具在真正执行前都先做一次校验:
ALLOWED_DIRS = ["C:/projects/excel_mcp/data"] def _safe_path(file_path: str) -> bool: normalized = os.path.abspath(file_path) return any(normalized.startswith(os.path.abspath(d)) for d in ALLOWED_DIRS)同时只允许.xlsx和.xlsm扩展名。这样即使AI在对话中收到某些引导性请求,工具层也会直接拒绝执行,等于给系统上了一把物理锁。
6.2 公式与缓存:data_only的暗坑
开头的坑必须再强调一次。load_workbook(path, data_only=True)读取的是公式计算后的缓存值。问题在于:如果这个Excel文件是从系统导出后从没被Excel软件打开算过,或者你的openpyxl只是写了公式进去但没经过Excel重算,那么这些单元格的缓存值是空的,data_only读出来全是None。
处理方式我视场景而定。需要"结果值"时用data_only=True,但必须允许AI感知到空值;需要"公式本身"时用data_only=False。最好在工具描述里写清楚"读取结果中'空'可能代表单元格真的为空,也可能代表公式未计算"。另外,如果AI要批量填公式,建议填完之后用LibreOffice或Excel公式批量重算一次,再重新接入读取。
6.3 性能陷阱:大表别硬怼
openpyxl对超过几万行的表性能不太友好,连续读写大表会卡到怀疑人生。我的策略是分级处理:小于1万行的表直接用openpyxl;更大的表用pandas读入再处理;只是快速探索结构时永远用read_only=True模式,只加载需要的那几个sheet和区域。还有一个经验是,工具描述里明确提醒AI"对于超大表格,优先使用peek_sheet而不是read_range_as_markdown"——把性能约束写进上下文,模型就会主动避坑,这比在代码层面做超时控制优雅得多。
6.4 工具描述真的是"写的什么,AI就信什么"
这一点我要单独拿出来说。MCP协议会把工具名和docstring原样喂给模型,模型的决策完全基于这段描述。你如果只写"读取单元格",AI大概率会在调用时困惑:我要传sheet吗?sheet名怎么写?文件路径是绝对路径还是相对路径?于是就会产生大量无效调用甚至幻觉结果。
后来我把所有工具描述都改成了"参数级说明书":每个参数都写清类型、格式、示例,甚至包括反例。写完后AI的首次调用成功率几乎翻倍。有次我在描述里加了"sheet_name为空时自动使用第一个工作表",AI甚至在对话里说"系统会自动选择默认表"——它真的把描述当常识用了。用写产品文档的态度去写工具的docstring,是整个项目的隐藏胜负手。
6.5 并发与文件锁
MCP Server本质是一个进程,多个客户端同时连接时会触发并发问题。我的Server使用threading.Lock包住了所有涉及文件读写的操作,避免两个AI同时打开同一个文件写坏数据。虽然目前的并发量不大,但这个锁在跑了一周后确实拦住过一次冲突——当时两个同事几乎同时让AI编辑同一个共享Excel,文件没坏,但一度出现过"最后写入覆盖先写入"的现象。有了锁之后,至少保证同一时刻只有一个写操作。
6.6 千万注意:让AI直接执行代码的诱惑
最后说一个我当初差点选错方向的问题。做这个过程时有人建议:"干脆别封装工具了,给AI一个execute_python工具,让它自己写代码自己执行,不是更灵活?"我试过的,效果确实灵活,但代价是安全性完全失控——模型会基于上下文自行编写任意文件操作代码,白名单机制形同虚设,而且一旦生成的代码有bug,报错信息模型自己不一定能看懂,调试成本更高。MCP限定工具集的思路才是正路:你把能力边界画好,让AI在边界内自由发挥。这既给了AI灵活性,又守住了数据和系统的底线。
写到这儿,我的第一个MCP项目算是完整复盘了。如果你想在自己的机器上复现,核心路径就是:搭环境 -> 写Server -> 封装Excel工具 -> Inspector验证 -> 接入AI客户端 -> 逐步加安全校验。我第一次跑通"AI自己读表、自己分析、自己写出结果文件"的时候,已经预感到以后处理杂七杂八的表格活不会再想回到"手动复制粘贴进对话"的老路了。接下来我打算给这套Server加上邮件发送和周报自动生成工具,把它从"Excel操作员"升级成一个能跑完一整条报表工作流的助手。你的第一个MCP想接什么能力,现在就可以动手了。