☰
从零手写 MCP Server:用 Python 让 AI 自动处理 Excel
2026/10/31 16:32:32 网站建设 项目流程

1. 为什么我要自己动手写一个 MCP

1.1 从一次被 Excel 折磨到崩溃说起

上个月帮朋友处理一批销售数据,两千多行,需要按区域拆分、按品类汇总、再生成带图表的周报。我当时的做法是打开 Excel,手动筛选、复制、粘贴、插入数据透视表,一套流程走下来花了将近四十分钟。更崩溃的是,第二周数据更新了,同样的操作我又得重来一遍。那一刻我脑子里只有一个念头:这东西能不能让 AI 直接帮我干完?

于是我开始研究 MCP。MCP 全称是 Model Context Protocol,翻译过来叫模型上下文协议,说白了就是一套让 AI 模型能够调用外部工具、读取外部数据的标准接口。你可以把它理解成 AI 世界的 USB 接口——以前每个 AI 应用要对接一个外部服务,都得自己写一套私有代码,现在有了统一协议,只要你的工具实现了 MCP,任何支持 MCP 的 AI 客户端都能直接调用。

这个项目要干的事情很明确:用 Python 写一个 MCP Server,把 Excel 的常用操作(读取、筛选、汇总、写入、生成图表)封装成 AI 可以调用的工具,然后接入支持 MCP 的 AI 客户端,实现“我说一句话,AI 帮我把 Excel 处理完”的效果。适合谁看?有一定 Python 基础、日常被 Excel 重复劳动折磨、想入门 AI Agent 开发的人。零基础也能跟着走,我会把每一步都拆开讲。

1.2 MCP 到底解决了什么核心问题

在没有 MCP 之前,想让 AI 操作 Excel,通常有几条路。第一条是让 AI 生成 VBA 代码,你复制到 Excel 里运行,问题是 VBA 调试麻烦,AI 生成的代码经常报错,而且每次都要手动粘贴。第二条是用 Python 脚本,让 AI 帮你写 pandas 代码,你保存成文件再运行,问题是数据路径、列名、格式每次都要改,AI 看不到你的实际数据长什么样。第三条是用一些低代码工作流平台,拖拽节点配置,灵活度有限,复杂逻辑很难表达。

MCP 的思路不一样。它把“能力”和“调用”解耦了。我写好一个 Excel 处理的 MCP Server,里面定义了若干工具函数,比如read_excel、filter_rows、pivot_summary、write_excel。AI 客户端启动时会读取这个 Server 的工具列表,知道有哪些能力可用。当用户说“帮我把销售表按区域汇总一下”,AI 会自动判断需要调用read_excel读取数据,再调用pivot_summary做汇总,最后把结果返回给用户。整个过程 AI 是“看着真实数据”在做决策,而不是盲写代码。

这就是 MCP 的核心价值:让 AI 从“生成代码的工具”变成“直接操作数据的执行者”。对于 Excel 这种结构化数据处理场景,这个转变带来的效率提升是数量级的。

1.3 技术选型:为什么是 Python + openpyxl + pandas

实现 MCP Server 的语言选择很多,Node.js、Python、Go 都能做。我选 Python 的原因很实际:Excel 处理生态最成熟。pandas 做数据分析和汇总,openpyxl 做单元格级别的读写和格式控制,两个库配合几乎能覆盖所有 Excel 操作场景。

具体分工是这样的:pandas 负责数据的读取、筛选、分组、聚合、透视,它的 DataFrame 结构处理表格数据非常顺手;openpyxl 负责写入时的格式设置,比如列宽、字体、边框、条件格式、图表插入。为什么不只用 pandas?因为 pandas 写出的 Excel 文件格式很朴素,没有样式,而实际工作中我们往往需要输出带格式的报表。为什么不只用 openpyxl?因为 openpyxl 做数据聚合太啰嗦,写个分组求和要循环好几层,pandas 一行groupby就搞定了。

MCP Server 的框架我选用官方提供的 Python SDK,它封装了协议通信的底层细节,我只需要关注工具函数的实现。整个项目的依赖很轻量:mcp、pandas、openpyxl,三个包,pip 一次装完。

2. 环境搭建与 MCP Server 骨架

2.1 Python 环境准备与依赖安装

先确认你的 Python 版本。MCP 的 Python SDK 要求 Python 3.10 及以上,我实测 3.11 和 3.12 都没问题。打开终端输入python --version看一下,如果低于 3.10,建议去官网下载最新版安装。Windows 用户安装时记得勾选“Add Python to PATH”,不然命令行里找不到 python 命令。

装好 Python 之后,我强烈建议用虚拟环境,不要直接装在全局。原因很简单:不同项目的依赖版本可能冲突,虚拟环境能隔离。创建虚拟环境的命令是python -m venv mcp-excel-env,然后激活:Windows 下是mcp-excel-env\Scripts\activate,Mac 和 Linux 下是source mcp-excel-env/bin/activate。激活后命令行前面会出现(mcp-excel-env)的标识。

接下来安装依赖。我习惯先升级 pip 再装包,避免一些奇怪的兼容问题:

pip install --upgrade pip pip install mcp pandas openpyxl

这里有个小坑要注意:如果你之前装过旧版本的 pandas,可能会有版本冲突。我遇到过 pandas 1.x 和 openpyxl 新版本不兼容的情况,报错信息是AttributeError: 'DataFrame' object has no attribute 'style'。解决办法就是升级 pandas 到 2.x:pip install --upgrade pandas。装完之后用pip list检查一下三个包的版本,pandas 建议 2.0 以上,openpyxl 建议 3.1 以上,mcp 用最新的就行。

2.2 MCP Server 的最小可运行骨架

MCP Server 的代码结构其实很清晰。核心就是创建一个 Server 实例,然后用装饰器注册工具函数,最后启动服务。我先给你一个最小骨架,让你感受一下整体结构:

from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent import asyncio app = Server("excel-mcp-server") @app.list_tools() async def list_tools(): return [ Tool( name="read_excel", description="读取Excel文件,返回前若干行数据预览", inputSchema={ "type": "object", "properties": { "file_path": {"type": "string", "description": "Excel文件路径"}, "sheet_name": {"type": "string", "description": "工作表名称,默认第一个"} }, "required": ["file_path"] } ) ] @app.call_tool() async def call_tool(name: str, arguments: dict): if name == "read_excel": # 具体实现逻辑 return [TextContent(type="text", text="读取成功")] raise ValueError(f"未知工具: {name}") async def main(): async with stdio_server() as (read_stream, write_stream): await app.run(read_stream, write_stream, app.create_initialization_options()) if __name__ == "__main__": asyncio.run(main())

这段代码里有两个关键装饰器。@app.list_tools()告诉 MCP 客户端“我有哪些工具可用”,返回的是一个 Tool 列表,每个 Tool 包含名称、描述和参数 schema。@app.call_tool()是实际执行入口,客户端调用某个工具时,请求会路由到这里,根据工具名分发到具体实现。

参数 schema 用的是 JSON Schema 格式,properties里定义每个参数的类型和说明,required列出必填参数。这个 schema 很重要,AI 客户端会根据它来判断该传什么参数。描述写得越清楚,AI 调用时越不容易出错。

2.3 通信方式选择:stdio 还是 SSE

MCP 支持两种通信方式:stdio 和 SSE。stdio 是标准输入输出,Server 和客户端在同一台机器上,通过管道通信,配置简单,适合本地使用。SSE 是 Server-Sent Events,走 HTTP 协议,适合 Server 部署在远程服务器上的场景。

我这个项目选的是 stdio,原因很直接:Excel 文件在本地,Server 也在本地,没必要走网络。而且 stdio 方式不需要处理端口占用、防火墙、认证这些问题,配置起来省心。如果你后续想把 Excel 处理能力共享给团队用,可以改成 SSE 方式部署到内网服务器,但那是另一个话题了。

stdio 方式的配置在 AI 客户端那边通常长这样:

{ "mcpServers": { "excel-processor": { "command": "python", "args": ["/path/to/your/excel_server.py"] } } }

客户端启动时会自动执行这个命令,把 Server 进程拉起来,然后通过标准输入输出交换消息。你不需要手动去运行 Server,客户端会帮你管理生命周期。

3. 核心工具函数的实现细节

3.1 读取 Excel:不只是 pd.read_excel 那么简单

读取 Excel 看起来简单,但实际场景里有很多细节要处理。比如文件可能有多个 sheet,用户可能只想读其中一个;比如表头可能不在第一行,前面有几行说明文字;比如某些列可能是合并单元格,pandas 读出来会是 NaN。我的read_excel工具做了这些处理:

import pandas as pd def read_excel_file(file_path: str, sheet_name: str = None, header_row: int = 0, max_rows: int = 20): try: xl = pd.ExcelFile(file_path) sheets = xl.sheet_names if sheet_name is None: sheet_name = sheets[0] df = pd.read_excel(file_path, sheet_name=sheet_name, header=header_row) preview = df.head(max_rows) info = { "sheet_names": sheets, "current_sheet": sheet_name, "total_rows": len(df), "total_columns": len(df.columns), "columns": list(df.columns), "dtypes": {col: str(dtype) for col, dtype in df.dtypes.items()}, "preview": preview.to_dict(orient="records") } return info except FileNotFoundError: return {"error": f"文件不存在: {file_path}"} except Exception as e: return {"error": f"读取失败: {str(e)}"}

这里有几个设计决策值得说明。第一,我返回的不只是数据预览,还有 sheet 列表、总行数、列名、每列的数据类型。为什么?因为 AI 需要这些元信息来做决策。比如用户说“按金额汇总”,AI 需要知道哪一列是金额列,如果列名是“销售金额(元)”而不是“金额”,AI 看到列名列表就能匹配上。第二,我限制了预览行数,默认 20 行。如果数据有几万行,全量返回会撑爆上下文窗口,AI 反而处理不了。第三,异常处理返回的是结构化错误信息,而不是直接抛异常,这样 AI 能理解发生了什么并给用户友好的提示。

注意:读取大文件时,pandas 默认会加载全部数据到内存。如果文件超过 100MB,建议加nrows参数限制读取行数,或者用chunksize分块读取。我处理过一个 50 万行的文件,直接读导致内存飙到 2GB,后来改成只读前 1000 行做预览,实际处理时再分块。

3.2 筛选与查询:让 AI 用自然语言过滤数据

筛选是 Excel 里最高频的操作之一。传统做法是手动点筛选按钮,或者写公式。在 MCP 里,我把筛选封装成一个工具,AI 根据用户意图生成筛选条件,然后调用这个工具执行。

def filter_data(file_path: str, sheet_name: str, conditions: list, logic: str = "and"): df = pd.read_excel(file_path, sheet_name=sheet_name) mask = None for cond in conditions: col = cond["column"] op = cond["operator"] val = cond["value"] if op == "eq": m = df[col] == val elif op == "gt": m = df[col] > val elif op == "lt": m = df[col] < val elif op == "contains": m = df[col].astype(str).str.contains(str(val), na=False) elif op == "in": m = df[col].isin(val) else: continue if mask is None: mask = m elif logic == "and": mask = mask & m else: mask = mask | m result = df[mask] if mask is not None else df return { "matched_rows": len(result), "data": result.head(50).to_dict(orient="records") }

conditions 是一个列表,每个条件包含列名、操作符、值。操作符支持等于、大于、小于、包含、在列表中这几种。logic 参数决定多个条件之间是“与”还是“或”的关系。

这个设计的好处是灵活。用户说“帮我找出华东区销售额大于一万的订单”,AI 会解析成两个条件:{"column": "区域", "operator": "eq", "value": "华东"}和{"column": "销售额", "operator": "gt", "value": 10000},logic 设为 and。用户说“找出北京或者上海的客户”,AI 会生成{"column": "城市", "operator": "in", "value": ["北京", "上海"]}。

实操心得:contains操作符我加了astype(str)转换,因为如果列里有数字或日期,直接调.str会报错。另外na=False是为了让 NaN 值不参与匹配,避免结果里混入空行。这两个细节看起来小,但不处理的话实际用起来经常出问题。

3.3 分组汇总与透视:一行代码背后的参数设计

分组汇总是 Excel 数据透视表的核心功能。pandas 的groupby做这件事非常高效,但参数设计要考虑 AI 怎么调用。

def pivot_summary(file_path: str, sheet_name: str, group_by: list, agg_column: str, agg_func: str = "sum"): df = pd.read_excel(file_path, sheet_name=sheet_name) func_map = { "sum": "sum", "mean": "mean", "count": "count", "max": "max", "min": "min", "median": "median" } if agg_func not in func_map: return {"error": f"不支持的聚合函数: {agg_func}"} result = df.groupby(group_by)[agg_column].agg(func_map[agg_func]).reset_index() result = result.sort_values(agg_column, ascending=False) return { "group_count": len(result), "data": result.to_dict(orient="records") }

group_by 是分组列名的列表,支持多列分组。agg_column 是要聚合的数值列,agg_func 是聚合方式。我支持了求和、平均、计数、最大、最小、中位数六种,覆盖了绝大多数场景。

这里有个细节:结果我按聚合值降序排列了。为什么?因为用户看汇总结果时,通常最关心“哪个最多/最高”。默认降序能让 AI 在回答时直接说“华东区最高,达到 XX”,而不需要再排一次序。

注意:如果 agg_column 不是数值列,求和会报错。我在实际使用中加了一层判断,如果聚合函数是 sum 或 mean,先检查列的数据类型,不是数值就返回错误提示。这个检查很有必要,因为 AI 有时候会选错列,提前拦截比让它报一堆 traceback 要好。

3.4 写入与格式化:让输出结果能直接交付

处理完数据,最终要写回 Excel。如果只是df.to_excel(),出来的文件没有格式,列宽窄得看不清,数字没有千分位,标题没有加粗。这种文件拿给领导看肯定不行。所以我用 openpyxl 做了一层格式化。

from openpyxl import Workbook from openpyxl.styles import Font, Alignment, PatternFill, Border, Side from openpyxl.utils.dataframe import dataframe_to_rows def write_excel(data: list, output_path: str, sheet_name: str = "结果", headers: list = None): wb = Workbook() ws = wb.active ws.title = sheet_name if not data: wb.save(output_path) return {"status": "success", "message": "数据为空,已创建空文件"} if headers is None: headers = list(data[0].keys()) header_font = Font(bold=True, color="FFFFFF", size=11) header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") thin_border = Border( left=Side(style="thin"), right=Side(style="thin"), top=Side(style="thin"), bottom=Side(style="thin") ) for col_idx, header in enumerate(headers, 1): cell = ws.cell(row=1, column=col_idx, value=header) cell.font = header_font cell.fill = header_fill cell.alignment = Alignment(horizontal="center", vertical="center") cell.border = thin_border for row_idx, row_data in enumerate(data, 2): for col_idx, header in enumerate(headers, 1): cell = ws.cell(row=row_idx, column=col_idx, value=row_data.get(header)) cell.border = thin_border if isinstance(row_data.get(header), (int, float)): cell.number_format = "#,##0.00" for col_idx, header in enumerate(headers, 1): max_len = len(str(header)) for row_data in data[:100]: val_len = len(str(row_data.get(header, ""))) if val_len > max_len: max_len = val_len ws.column_dimensions[ws.cell(row=1, column=col_idx).column_letter].width = min(max_len + 4, 40) wb.save(output_path) return {"status": "success", "output_path": output_path, "rows_written": len(data)}

这段代码做了几件事:表头加粗白字蓝底、所有单元格加细边框、数字列自动加千分位格式、列宽根据内容自动调整(上限 40 字符,避免某一列特别宽)。这些格式看起来是小事,但实际交付时,一个格式整齐的文件和一个裸数据文件,给人的专业感差距很大。

实操心得:列宽计算我用了min(max_len + 4, 40),加 4 是留点边距,上限 40 是防止备注列内容太长把表格撑得没法看。另外data[:100]只取前 100 行算列宽,数据量大时不用全量遍历,速度更快,效果也够用。

4. 接入 AI 客户端与完整工作流演示

4.1 客户端配置与连接测试

Server 写好了,接下来要接入 AI 客户端。我用的是支持 MCP 的桌面客户端,配置方式是在配置文件里加一段 JSON。不同客户端的配置文件位置不一样,一般在设置里能找到“MCP Servers”或“开发者选项”的入口。

配置内容就是我前面提到的 stdio 方式:

{ "mcpServers": { "excel-processor": { "command": "python", "args": ["D:/projects/excel_mcp/server.py"], "env": { "PYTHONIOENCODING": "utf-8" } } } }

这里有个 Windows 用户经常踩的坑:路径要用正斜杠或者双反斜杠。我一开始写的是D:\projects\excel_mcp\server.py,结果 JSON 解析报错,因为反斜杠在 JSON 里是转义字符。改成D:/projects/excel_mcp/server.py就好了。另外PYTHONIOENCODING设成 utf-8 是为了避免中文乱码,Windows 默认编码是 gbk,处理中文列名时容易出问题。

配置保存后重启客户端,在对话界面输入“列出你可用的工具”,如果配置成功,AI 会返回 excel-processor 提供的工具列表。如果没反应,检查客户端日志,常见问题是 Python 路径不对(虚拟环境没激活)或者依赖没装全。

4.2 一个完整的 Excel 处理对话实录

配置好之后,我拿一份真实的销售数据做了测试。文件叫sales_2024.xlsx,有 1500 行,列包括:订单编号、日期、区域、城市、品类、销售额、数量、负责人。

我的第一句话是:“帮我看看 sales_2024.xlsx 这个文件里有什么。”

AI 调用了read_excel,返回了 sheet 列表、列名、数据类型和前 20 行预览。然后它总结说:“这个文件有一个工作表,包含 1500 行数据,8 个列。主要字段有订单编号、日期、区域、城市、品类、销售额、数量和负责人。销售额是数值类型,日期是日期类型。”

第二句话:“按区域汇总销售额,从高到低排。”

AI 调用了pivot_summary,参数是group_by=["区域"]、agg_column="销售额"、agg_func="sum"。返回结果后,AI 说:“华东区销售额最高,达到 328 万;其次是华南区 256 万;华北区 198 万;西南区 145 万;东北区 89 万。”

第三句话:“把华东区的数据单独导出来,只要销售额大于 5000 的订单。”

AI 先调用filter_data,条件是两个:区域等于华东、销售额大于 5000,logic 是 and。然后调用write_excel把结果写到新文件。最后告诉我:“已筛选出 127 条符合条件的订单,导出到华东区大额订单.xlsx。”

整个过程我没有打开 Excel,没有写一行公式,没有手动筛选。从说话到拿到结果文件,不到两分钟。同样的操作手动做,至少十五分钟。

4.3 处理复杂场景:多步骤任务的拆解

单步操作已经能省不少事了,但 MCP 真正的威力在于多步骤任务的自动编排。我试了一个更复杂的场景:“帮我分析一下每个区域的销售情况,找出每个区域销售额最高的品类,然后生成一份汇总报告。”

AI 的处理流程是这样的:先调用read_excel了解数据结构,然后调用pivot_summary按区域和品类两个维度分组求和,拿到结果后自己在上下文里做二次分析,找出每个区域的最大值对应的品类,最后调用write_excel把分析结果写成报告文件。

这个过程中,AI 不是简单地执行单个工具,而是在多个工具调用之间做推理和决策。它知道先读数据才能汇总,汇总完才能找最大值,找到结果才能写文件。这种编排能力是 MCP 架构带来的核心优势——AI 有了“手”,能真正操作数据,而不只是“嘴”,只能告诉你怎么做。

注意:多步骤任务对 AI 的上下文窗口有要求。如果中间结果数据量很大,可能会超出窗口限制。我的经验是,在工具函数里尽量返回摘要信息而不是全量数据。比如pivot_summary返回的是聚合后的结果,通常只有几十行,不会撑爆上下文。如果确实需要处理大数据,可以分批次调用,每次处理一部分。

5. 踩坑记录与常见问题排查

5.1 工具调用失败的五种典型情况

在实际开发和调试过程中,我遇到了不少问题,整理成一张速查表,方便你对照排查:

问题现象可能原因排查方法解决方案
客户端看不到工具列表Server 启动失败手动运行python server.py看报错检查依赖是否装全,Python 版本是否 3.10+
调用工具返回空结果文件路径不对或 sheet 名错误在工具里打印实际路径和 sheet 列表用绝对路径,sheet 名从 read_excel 返回的列表里选
中文列名匹配不上编码问题检查返回的列名是否有乱码设置PYTHONIOENCODING=utf-8,读取时指定encoding
写入文件后格式丢失用了df.to_excel而非 openpyxl打开文件看是否有样式改用 openpyxl 逐单元格写入并设置样式
大文件处理超时全量加载内存看内存占用和耗时加nrows限制,或分块读取

5.2 那些文档里不会写的实操细节

第一个坑是路径问题。Windows 上路径分隔符是反斜杠,但在 JSON 配置和 Python 字符串里经常需要转义。我的建议是统一用正斜杠,Python 和 Windows 都能识别。如果非要用反斜杠,在 Python 字符串里用原始字符串r"D:\path\to\file",在 JSON 里用双反斜杠"D:\\path\\to\\file"。

第二个坑是 pandas 的read_excel默认把第一行当表头。但实际业务表格经常前几行是标题、说明、合并单元格,真正的表头在第三行或第五行。这时候要传header=2(从 0 开始计数)。我在read_excel工具里加了这个参数,AI 发现列名是“Unnamed: 0”这种就会尝试调整 header 参数重新读取。

第三个坑是日期格式。Excel 里的日期读进 pandas 可能是字符串,也可能是 datetime 对象,取决于单元格格式。如果要做日期筛选,最好在读取时用parse_dates参数指定日期列,或者在工具里做一次转换。我遇到过用户说“筛选三月份的数据”,结果日期列是字符串格式,比较大小变成了字典序比较,三月份的数据全错了。

第四个坑是并发写入。如果多个 AI 会话同时调用write_excel写同一个文件,会冲突。我的处理方式是在文件名里加时间戳,或者让用户指定输出路径。MCP Server 本身是单进程的,但客户端可能同时发起多个调用,这个要注意。

5.3 性能优化的几个实用技巧

处理大文件时,性能是绕不开的话题。我总结了几个实测有效的优化手段。

第一,读取时只加载需要的列。pandas 的read_excel支持usecols参数,比如usecols=["区域", "销售额"],只读这两列,内存占用和读取速度都能大幅下降。我在read_excel工具里加了这个可选参数,AI 在明确知道只需要某几列时会自动传入。

第二,聚合前先过滤。如果用户要的是“华东区的销售汇总”,不要先全量 groupby 再筛选,而是先 filter 出华东区再 groupby。数据量大的时候,这个顺序差异能带来几倍的性能差距。我在工具设计上让 AI 可以自由组合调用顺序,它通常会先 filter 再 pivot。

第三,写入时用write_only模式。openpyxl 的Workbook(write_only=True)模式内存占用更低,适合写入大量数据。但缺点是不能再读取单元格,只能追加。对于纯输出场景,这个模式很合适。

第四,缓存读取结果。如果同一个文件在短时间内被多次读取,可以在 Server 内存里缓存 DataFrame,用文件路径和修改时间做 key。文件没变就直接返回缓存,省去重复 IO。这个优化我实测能减少 60% 以上的重复读取时间。

6. 从第一个 MCP 到工作流自动化

6.1 这个项目还能怎么扩展

写完这个 Excel MCP Server 之后,我发现这套模式可以复制到很多场景。比如你可以做一个 CSV 处理的 MCP,逻辑几乎一样,只是把read_excel换成read_csv。也可以做一个数据库查询的 MCP,把read_excel换成execute_sql,让 AI 直接查数据库。甚至可以做一个文件管理的 MCP,让 AI 帮你批量重命名、移动、整理文件。

更进一步,你可以把多个 MCP Server 组合使用。比如 Excel MCP 负责数据处理,邮件 MCP 负责发送报告,定时任务 MCP 负责触发。AI 客户端同时连接这几个 Server,就能实现“每天上午九点读取销售数据,汇总后生成报告,自动发送给相关负责人”这样的完整工作流。这就是 AI Agent 的雏形——不是单个工具,而是工具的组合编排。

6.2 我个人的一些使用体会

用了一段时间之后,我最大的感受是:MCP 把 AI 从“顾问”变成了“执行者”。以前我问 AI“怎么用 pandas 做数据透视”,它给我一段代码,我还要自己改路径、改列名、调试运行。现在我说“帮我做数据透视”,它直接做完把结果给我。这个体验差异是质的改变。

另一个体会是,工具的描述文字非常关键。description字段写得好不好,直接决定 AI 能不能正确调用。我一开始写得很简略,比如“读取 Excel”,结果 AI 经常不知道该传什么参数。后来改成“读取 Excel 文件,返回工作表列表、列名、数据类型和前 20 行数据预览。file_path 参数必填,sheet_name 可选,不传则读取第一个工作表”,调用准确率明显提升。

还有一点,错误处理要做在工具内部。不要让异常直接抛到 MCP 协议层,那样 AI 收到的是一个模糊的错误消息,没法给用户有用的反馈。我现在的做法是每个工具函数都用 try-except 包起来,返回结构化的错误信息,比如{"error": "文件不存在", "file_path": "xxx"}。AI 拿到这个信息就能告诉用户“你指定的文件路径不对,请检查一下”。

最后分享一个小技巧:在开发阶段,我会在工具函数里加日志输出,把每次调用的参数和返回结果写到本地文件。这样当 AI 行为不符合预期时,我可以翻日志看它到底传了什么参数、拿到了什么结果,排查起来比猜要快得多。日志文件按天分割,避免无限增长。这个习惯帮我省了很多调试时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询