把一段崩溃日志直接扔给大模型,它往往会回你一句“这可能是网络问题”——这个场景,很多开发者已经熟悉到麻木。原因倒也不难理解:大模型不是一个精确的检索系统,它对具体异常的理解来自训练数据里的概率分布,而不是你当前项目的真实上下文。它更擅长告诉你“大概可以往哪个方向排查”,而不是告诉你“这个错误码在你的技术栈里到底意味着什么”。
所以当看到“An MCP server that knows what that error message means”这个项目时,我认为值得关注的不是“又一个查错误码的小工具”,而是它背后代表的一种范式转变:把错误排查知识变成 AI 可以直接调用的工具能力,而不是靠提示词硬套。
这篇文章我会拆开讲清楚一件事:为什么“错误信息理解”特别适合做成 MCP Server,以及如果你也打算实现一个,从协议理解、环境准备、核心代码、规则库设计、客户端接入到效果验证的完整路径是什么。读完你不仅能看懂这类项目大概是怎么做的,还能照着思路搭出一个属于你自己团队、甚至属于你自己的错误知识库版本。
1. 这篇文章真正要解决的问题
先说说大多数开发者每天都在经历的事情。
你在终端里启动服务,报错信息长这样:
Error: EACCES: permission denied, open '/var/log/your-app/app.log'你大概率知道这是权限问题,但如果是更晦涩的:
ORA-28547: connection to server failed, probable Oracle Net admin error或者:
failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字尝试这时候你通常会打开搜索引擎,或者把错误信息粘贴给 AI。但实际体验往往是:
- 错误信息本身就不是给人看的。很多报错来自底层框架,它只告诉你有异常,不告诉你业务场景。
- 搜索引擎命中率不稳定。全局唯一、冷门的错误码,搜索出来的可能只有一条 Stack Overflow 帖子,而且不一定适配你的版本。
- 大模型只会“一本正经地胡说八道”。你贴一段 token exchange failed 的日志,它可能给你分析十分钟网络代理配置,最后发现错误原因是目标环境不支持该地区访问。
这第三个痛点,恰恰是 MCP Server 最能改变的地方。
直接问大模型,本质上是让模型“凭空推理”。而通过 MCP Server 查询,本质上是让模型“先查表,再回答”。推理能力负责把查询结果组织成自然语言,检索能力负责给出准确答案。
所以这篇文章的核心判断是:错误信息解读这种任务,真正可靠的做法不是让 AI 猜,而是给 AI 配一个可查询、可更新、可积累的错误知识库。MCP Server 就是这个知识库和 AI 客户端之间的“标准插头”。
2. MCP 协议基础:模型上下文协议到底在做什么
MCP 的全称是 Model Context Protocol,模型上下文协议。它由 Anthropic 在 2024 年底开源,目的是解决一个很实际的问题:大模型应用不能只靠训练数据,它需要访问外部数据源和工具,但每个客户端都自己开发一套工具接入方式,成本和混乱程度都太高。
把 MCP 类比成 USB 接口更容易理解。如果没有 USB,你每买一个外设都要给电脑焊一根专用线缆。MCP 做的事情,就是统一了 AI 客户端和外部工具之间的接口标准。
一个完整的 MCP 架构包含三层:
MCP 客户端(宿主程序) | | MCP 协议(stdio / HTTP+SSE) | MCP Server | | API / 文件 / 数据库 / 内部服务 | 错误知识库、日志系统、监控平台、代码仓库...所谓“宿主程序”(Host),就是 Claude Desktop、Cursor、VS Code、Dify 这类支持 MCP 的应用。它负责接收用户的自然语言,决定是否调用某个工具,并把工具返回的结果组织成最终回答。
MCP Server 可以暴露三类能力:
| 能力类型 | 作用 | 举例 |
|---|---|---|
| Tool(工具) | 让模型执行外部操作 | 查询错误码、查询数据库、调用搜索引擎 |
| Resource(资源) | 让模型读取结构化数据 | 读取配置文件、读取项目文档 |
| Prompt(提示词) | 给模型提供可复用的模板 | 代码评审模板、日志分析模板 |
对于一个“懂得错误信息含义”的 MCP Server,核心能力就是 Tool:提供一个lookup_error工具,接受错误码或错误关键词,返回该错误的技术栈归属、可能原因和解决方案。
这里还有一个容易被忽略的设计点:MCP 支持多种传输方式。本地开发常用 stdio,也就是通过标准输入输出通信;远程服务可以用 HTTP+SSE 或 Streamable HTTP。这意味着你可以把错误知识库部署成公司内部服务,每个开发者的 AI 客户端都可以连上来,而不是每个人各自维护一份错误文档。
3. 整体架构设计:从“让 AI 猜”到“让 AI 查”
理解了 MCP 协议之后,我们再来看这类项目的整体架构。
一个“错误信息查询 MCP Server”,从职责上可以拆成三层:
第一层:MCP 协议层。这一层负责接收 AI 客户端的请求,校验参数,返回结构化结果。开发者不需要每次都自己实现协议细节,直接使用官方 SDK 即可。
第二层:错误解析层。这一层是核心逻辑所在。它接收一段错误消息,提取错误码或关键词,再结合技术栈信息,匹配知识库中的规则。
第三层:知识库层。这一层是数据来源。起步阶段可以是一个 JSON 文件,以后可以升级成 SQLite、MySQL,甚至是搜索引擎前的向量数据库。
这三层之间的关系可以用下面这段文本流程描述:
用户粘贴错误日志 ↓ AI 客户端识别出“这是一个错误查询请求” ↓ 调用 lookup_error 工具,传入错误码/关键词 ↓ MCP Server 解析参数,匹配本地知识库 ↓ 返回结构化结果:错误含义、原因分析、解决步骤 ↓ AI 结合用户的上下文,生成可读的回答这里有一个关键点:AI 客户端负责判断“什么时候该查”,MCP Server 负责给出“准确的答案”。用户不需要记住错误知识库里有哪几条规则,只需要把报错贴给 AI,AI 会根据工具描述自动决定是否调用。
4. 环境准备与项目初始化
下面进入实操环节。我们以 TypeScript 为例,从零搭一个最简可用的 MCP Server。如果你更熟悉 Python,也可以参考官方 Python SDK,核心思路完全一致。
首先确认本机环境:
- Node.js 16 或更高版本,建议使用 LTS 版本,具体版本以你实际安装为准。
- npm 或 pnpm、yarn 任一包管理器。
- 一个趁手的编辑器,VS Code 即可。
项目目录和依赖按下面步骤创建。
mkdir error-helper-mcp cd error-helper-mcp npm init -y npm install @modelcontextprotocol/sdk zod npm install -D typescript @types/node tsx这里解释一下依赖:
@modelcontextprotocol/sdk是 MCP 官方 TypeScript SDK。zod用于声明工具的输入参数 schema,MCP 客户端会根据这个 schema 决定如何传参数。typescript和tsx用于编译和本地调试运行。
然后初始化 TypeScript 配置:
npx tsc --init最终的目录结构建议如下:
error-helper-mcp/ ├── src/ │ ├── index.ts # MCP Server 入口 │ ├── errors.ts # 错误查询逻辑 │ └── knowledge-base.ts # 错误知识库数据 ├── package.json └── tsconfig.json这样设计的好处是:入口文件只负责注册工具,查询逻辑放独立模块,知识库数据单独维护。后续如果要从文件切换成数据库,只需要改 knowledge-base 这一层,MCP 工具注册部分完全不用动。
5. 核心代码实现:最简可用的错误查询 MCP Server
这一节我们写三个文件:知识库数据、查询逻辑、Server 入口。
5.1 定义错误知识库
先定义一个知识库数据结构。为了演示方便,这里直接放在 TypeScript 文件里,实际项目可以抽成 JSON 或数据库。
// 文件路径:src/knowledge-base.ts export interface ErrorEntry { /** 错误码,尽量保持全局唯一 */ code: string; /** 技术栈标签,例如 nodejs、mysql、oracle */ stack: string[]; /** 错误关键词,用于模糊匹配 */ keywords: string[]; /** 错误含义 */ description: string; /** 可能原因列表 */ causes: string[]; /** 解决步骤 */ solutions: string[]; /** 参考文档链接 */ references?: string[]; } export const errorKnowledgeBase: ErrorEntry[] = [ { code: "EACCES", stack: ["nodejs", "linux"], keywords: ["permission denied", "access denied"], description: "当前用户没有足够的权限来访问指定文件或目录。", causes: [ "运行 Node.js 进程的用户对文件没有读写权限", "文件或目录所有者与当前用户不一致", ], solutions: [ "检查文件权限,使用 ls -l 查看所有者", "使用 sudo 运行命令,但要确认命令来源可信", "为应用单独创建服务用户,并给该用户授权", ], references: ["https://nodejs.org/docs/"], }, { code: "ORA-28547", stack: ["oracle", "database"], keywords: ["oracle net admin error", "connection to server failed"], description: "Oracle 客户端与服务器之间的网络连接失败,通常是 Oracle Net 组件配置或版本不匹配导致。", causes: [ "sqlnet.ora 或 tnsnames.ora 配置错误", "Oracle 客户端版本与数据库服务器版本不兼容", ], solutions: [ "检查 sqlnet.ora 中的连接参数", "确认客户端和服务器端 Oracle 版本兼容性", "查看监听服务是否启动", ], }, { code: "TOKEN_EXCHANGE_FAILED", stack: ["auth", "api"], keywords: ["token exchange failed", "token endpoint"], description: "令牌交换失败,通常是 OAuth/OIDC 流程中授权码或客户端凭证无效。", causes: [ "授权码已过期或已被使用", "客户端密钥配置错误", "回调地址与注册的不一致", "服务端对请求来源区域有限制", ], solutions: [ "重新发起授权流程,获取新的授权码", "检查客户端配置中的 client_secret", "确认回调地址精确匹配", "查看服务端是否有区域限制策略", ], }, ];从知识库结构可以看出,每一种错误都包含两层信息:一是机器可匹配的字段(错误码、关键词、技术栈),二是 AI 可理解的字段(含义、原因、解决方案)。MCP Server 的查询逻辑,本质上就是机器匹配和语义理解的结合。
5.2 实现查询逻辑
接下来写查询函数。这里采用一个比较务实的策略:先按错误码精确匹配,再按关键词模糊匹配,最后用技术栈过滤。
// 文件路径:src/errors.ts import { errorKnowledgeBase, ErrorEntry } from "./knowledge-base.js"; export interface LookupParams { /** 错误码或错误消息片段 */ query: string; /** 可选的技术栈标签 */ stack?: string; } export function lookupError(params: LookupParams): ErrorEntry[] { const query = params.query.trim().toLowerCase(); const stack = params.stack?.trim().toLowerCase(); if (!query) { return []; } // 第一次匹配:错误码精确匹配 const exactMatches = errorKnowledgeBase.filter((entry) => entry.code.toLowerCase() === query ); // 第二次匹配:错误码包含匹配 const codeMatches = exactMatches.length === 0 ? errorKnowledgeBase.filter((entry) => entry.code.toLowerCase().includes(query) ) : []; // 第三次匹配:关键词匹配 const keywordMatches = exactMatches.length === 0 && codeMatches.length === 0 ? errorKnowledgeBase.filter((entry) => entry.keywords.some((keyword) => query.includes(keyword.toLowerCase())) ) : []; // 合并结果,并去重 const combined = [...exactMatches, ...codeMatches, ...keywordMatches]; const deduplicated = Array.from( new Map(combined.map((item) => [item.code, item])).values() ); // 如果指定了技术栈,进一步过滤并优先返回 if (stack) { const stackFiltered = deduplicated.filter((entry) => entry.stack.some((s) => s.toLowerCase().includes(stack)) ); if (stackFiltered.length > 0) { return stackFiltered; } } return deduplicated; }这段逻辑并不复杂,但有一个设计值得注意:“匹配失败”本身就是重要信息。当知识库里没有命中任何规则时,MCP Server 返回空数组,AI 客户端就能明确告诉用户“这个错误没有收录,建议人工排查后再沉淀进知识库”。而不是让大模型硬编一个看起来合理的答案。
5.3 注册 MCP 工具
最后是 MCP Server 入口。这里使用官方 SDK 中比较通用的 API,因为 SDK 版本仍在迭代,具体方法名以你安装的版本为准,但整体结构是不变的。
// 文件路径:src/index.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { lookupError } from "./errors.js"; const server = new McpServer({ name: "error-helper", version: "0.1.0", }); server.tool( "lookup_error", "根据错误码或错误消息片段查询错误含义、原因和解决方案", { query: z.string().describe("错误码或错误消息,例如 EACCES 或 ORA-28547"), stack: z .string() .optional() .describe("可选的过滤条件,例如 nodejs、oracle、mysql"), }, async (params) => { const results = lookupError({ query: params.query, stack: params.stack, }); if (results.length === 0) { return { content: [ { type: "text", text: "知识库中未找到该错误的直接匹配记录。建议先通过日志上下文人工排查,确认后将规则补充到知识库。", }, ], }; } const formatted = results.map((entry) => { return [ `错误码:${entry.code}`, `技术栈:${entry.stack.join(", ")}`, `含义:${entry.description}`, `可能原因:`, ...entry.causes.map((cause) => ` - ${cause}`), `解决方案:`, ...entry.solutions.map((solution) => ` - ${solution}`), ].join("\n"); }); return { content: [ { type: "text", text: `查到 ${formatted.length} 条相关记录:\n\n${formatted.join("\n\n")}`, }, ], }; } ); const transport = new StdioServerTransport(); await server.connect(transport);代码看起来不长,但它完成了一个完整的闭环:接收 AI 客户端的工具调用请求、解析参数、查询知识库、返回结构化 Markdown 文本。AI 拿到这段文本后,会结合用户原来的报错上下文,生成一段自然语言的排查建议。
5.4 编译与启动
TypeScript 项目可以先编译再运行,也可以直接用 tsx 调试。
# 方式一:编译后运行 npx tsc node dist/index.js # 方式二:tsx 直接运行(开发调试更省事) npx tsx src/index.ts因为使用了 stdio 传输,这个程序不能像普通服务那样在终端里直接看到输出。它等待的是标准输入上的 JSON-RPC 请求,需要借助 MCP Inspector 或客户端来测试。
6. 规则库设计:决定这个工具价值的不是代码,而是数据
代码写完后,这个项目的价值重心就从“怎么写”转移到了“存了什么”。一个错误知识库,如果只有三条规则,价值约等于零;如果有三百条经过验证的规则,就是一个团队级的排查资产。
规则库设计有四个要点。
第一,筛选高频错误。不要一开始就追求全面覆盖。观察团队一个月内的报错记录,把出现频率最高的前 20 个错误收录进来,比盲目收录 200 个冷门错误更有价值。
第二,字段要同时满足“机器匹配”和“AI 语义”。机器匹配靠错误码和关键词,AI 语义靠 description、causes、solutions。只写关键词没有含义解释,AI 拿到结果也组织不出高质量回答。
第三,解决方案要“可执行、可验证”。好的解决方案不是“检查网络配置”这种笼统建议,而是给出具体命令、具体配置项,以及如何验证是否生效。例如:
解决方案: 1. 执行 adb reverse tcp:8080 tcp:8080,将设备端口映射到本地 2. 重新启动应用并观察日志 3. 如果仍然失败,使用 netstat -ano 检查端口占用第四,为“未命中”设计回退策略。当 AI 查询不到结果时,它应该明确告诉用户“知识库未收录”,而不是硬编答案。这样错误知识库才能持续收敛——每个未命中都是下一次补充规则的机会。
7. 接入 MCP 客户端:Claude Desktop 与编辑器场景
MCP Server 写好后,需要接入支持 MCP 的客户端。这里以 Claude Desktop 为例,其他客户端的配置位置可能不同,但配置结构是类似的。
找到客户端的配置文件。Claude Desktop 的配置路径通常是:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
在配置文件中加入:
{ "mcpServers": { "error-helper": { "command": "npx", "args": ["tsx", "/absolute/path/to/error-helper-mcp/src/index.ts"] } } }注意command和args需要根据你的环境调整。如果 node_modules 安装在项目本地,也可以指定完整的 node 路径和脚本路径。
重启客户端后,你可以输入一段包含错误信息的描述,观察客户端是否自动调用lookup_error工具。正常情况下,AI 客户端会在回答中提示“已通过 error-helper 查询错误信息”,并给出 Tool 返回的结构化内容。
对于 Cursor、VS Code 等编辑器,通常是在 MCP 配置界面中添加同样的 JSON 配置。不同的客户端对 stdio 启动方式的参数要求可能略有差异,如果不确定,可以查看客户端文档中的 MCP 配置说明。
8. 效果验证:用 MCP Inspector 测试工具调用
没有接入客户端之前,MCP Inspector 是调试 MCP Server 最方便的工具。它相当于一个可视化调试面板,可以直接看到 Server 注册了哪些工具、工具接收了什么参数、返回了什么结果。
在项目根目录运行:
npx @modelcontextprotocol/inspector npx tsx src/index.ts如果当前环境对 npx 嵌套解析有问题,可以先安装 tsx 到全局,再运行:
npm install -g tsx npx @modelcontextprotocol/inspector tsx src/index.ts启动后,Inspector 会提供一个本地网页地址,用浏览器打开即可看到 MCP Server 的工具列表。选择lookup_error工具,填入参数:
{ "query": "ORA-28547", "stack": "oracle" }点击执行,预期返回结果中包含错误码、技术栈、含义、可能原因和解决方案。
同样可以测试未命中场景:
{ "query": "UNKNOWN_ERROR_XYZ" }预期返回文本是“知识库中未找到该错误的直接匹配记录”。
如何判断成功?主要看三点:
- MCP Inspector 能正常列出
lookup_error工具。 - 输入参数带 schema 校验,缺失必填参数时客户端会提示。
- 返回结果是结构化的
content数组,而不是启动时的报错堆栈。
如果 MCP Server 本身有逻辑错误,Inspector 会直接显示服务端的异常堆栈,这是第一时间的定位线索。
9. 常见问题与排查思路
在实际搭建过程中,最容易遇到的几个问题如下:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 客户端启动后找不到 MCP Server | 配置路径错误或命令启动失败 | 查看客户端日志,确认配置文件是否被加载 | 检查配置中的绝对路径,先手动在终端执行启动命令验证 |
| 工具调用返回超时 | stdio 输出被无关日志污染 | 查看启动命令是否有 console.log 输出 | 移除 MCP Server 中的调试日志,stdout 只能用于协议通信 |
| TypeScript 类型报错 | SDK 版本 API 差异 | 查看 node_modules 中 SDK 的实际导出 | 以当前 SDK 版本为准调整 import 和工具注册方法 |
| 客户端能连接但工具不调用 | 工具描述不够清晰,AI 不知道何时调用 | 在聊天中直接问客户端“你能查错误码吗” | 优化工具描述,明确说明适用场景和参数含义 |
| 查询结果不完整 | 知识库命中率低 | 检查匹配逻辑是否覆盖错误码前缀 | 增加包含匹配和关键词匹配策略,补充规则 |
其中最容易踩坑的是第二个:stdio 传输模式下,MCP Server 的 stdout 是协议通道。任何多余的 console.log 都会污染协议数据,导致客户端解析失败。调试时要用 console.error 输出诊断信息,或者直接使用文件日志。
10. 最佳实践与工程建议
从“一个能跑的 Demo”到“一个能用的团队工具”,中间还差几个工程决策。
错误知识库和代码一起版本管理。知识库本身就是最重要的资产,和代码一起进 Git 仓库,可以保证每次修改都有历史记录,也方便团队 review。
匹配失败要埋点。当用户查询一个知识库没有收录的错误时,记录下查询关键词和技术栈。这些数据是知识库扩充的第一手资料。
不要让 AI 直接执行解决方案中的命令。即使 MCP Server 返回了带有命令的解决步骤,AI 客户端能“显示”命令,也不代表它应该自动执行。尤其涉及改配置、改文件权限、操作数据库时,必须保留人工确认环节。
从“单机版”演进到“服务版”。本地 JSON 知识库适合个人学习,团队场景建议把 MCP Server 部署成远程服务,通过 HTTP 暴露工具。这样知识库只需要在服务端维护一份,所有开发者的 AI 客户端共享同一个错误语义层。
定义清晰的数据来源和可靠度。每条错误规则的来源可以是官方文档、真实排障记录或社区高票答案。建议给每条记录增加一个来源标记,例如官方文档优先,社区答案标明参考链接,避免后续维护时无法判断信息可靠度。
11. 总结与后续方向
这个出现在 HN 上的 MCP Server 项目,本质上是在做一件事:把错误信息从无人维护的“报废字符串”变成 AI 可查询的结构化知识。它的价值不在于用上了多复杂的模型或算法,而在于选对了一个足够痛的场景,并采用了一个足够标准的接入方式。
如果你正在尝试类似方向,我的建议是:先不要急着设计复杂架构,用这篇文章里的最小代码跑通“用户贴报错 -> AI 调用工具 -> 返回结构化方案”的闭环,然后花时间积累知识库。前 50 条规则可能会有些枯燥,但到 200 条的时候,你会发现 AI 对你们团队报错的理解,已经远远超过了一个普通开发者的记忆范围。
下一步可以考虑的方向包括:知识库接入向量检索,支持碎片化错误日志的语义匹配;将 MCP Server 部署成公司内部 HTTP 服务,让所有开发者共享;把每次排障过程自动沉淀为新规则,形成持续演进的错误知识闭环。判断这类项目是否优秀,最终看的不是工具数量,而是你愿不愿意让它成为你日常工作流的一部分。