
我不知道你怎么样,但我经常会切换使用的 AI 模型(谁还记得突然发布的 Gemini?)和客户端(Cursor、Windsurf、又回到 Cursor——等等,又换了!)。
最让我抓狂的就是上下文的丢失。我总是得不断地向 AI 解释我遇到的问题背景,还得让它学会用“我自己的风格”来处理事情。
但如果这些上下文是可以“带着走”的呢?比如,你在 Claude Desktop 上问了一个问题,得到了答案,然后在 Cursor 中编码时还能把这段对话调用回来?
在这篇文章中,我们就要实现这个目标——只需几个简单步骤,就能一起构建出这个工具。最终效果如下所示:
这里有这个示例项目的完整代码,你可以直接克隆。我建议你边看边操作;本教程的目标是,让你最终可以打造出属于你自己的小梦想服务器。
为什么要在意 MCP?
你现在看到的内容,正如你可能已经从 48 像素的大标题和几乎荒谬的关键词优化中猜到的那样,是一个 Model Context Protocol(MCP)服务器。
如果你已经了解 MCP,并且迫不及待想开始搭建,请随意跳过本节,直接看下面的“快速开始”。否则,计时开始——这里有一份 3 分钟入门指南。
1. 为什么 MCP 会存在?
如果你想要真正的自主 AI agent,就需要工具让它们能够“看见”并“操作”它们所处的世界。不幸的是,直接把 AI 助手和工具连接起来很容易变得脆弱:无论是 AI 模型更新,还是工具的 API 改动,都会导致集成失效。
那么,我们该如何构建更稳健、可复用的 AI 能力呢?
一个方法是使用 Anthropic 提出的 Model Context Protocol(MCP)。它是一个标准化的通信层(基于 JSON-RPC),允许 AI 客户端(比如 Cursor)发现并使用 MCP 服务器提供的外部能力。
这些能力包括访问持久化数据(Resources)、执行各种现实世界操作(Tools),以及获取如何使用这些资源和工具的指令(Prompts)。
如果你想深入了解 MCP 的目标、架构和潜力,可以阅读我写的详解文章。
2. 为什么要用 MCP 服务器?
像 Cursor 和 Windsurf 这样的客户端已经配备了很棒的 AI agent,那我们为什么还需要 MCP 提供的工具呢?
简单来说:客户端开发者不可能什么都做。他们没空为每个新模型都去重新调教网络搜索功能,也不可能自己去写一个 Jira 集成。
MCP 让 GitHub、Notion 这样的服务提供商可以自己维护 AI 集成,这意味着交互质量更高,也避免了重复造轮子。
所以,当你选择使用 MCP 服务器时,你获得的最大好处就是未来适配能力和上下文可迁移性。你可以拥有一整个即插即用的工具生态系统,只要你使用支持 MCP 的聊天窗口,它们就都能用上。
3. 为什么要自己搭建 MCP 服务器?
即使你不是那种需要把自己的服务 API 接入 MCP 的开发者,掌握这方面的知识也有很多好处。
对我来说,我发现花时间搭建服务器之后,我不再觉得自己的工作只是把一大堆文本复制粘贴到不同的输入框里。我是在自动化上下文管理,这让 AI 模型对我来说更加有用和贴近个人需求。
此外,在这个 AI 世界不断变化的时代,这也像是在地上立个“桩”一样:我今天构建的工具,即使将来出现了新的模型、客户端或服务,也能继续使用。
但诗意到此为止——现在开始动手干活吧。
快速开始:Vibe 式编码?
说实话:如果你只想把 MCP 的文档扔给 AI agent,并告诉它你想实现哪些功能……那很可能是行得通的。这类代码本身就偏模板式,正好是 AI 擅长的领域。
使用 MCP Inspector 来边调边看,出错就扔回去让 AI 修。另外,看看我们整理的一些 Cursor 使用技巧,能让你更高效地与 AI 配合。
不过如果你想真正理解架构、构建可扩展的 AI 工具,那我们就开始正式学习吧。
快速开始(认真版):克隆、安装、构建
我们先通过三个步骤准备好代码基础,暂时不涉及 API 密钥和客户端配置。
1. 克隆仓库:把示例代码拉到本地。
2. 安装依赖:需要安装 MCP SDK 和一些其他库。
3. 构建代码:将 TypeScript 编译为可运行的 JavaScript。
完成后你会在 build/ 目录中看到编译好的代码。
如果你已经准备好了 OpenRouter 的 API 密钥,也可以直接跳到“与真实客户端一起运行服务器”部分,服务器已经可以跑起来了。
核心循环:运行你的第一个服务器
在介绍这个 CSS Tutor 示例项目的具体功能之前,我们先来搞清楚任何基于 TypeScript SDK 的 MCP 服务器的基本结构,并跑起一个最小版本的服务器。
核心结构(src/index.ts)
打开主文件 src/index.ts,你会看到这些关键部分:
-
导入模块:引入
McpServer(核心类)和StdioServerTransport(用于通信),它们都来自@modelcontextprotocol/sdk。 -
注册函数导入:从
src/目录下其他文件中导入registerPrompts、registerResources和registerTools。这些函数负责告诉服务器有哪些能力。 - 实例化服务器:创建服务器实例,设置服务器名和版本,并初始化功能占位字段。
-
调用注册:调用上面导入的
register*函数,把能力注入服务器。 - 主函数:一个 async 函数,负责设置通信方式并连接服务器。
-
执行入口:调用
main(),并加上基本的错误处理。
这个结构就是服务器的核心:初始化 → 注册能力 → 建立通信连接。
创建一个最小服务器(临时改动)
为了确保基础结构正常运行,并且暂时不用外部 API 或复杂逻辑,我们可以这样临时修改 src/index.ts:
- 注释掉原来的能力注册函数调用
- 在
main()函数前添加一个简单的 "hello" 工具 - 重新构建代码
这样你就得到了一个可运行的 MCP 服务器,它目前只提供一个基础功能(比如“讲述帝国反击战的剧透”),但这可以确认通信结构已搭好。
用 MCP Inspector 调试
现在我们有了一个最小运行版本的服务器,怎么验证它是否正确说“MCP语”?答案是使用 Anthropic 的 MCP Inspector。
这个命令行工具可以作为一个基本的 MCP 客户端,它会像 Claude Desktop 或 Cursor 那样通过标准输入/输出启动你的服务器,并展示双方交互的 JSON-RPC 消息。
启动 MCP Inspector
在你的项目根目录下运行:
npx @modelcontextprotocol/inspector node ./build/index.js
-
npx ...inspector:下载并运行 Inspector 工具 -
node:启动你的服务器 -
./build/index.js:你编译好的服务器入口文件路径
你会看到什么
Inspector 启动后,会连接到服务器并开始交互。你可以访问本地页面与其交互:
- 连接确认:会看到初始化信息,表明连接成功。
-
列出工具:你可以用 Inspector 界面查看服务器暴露的工具,应该只看到我们加的
hello_world。 - 列出资源/提示:由于我们注释掉了这些注册项,资源和提示页应该是灰色的,不能点击。
-
调用工具:通过界面调用
hello_world,会看到服务器返回我们自定义的信息。
在开发期间,MCP Inspector 是你最好的朋友。每次添加或修改功能后,都用它验证注册是否正确、响应是否符合预期。无需引入完整的 AI 客户端即可测试。
就像《传送门》游戏里的第一人称视角主角手里永远带着 Companion Cube,一人一 Inspector,走哪带哪
构建真实功能
现在我们已经有了基础服务器,也知道如何用 Inspector 调试,接下来就是:
- 拿点零食
- 逐步添加实际的 CSS Tutor 功能
过程中你可以自由调整能力实现方式——无论你现在是什么水平的程序员,都欢迎参与!
第一步:「获取更新」工具(get_latest_updates)
首先,我们来激活并理解这个用于抓取外部信息的工具。
激活工具注册
打开 src/index.ts,删除我们之前添加的 hello_world 测试工具定义,并取消注释 registerTools(); 这一行。这行代码会调用 src/tools/index.ts 中的函数,注册所有工具。
export const server = new McpServer({
name: "css-tutor",
version: "0.0.1",
capabilities: {
prompts: {},
resources: {},
tools: {}
}
});
// registerPrompts();
// registerResources();
registerTools();
// 删除 dummy tool
async function main() // 剩下的代码...
理解工具代码
打开 src/tools/index.ts,找到 registerGetLatestUpdatesTool 函数。这就是定义并注册 get_latest_updates 工具的地方。
在这个文件中,你会看到以下几个关键部分:
-
配置和安全检查:它使用
dotenv加载环境变量,特别是查找OPENROUTER_API_KEY。如果缺少密钥,它会记录警告并跳过注册,防止服务器暴露一个无法使用的工具。 -
工具注册:使用
server.tool()注册get_latest_updates工具,指定名称、AI 客户端可见的描述,以及输入结构(这里是{},因为它不需要参数)。 - 核心逻辑(处理器):主要逻辑写在异步的处理函数里,它会在工具被调用时执行。
-
激活:文件底部的
registerTools函数会确保registerGetLatestUpdatesTool()被调用。
构建
编译变更:
npm run build
配置 API Key 进行测试
为了在 MCP Inspector 中测试这个工具,需要提供 API 密钥。可以像这样前缀命令:
# Linux/macOS 示例
OPENROUTER_API_KEY="sk-or-..." npx @modelcontextprotocol/inspector node ./build/index.js
(Windows 示例见项目的 README.md)
调试
运行 MCP Inspector,使用工具列表功能,你应该能看到 get_latest_updates 已注册。尝试调用它,应该会返回最近的 CSS 新闻!(前提是你在 OpenRouter 上还有大约 $0.04 的额度)

第二步:记忆资源及相关工具(css_knowledge_memory, read_from_memory, write_to_memory)
接下来,我们来激活服务器跨会话记忆功能:css_knowledge_memory 资源及相关工具。
激活资源注册
回到 src/index.ts,取消注释 registerResources();。
理解资源代码
打开 src/resources/index.ts,找到 registerCssKnowledgeMemoryResource 函数。
-
注册:使用
server.resource()定义资源,设置名称、唯一 URI(如memory://...)、读写权限、以及处理函数。 -
核心逻辑(处理函数和辅助函数):处理函数在客户端读取当前状态时被调用,调用了辅助函数
readMemory和writeMemory。这些函数负责读写本地的data/memory.json文件,它就是我们的持久存储。 -
激活:底部的
registerResources函数确保资源被注册。
理解内存工具代码
接下来,打开 src/tools/index.ts,查看 registerReadFromMemoryTool 和 registerWriteToMemoryTool。
-
注册:使用
server.tool()注册工具。read_from_memory没有输入结构,而write_to_memory使用zod定义了一个输入 schema:{ concept: z.string(), known: z.boolean() }。 -
核心逻辑:
read_from_memory调用readMemory()读取当前状态;write_to_memory接收输入后,读取现有状态,更新,再写入data/memory.json。 -
激活:底部的
registerTools函数会确保这些注册函数被调用。
构建
npm run build
调试
- 打开 MCP Inspector,在 Resources 标签中应看到
css_knowledge_memory; - 在 Tools 标签中应看到
get_latest_updates,还有新增的read_from_memory和write_to_memory; - 验证有状态:先调用
read_from_memory,然后用数据如{ "concept": "Grid", "known": true }调用write_to_memory,再读取一次,确认数据更新;你也可以直接查看data/memory.json。
第三步:提示(css-tutor-guidance)
最后一步!我们要告诉 AI 如何使用我们提供的工具和资源。
激活提示注册
回到 src/index.ts,取消注释最后一行:registerPrompts();。
理解提示代码
打开 src/prompts/index.ts。
-
注册:使用
server.prompt()注册提示,设置名称、描述。输入结构是空的{},因为不要求客户端传参数。(当然我们也可以传动态数据,会更灵活。) -
核心逻辑(处理器和内容):处理函数很简单,返回
cssTutorPromptText的内容,它定义了 AI 应该如何作为 CSS 教学助手的行为说明。 -
激活:底部的
registerPrompts函数确保提示被注册。
构建
编译变更:
npm run build
调试
运行 MCP Inspector。
在 Prompts 标签页中,你现在应该能看到 css-tutor-guidance 已注册。
尝试在 Inspector 中调用该 Prompt。它应该会显示出 cssTutorPromptText 中定义的完整指导内容。
是不是挺酷的?不过事情是这样的:
虽然我们的服务器现在已经通过 MCP 提供了这个 Prompt,但 大多数 AI 客户端目前还无法自动使用 MCP 提示。
比如 Claude 需要你手动选择,而 Cursor 甚至还无法访问 MCP Prompts。
所以现在的做法是:依靠像 Cursor 的 “规则(Rules)” 功能,为它提供如何使用 MCP Server 的提示说明。希望不久后,更多客户端会支持 MCP。
与真实客户端协作运行服务器
既然我们的服务器已经构建并通过 Inspector 调试完毕,现在是时候连接真实的 AI 客户端了。
Claude Desktop 设置
如果你使用 Claude 桌面版应用:
打开设置(注意:不是点击头像旁边的设置,而是顶部菜单栏的 “Settings”)。
进入
Developer→Edit Config。-
添加一个新的 MCP 服务器条目,配置如下:
- 使用你的 服务器绝对路径(不是相对路径)
- 填写你的 API Key
⚠️ 替换示例中的路径和密钥为你自己的实际值。
重启 Claude Desktop。
然后你就可以连接到
css-tutor服务器了。(如何点击连接按钮请参考顶部演示视频)
Cursor 设置
如果你使用 Cursor 编辑器:
- 打开
Cursor Settings > MCP > Add new global MCP server,添加新的服务器。 - 配置方法与 Claude 步骤完全相同。
- 创建一个 Prompt 规则:Cursor 不会自动使用服务器的 MCP 提示,因此你需要前往:
-
Cursor Settings > Rules,添加一个新的项目规则。 - 复制服务器里 prompt 的内容粘贴进去。
-
- 激活该规则:在此项目中聊天或代码生成时(例如按 Cmd+K),你需要通过
@规则名称来使用它。这样 Cursor 的代理就能正确使用我们配置的 MCP Server。
现在你就可以像演示视频里那样使用了——在一个客户端开始对话,切换到另一个客户端继续,数据还能保持同步!
下一步建议
首先,给自己点个赞 ✨。掌握新技能超棒!
然后,可以思考它能带来的更大可能。
这个 CSS 教学示例是为了教学而故意简化的,但你应该已经看出 MCP 有多强大。你可以:
- 更复杂的状态存储:将 JSON 文件换成 SQLite 或 PostgreSQL,支持多用户或更大规模的数据集。
- 更多工具:添加可搜索 MDN 的工具,从 Codepen 抓取 CSS 示例,或分析用户本地 CSS 文件。
- 动态提示:根据资源中存储的已知概念,动态生成教学提示,而不是固定文本。
- 错误处理与兜底机制:添加细粒度的错误处理逻辑,尤其是外部 API 请求失败时进行兜底操作。
-
多种传输协议:除了默认的
StdioServerTransport,你还可以探索 SSE(Server-Sent Events)等网络通信方式,实现流式传输。
MCP 是一个非常强大而灵活的协议框架,它让你可以构建出真正 定制化、有记忆力、面向未来的 AI 集成系统,适配任何支持该协议的客户端。