从Lensa看MCP协议:AI工具集成与智能体能力调用的标准化实践

从Lensa看MCP协议:AI工具集成与智能体能力调用的标准化实践 Lensa 是一个以开源方式组织 MCP connectors 和 skills 的项目目标是把 ChatGPT 等 AI 助手接入外部工具和业务系统时的重复工作收敛成一套可复用配置。实际做 AI 应用集成的人会遇到同一个问题模型本身只负责生成文本真正要完成“查数据库、改工单、读文档、发通知”这类动作必须靠外部工具。每次接入一个工具都写一套自定义插件成本高且难以维护Lensa 这类项目选择的做法是基于 MCP 协议把连接器connectors和能力包skills统一封装起来让 ChatGPT 这类客户端通过标准协议发现并调用工具。这篇文章不会只讲 Lensa 的仓库结构。我会把 MCP 的协议概念、最小可运行 server、connector 与 skill 的职责边界、常见启动报错和生产环境落地建议串在一起帮你建立一条完整的接入路径。读完以后你可以回到 Lensa 这类项目里对照目录理解每个文件的作用也可以自己从零写一个供 ChatGPT 使用的 MCP server 和 skill。1. Lensa 是什么它解决 ChatGPT 扩展能力时的什么问题1.1 从 API 插件到 MCPAI 应用连接外部世界的三种方式大模型应用要操作外部系统通常有三条路可走。第一条路是模型内置工具调用。OpenAI 的函数调用、Anthropic 的 tool use本质是让模型输出一个结构化调用意图再由应用代码去执行。这种方式灵活但每个工具都要单独写注册逻辑、参数校验和执行函数接入方和平台方耦合很高。第二条路是传统插件体系。插件平台定义一套 HTTP API 或事件接口开发者按照规范把能力封装成插件。这种做法的好处是生态统一缺点是协议绑定在具体平台上ChatGPT 的插件不能直接用到其他客户端的场景里。第三条路就是 MCP。MCP 把“AI 应用如何发现和调用工具”这个环节标准化类似给 AI 世界做了一个 USB-C 接口。无论客户端是 ChatGPT、Claude Desktop、Dify 还是自研 Agent只要支持 MCP就能连接同一个 MCP server。Lensa 这类项目的价值就在这里它把常用系统的接入能力connectors和面向场景的行为模板skills做成开源资产减少重复造轮子。1.2 理解 connectors 和 skills 的分工只看项目标题容易把 connectors 和 skills 混为一谈实际上它们解决的是两个完全不同层级的问题。connectors 解决的是“能不能连得上”。它负责通信、鉴权、请求封装、数据格式转换。一个 GitHub connector要处理的是 API 地址、Token、分页、限流、错误码最终把“列出某个仓库的 issue”“读取某个文件内容”暴露成模型可调用的工具。skills 解决的是“连上了之后怎么做”。它是一段结构化的行为指令告诉模型在什么场景下、按什么流程、调用哪些工具、输出什么格式。一个 frontend review skill可以把“阅读代码、打开页面截图、检查可访问性、输出审查报告”这套流程固化下来。下面用一张表对比两者的边界。对比维度ConnectorSkill核心问题外部系统如何被调用模型如何组织行为主要载体MCP server、配置、SDKSKILL.md、提示词、示例变更频率外部系统 API 变化时更新业务规则变化时更新失败表现连接失败、鉴权失败、超时模型行为不达标、流程缺失测试方式用 MCP Inspector 验证工具返回用典型输入做对话回归实际项目中两者是配合关系。一个 skill 的声明里通常会写明“这个能力依赖哪个 connector”而 connector 提供工具skill 决定工具何时被调用。1.3 什么时候值得用 Lensa 这类项目如果只是想在本地让 ChatGPT 读一个 CSV 文件不需要引入项目级封装一个最简单的 MCP server 就够。但如果你的场景符合下面任一条件Lensa 这类开源资产的价值就会显现。一是团队需要同时接入多个外部系统。每个系统都从零写连接器会重复处理鉴权、日志、错误码这些共性工作统一封装后可以共享维护经验。二是技能需要沉淀和复用。项目里积累的 skill 不只是提示词而是包含工作流、工具依赖和示例的结构化资产新成员接手时不需要从聊天记录里找经验。三是客户端可能变化。今天用 ChatGPT明天要接到 Dify 或者其他 Agent 平台基于 MCP 封装后迁移成本主要在客户端配置层面而不是重写整套工具链。需要提醒的是使用开源项目时不要假设里面的配置开箱即用。仓库里给出的是示例环境下的默认值落地前要重新确认依赖版本、鉴权方式和目标客户端的支持情况。2. 先把 MCP 协议的核心概念讲清楚2.1 MCP 是什么为什么能替代一堆自定义插件MCP 全称是 Model Context Protocol是一套基于 JSON-RPC 的开放协议。它定义了 AI 客户端MCP client和外部工具服务MCP server之间的消息格式、请求流程和能力模型。理解它可以拿浏览器类比浏览器通过 HTTP 协议访问各种网站不需要为每个网站单独实现一套传输层MCP 要做的就是让 AI 应用通过统一协议访问各种工具不用为每个工具单独实现一套调用链。一个 MCP 会话的默认消息格式基本是 JSON-RPC 风格的请求和响应。客户端发送初始化请求服务端返回协议版本和服务器能力然后双方进入正常调用阶段。整个过程不需要理解对方的业务实现只需要遵守消息格式。这也是它能替代自定义插件的原因平台方只需要实现一个 MCP client就能连接所有符合协议的 server工具方只需要实现一个 MCP server就能被所有支持 MCP 的客户端复用。2.2 MCP server、MCP client、capability 的生命周期一次完整的 MCP 交互通常包括三个阶段。初始化阶段客户端向 server 发送 initialize 请求server 返回协议版本、自身能力和 server 信息。客户端确认协议版本后发送 initialized 通知。能力发现阶段server 通过 capabilities 字段声明自己支持哪些能力。常见能力包括 tools、resources、prompts。客户端可以根据声明决定如何展示和调用。调用阶段对于 tools 类型能力客户端会先调用 tools/list 获取工具清单再根据模型决策调用 tools/call 执行具体工具。每次调用包含工具名和参数server 返回结构化结果。这里的关键认知是MCP server 本身不产生智能决策它只负责能力注册和执行。是否调用某个工具、按什么顺序调用是模型和客户端协作决策的结果。这就解释了为什么很多项目“连上了但模型不调用”问题往往不在连接层而在工具描述或 skill 指令写得不够清楚。2.3 MCP 与普通 REST API 的差异很多第一次接触 MCP 的人会问既然外部系统都有 REST API为什么还要经过 MCP因为 REST API 是为“确定的程序调用”设计的而 MCP 是为“不确定的模型决策”设计的。两者的差异主要体现在三个地方。对比维度REST APIMCP调用发起方程序代码明确调用模型根据语义决定是否调用接口契约由开发人员阅读文档后编写代码由模型读取工具描述后生成参数发现机制人工阅读 API 文档client 通过 tools/list 自动发现能力聚合一个系统一套 API一个 MCP server 可聚合多个系统上下文传递靠调用方拼接协议层可以关联 resources 和 prompts所以 MCP 不是要取代 REST API它是套在 API 上层的一层语义适配。server 内部仍然可以用 REST、数据库连接或 SDK 去访问外部系统只是对外统一暴露成 MCP 协议。3. 环境准备在自己电脑上先跑通一个 MCP server3.1 前置依赖学习阶段不需要太复杂的环境建议先准备以下几项。依赖项说明建议版本Python运行 MCP server 示例3.10 及以上uv 或 pip管理 Python 依赖最新稳定版MCP Python SDK提供 FastMCP 等开发接口以官方最新版本为准Node.js运行 MCP Inspector 工具18 及以上安装 MCP SDK 的命令在 pip 和 uv 下分别是pip install mcp[cli]uv add mcp安装完成后可以确认版本python -c import mcp; print(mcp.__version__)如果这条命令报错先检查当前 Python 环境是否和安装 SDK 的环境一致。实际开发中很多问题都出在“安装了一个环境运行在另一个环境”。3.2 最小 MCP server 示例下面用一个最小示例说明 MCP server 的骨架。这个 server 只暴露一个工具模拟查询服务器健康状态。下面代码用于说明思路不同 SDK 版本在装饰器风格上可能有差异请以你当前安装的版本为准。from mcp.server.fastmcp import FastMCP mcp FastMCP(lensa-demo) mcp.tool() def query_server_health(host: str) - dict: 查询指定服务器的健康状态。 return { host: host, status: ok, latency_ms: 23, checked_at: 2025-01-01T10:00:00Z } if __name__ __main__: mcp.run(transportstdio)这里有几个关键点。工具函数必须有清晰的中文或英文描述模型会读取这个描述来决定是否调用。如果描述写成健康状态模型可能理解不够如果写成查询指定服务器的健康状态返回存活状态和延迟毫秒数模型的调用意愿会明显提高。返回值尽量是 JSON 可序列化的结构不要返回对象或自定义类否则 client 在解析时可能失败。示例用 stdio 作为传输方式这是学习阶段最简单的方式由客户端启动 server 进程并通过标准输入输出通信。注意不要直接运行python server.py后期待看到输出因为 MCP 的数据是通过 stdio 在进程间传递的不是打印到终端。3.3 用 MCP Inspector 验证连接本地验证 MCP server 是否正常推荐使用 MCP Inspector。先启动 Inspectornpx modelcontextprotocol/inspector python server.pyInspector 会启动一个本地 Web 界面默认地址通常是http://localhost:6277具体端口以终端输出为准。在界面里可以完成 initialize、tools/list、tools/call 等操作相当于手动模拟客户端和 server 对话。验证通过的标准初始化请求返回 success。tools/list 能看到query_server_health这个工具。tools/call 传入host参数后返回 JSON 结果。传错参数时能收到错误提示。这一步通过后再接入 ChatGPT、Claude Desktop 或 Dify 才有意义。连接问题要先用 Inspector 排除不要在客户端界面里反复猜。3.4 常见坑不要污染 stdout学习阶段最常踩的坑是在 server 代码里加print调试然后发现客户端连接失败或者返回结果解析异常。原因在于 stdio 模式下stdout 是 MCP 协议消息的传输通道。任何非 JSON-RPC 的文本输出都会破坏协议解析。正确做法是使用标准日志模块并把日志输出到 stderr 或文件import logging logging.basicConfig( filenamemcp_server.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) logging.info(server started)生产环境里日志监控是排障的重要依据不要节省这一步。4. Lensa 这类项目里的 connectors 和 skills 应该怎么组织4.1 典型目录结构Lensa 的项目定位决定了它通常会把连接器和技能分开管理。一个具备扩展性的目录结构通常是这样的lensa/ ├── connectors/ │ ├── github/ │ │ ├── connector.json │ │ ├── server.py │ │ └── README.md │ ├── figma/ │ ├── ssh/ │ └── database/ ├── skills/ │ ├── frontend-review/ │ │ ├── SKILL.md │ │ └── examples/ │ ├── sql-analysis/ │ └── incident-response/ ├── config.example.toml ├── requirements.txt └── README.mdconnectors 目录下每个子目录是一个可独立运行的 MCP server包含配置文件和实现代码。skills 目录下每个子目录是一个行为模板核心是 SKILL.md 文件。这样一来连接器可以单独测试技能可以单独编辑两者互不阻塞。4.2 connector 配置示例connector 的配置通常描述“如何启动一个 server、需要哪些环境变量、暴露哪些能力”。一个示意配置如下{ name: github, transport: stdio, command: python, args: [connectors/github/server.py], env: { GITHUB_TOKEN_ENV: GITHUB_TOKEN }, capabilities: [tools, resources] }配置里值得注意的点是鉴权信息的引用方式。建议 env 里只写环境变量名不直接写 Token 值否则配置文件一旦提交到 Git 就会泄密。实际接入前要确认command 指向的解释器是否在 PATH 中。args 使用相对路径还是绝对路径客户端的工作目录是否稳定。目标客户端是否支持 capabilities 中声明的类型。4.3 skills 文件应包含哪些内容一个可被模型理解的 skill 文件通常包含 frontmatter 元信息和正文两部分。--- name: frontend-review description: 对前端页面做代码审查重点检查可访问性、性能和安全风险。 --- # Frontend Review 适用场景用户提交一个 GitHub Pull Request 链接或组件源码时。 工作流程 1. 使用 github connector 读取 PR 文件列表。 2. 定位 HTML、CSS、TypeScript 文件。 3. 检查图片是否缺少 alt交互元素是否有键盘操作路径。 4. 检查是否存在危险 HTML 注入风险。 5. 输出按严重级别排序的审查结论。 工具依赖 - github connector: 读取 PR 内容和文件 - playwright connector: 截图验证页面关键点有两个。第一description 必须写清触发条件。模型靠 description 判断这个 skill 适不适合当前场景如果描述写成“前端审查”触发率会很低写成“当用户需要审查前端页面、分析可访问性问题或评估 Pull Request 中的前端代码时使用”模型才能判断。第二工作流程要可执行。不要写“认真检查代码”这类空话而是写“先读取文件列表再检查特定模式最后输出结构”。模型会把这些流程当作执行约束。4.4 在 ChatGPT 和兼容客户端中加载 MCP server不同客户端加载 MCP server 的方式不同。有的通过 JSON 配置有的通过 TOML 配置有的通过界面操作。这里给出一个 Claude Desktop 风格的配置片段作为示例因为它在很多学习教程中可以通用。{ mcpServers: { lensa-demo: { command: python, args: [/absolute/path/to/server.py] } } }在 ChatGPT 或 Codex 相关环境中如果使用 config.toml结构可能与 JSON 不同。无论使用哪种格式都要注意三点路径使用绝对路径、解释器路径要准确、修改配置后需要重启客户端。注意不要只验证配置文件能读取要验证 MCP server 能启动、工具能被列出、调用能返回结果。配置加载成功和连接成功是两回事。5. 自己写一个 Skill把 AI 变成“懂规范”的助手5.1 skill 的目标这里用一个更贴近实际开发的场景把 AI 变成一名“能按团队规范审查 SQL 的助手”。目标是当用户粘贴 SQL 或请求分析慢查询时模型能按固定流程工作而不是泛泛说几句“建议加索引”。先明确 skill 要满足的规范SELECT 字段不允许使用*。必须为多表连接中的每张表声明别名。WHERE 条件中的字段不能套函数。慢查询需要对比执行计划。5.2 编写 SKILL.md--- name: sql-analysis description: 审查 SQL 语句识别慢查询、全表扫描和违反团队规范的风险点。 --- # SQL Analysis 触发条件用户粘贴 SQL、询问 SQL 性能问题、请求分析慢查询时使用。 工作流程 1. 提取用户输入中的 SQL 语句。 2. 逐条检查是否使用 SELECT *如果使用则提示改为显式字段。 3. 检查多表连接是否缺少表别名。 4. 检查 WHERE 条件中字段是否被函数包裹例如 WHERE DATE(created_at) 2025-01-01。 5. 如用户提供执行计划基于全表扫描、索引失效等特征判断风险。 6. 输出格式 - 问题级别高 / 中 / 低 - 问题位置 - 违反的规范 - 修改建议5.3 与 MCP 工具配合SKILL.md 只定义了行为规则真正执行时还需要工具支撑。比如结合 database connector 提供的run_explain工具模型可以在审查 SQL 时主动请求执行计划。连接器工具描述示例mcp.tool() def run_explain(sql: str) - dict: 对指定 SQL 执行 EXPLAIN 并返回执行计划。 # 实际项目中在这里执行数据库 EXPLAIN return {table: orders, type: ALL, rows: 120000}这样模型拿到type: ALL和rows: 120000时就能判断出存在全表扫描风险进而给出更有依据的建议。skill 定义流程connector 提供数据两者互补。5.4 效果验证验证 skill 是否有效需要准备一组测试输入。输入期望输出粘贴包含SELECT *的 SQL提示显式列出字段级别中多表连接但无别名提示添加别名级别中WHERE 中套函数且数据量大提示函数导致索引失效级别高规范 SQL按格式输出无问题建议把这类测试输入放到 skill 的 examples 目录下作为回归用例。以后修改 skill 时可以快速验证行为有没有被破坏。6. 常见报错排查链路6.1 ChatGPT 提示 “unable to locate the codex cli binary”现象启动 ChatGPT 或 Codex 集成环境时界面直接报错提示找不到 codex CLI 二进制文件并要求设置 codex 相关路径。这个报错本质上不是 MCP 配置问题而是宿主环境缺少可执行程序或者可执行程序所在目录不在 PATH 中。排查顺序确认 Codex CLI 是否已安装which codex或where codex。如果为空先安装 Codex CLI安装完成后再确认。如果已安装但仍找不到检查安装目录是否在 PATH。修改 PATH 后重启 ChatGPT 客户端。如果客户端仍有缓存重启进程或清理配置缓存后再试。防止这个问题再出现可以在安装依赖后先手动执行一次 codex 命令确认能正常启动再打开客户端。6.2 config.toml 无法加载对话无法继续现象ChatGPT 提示无法加载 config.toml对话串无法继续并且要求修复文件。常见原因包括三种TOML 语法错误、模型名称不存在、MCP server 配置指向了无效路径。排查配置文件的 TOML 语法可以借助 Python 内置库import tomllib with open(config.toml, rb) as f: data tomllib.load(f) print(data)如果这段代码抛折行错误或类型错误说明配置文件本身有问题。常见的 TOML 语法坑包括字符串没有加引号、键重复、缩进与数组混用。如果语法没有问题再检查配置文件里引用的模型名、MCP server 命令和路径是否真实存在。这类报错经常出现在复制他人配置后没有改成本机路径的场景。6.3 Dify 添加本地 MCP server 不生效现象在 Dify 中配置了 MCP 类型工具但工具列表里始终没有出现。先确认连接类型是否匹配。Dify 中接入本地 MCP server 时如果本机服务是 stdio 模式界面配置却选择了 HTTP 或 SSE就会出现无法连接的问题。需要先在 Dify 配置中选定与 server 实际传输模式一致的连接方式再确认端口可以被 Dify 服务访问。检查顺序使用 MCP Inspector 先本地验证 server 是否正常。确认 Dify 中填写的 URL 或命令参数正确。查看 Dify 服务日志和 MCP server 日志确认请求是否到达。如使用 HTTP/SSE确认端口是否对外可达、是否有防火墙拦截。6.4 排查清单问题现象常见原因检查方式处理建议提示缺少 codex CLICodex 未安装或不在 PATHwhich codex安装 Codex 并配置 PATH重启客户端config.toml 无法加载TOML 语法错误或模型名无效Python tomllib 解析修复语法核对模型名server 启动但工具不显示capability 声明缺失或客户端未刷新MCP Inspector 查看列表补充声明重启客户端调用工具报解析失败stdout 被 print 污染检查日志和 stderr改用 logging输出到文件Dify 中工具不可用传输模式不匹配或端口不可达查看 Dify 日志统一传输模式确认端口开放7. 生产环境落地建议与最佳实践7.1 学习环境与生产环境的差异学习阶段用 stdio 和本机配置足够但进入生产环境后很多基础配置方式不再合适。维度学习环境生产环境传输方式stdio简单直接HTTP 或 SSE便于独立部署和监控鉴权本机文件无额外保护OAuth、服务间认证、密钥管理配置本地 config 文件配置中心、环境变量、CI/CD 注入日志终端或文件结构化日志、集中采集可观测性手动验证指标、追踪、告警版本管理单文件修改connector、skill 分别版本化生产环境里不要把“本地能跑”当作上线标准。至少要补充日志监控、权限控制、异常处理和回滚方案。7.2 安全、鉴权和权限最小化MCP server 的本质是给 AI 模型开放外部系统操作入口权限设计必须比人工 API 调用更严格。首先是认证。不要在配置文件和代码里硬编码 Token使用环境变量或密钥管理系统。服务端要有身份校验避免谁能访问 MCP 端口谁就能调用工具。其次是权限。一个只读工具千万不要绑定通用数据库账号。每个工具应该使用最小权限的访问身份例如只读账号、指定数据库、限制查询超时。对危险操作要增加二次确认机制比如“删除数据”类工具要求客户端显式传confirm: true。最后是审计。记录谁在什么时候调用了哪些工具、传入了什么参数。没有审计出问题后很难定位责任和根因。7.3 skill 版本管理与测试skill 看起来只是 Markdown但实际上它是需要版本化的行为资产。一个前端审查 skill 可能在某个版本要求先跑测试另一个版本删掉了这个要求必须有版本记录才能追踪行为变更。建议每个 skill 目录都包含一个包含 version 字段的元信息。一个 CHANGELOG 文件记录行为变化。一个 examples 目录保存典型输入和期望输出。一份依赖声明列出需要哪些 connector。修改 skill 后用 examples 目录里的测试输入跑一次确认输出没有偏离预期再决定是否发布。7.4 下一步扩展方向从 Lensa 这类项目出发可以沿着两条路径深入。一条是协议层方向。研究 MCP 的 resources、prompts、sampling 等高级能力理解 MCP 如何从“工具调用协议”升级成“完整上下文协议”。这会直接帮助你判断什么时候用 tools什么时候用 resources什么时候用 prompts。另一条是工程化方向。把 connector 做成独立服务使用 HTTP/SSE 传输接入内部网关把 skill 做成团队共享包由测试用例自动验证。当连接的系统和技能数量增长后这套工程化能力比单个功能实现更重要。对一个新入门的开发者来说最值得做的练习是先跑通本文的最小 MCP server再给一个自己刚写过的工具写一个 500 字左右描述然后接入客户端观察模型在什么场景下会调用它。这个实验做完你对 MCP 的调用链路和模型行为方式的理解会比看十篇文档更扎实。Lensa 这类项目为你提供了现成的参考坐标但真正让它有意义的是你能否在自己的项目里按同样的方式组织连接器和技能。