本文介绍如何使用
@modelcontextprotocol/sdk
构建一个 MCP 工具服务,并与 Cursor 编辑器中的 Claude 模型集成。通过 MCP,可以让 Claude 访问你自己的工具和数据,实现如 SQL 查询、文件读取等扩展功能------这些是原生 Cursor 无法完成的。
一、什么是 MCP(Model Context Protocol)?
MCP 是一种标准协议,允许大语言模型(LLM)在运行时调用外部工具。Claude、ChatGPT 等模型通过 MCP 能够访问你提供的功能,例如调用数据库、运行脚本、发出 HTTP 请求等。
MCP 的价值在于:
- 模型可以感知"外部世界"的工具能力
- 自动识别什么时候该调用工具,什么时候只用语言回答
- 工具调用是结构化的,标准 JSON 格式,容易集成
二、什么是 @modelcontextprotocol/sdk
?
这是 MCP 协议的官方 SDK,帮助我们快速启动一个 MCP 工具服务。
你只需要编写每个"工具"的定义(名称、功能、参数结构和执行逻辑),然后通过该 SDK 提供的 Server
和 StdioServerTransport
启动服务。
javascript
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
模型通过 stdio
通信通道与这个服务交互,在 Cursor 中这是一种默认的插件通讯方式。
此外还包括两个核心请求结构:
javascript
const {
ListToolsRequestSchema, // 模型请求你的工具列表
CallToolRequestSchema, // 模型调用你的某个工具
} = require('@modelcontextprotocol/sdk/types.js');
三、ListToolsRequestSchema 与 CallToolRequestSchema 的作用
ListToolsRequestSchema
当模型启动时,它会先向你的 MCP 工具服务发起请求,问一句: "你有哪些工具可以用?"
这时候你要返回所有工具的定义,包括:
- name:工具名称(唯一)
- description:功能描述,语言模型用它来理解用途
- inputSchema:JSON Schema 格式,描述参数结构
这个过程就像列出菜单:
json
{
"tools": [
{
"name": "execute_sql",
"description": "执行一段 SQL 查询,返回结果",
"inputSchema": {
"type": "object",
"properties": {
"sql": { "type": "string", "description": "SQL语句" }
},
"required": ["sql"]
}
}
]
}
CallToolRequestSchema
当模型决定调用某个工具时,它会发送一个结构化调用请求:
json
{
"type": "call_tool",
"params": {
"name": "execute_sql",
"arguments": {
"sql": "SELECT * FROM users"
}
}
}
你的 MCP 服务会根据 name
选择对应工具,执行 execute()
函数,并把结果(结构化文本)返回给模型。
四、Claude 是如何决定调用 MCP 工具的?
这一步是很多人最关心的:模型是怎么知道"现在应该调用工具"而不是自己瞎说?
实际上,Claude 会尝试自己回答问题,如果发现:
- 用户问的问题和已有知识不匹配
- 模型的回答不确定或含糊
- 用户请求的是模型没有权限的数据(如私有表格数据)
模型就会尝试去查工具列表,看有没有能"帮它"完成任务的工具。
举例说明:
问句 1:
users 表有哪些字段?
Claude 无法直接回答,因为它不知道你的数据库结构。此时它会匹配工具清单,发现你提供了 execute_sql
工具,于是调用它:
json
{
"name": "execute_sql",
"arguments": {
"sql": "SHOW COLUMNS FROM users"
}
}
返回:
dart
执行结果如下:
[
{ Field: 'id', Type: 'int', Null: 'NO', ... },
{ Field: 'name', Type: 'varchar', ... }
]
模型再将其转述给你:
users 表包含 id、name 等字段。
你看不出这是工具调用的,但实质上 Claude 已经通过 MCP 服务调用了你的数据库。
五、Cursor 能力扩展实战:3 个实际例子
1. 访问私有数据库(如你的用户表)
Claude 原本无法访问你的本地数据,现在你通过 MCP 提供一个 execute_sql
工具,它就可以根据自然语言问题自动转成 SQL 语句,并获取结果。
- 用户问:
这个月有多少注册用户?
- 模型内部调用:
SELECT COUNT(*) FROM users WHERE created_at >= '2024-07-01'
2. 自动创建文件内容(代码片段生成)
提供 create_file
工具:
css
{
"name": "create_file",
"description": "生成某个文件内容",
"inputSchema": {
"type": "object",
"properties": {
"filename": { "type": "string" },
"content": { "type": "string" }
},
"required": ["filename", "content"]
}
}
Claude 会根据你说的内容自动调用它来生成项目脚手架,比如:
- 用户问:创建一个包含
main.ts
的 hello world 项目 - Claude 自动构造文件内容并调用
create_file
3. 接入 REST API 或业务逻辑
你可以将已有的接口封装成工具:
json
{
"name": "get_weather",
"description": "获取某城市天气",
"inputSchema": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
然后:
- 用户问:北京今天会下雨吗?
- Claude 自动调用:
get_weather({ city: "北京" })
返回天气信息再转述给你。
六、使用建议
1. 工具描述越清晰,调用准确率越高
Claude 是靠匹配描述来判断用哪个工具的。比如:
- ❌ "run"
- ✅ "执行 SQL 查询语句"
2. 工具数量不要过多
否则 Claude 不知道选哪个。优先从单工具开始,逐步添加。
3. 参数结构要合理
模型必须能构造出合法 JSON 参数,否则无法调用。
4. 使用文本返回,不要复杂格式
MCP 结果必须是结构化 JSON:
css
{
"content": [
{ "type": "text", "text": "查询成功,共5条数据" }
]
}
七、总结
通过 MCP 协议,Claude 模型可以在 Cursor 编辑器中调用你自定义的工具服务:
过程 | 说明 |
---|---|
列出工具 | 使用 ListToolsRequestSchema 定义所有工具 |
调用工具 | Claude 构造 CallToolRequestSchema 请求执行 |
执行并返回 | 你的服务执行工具并返回结构化内容 |
Claude 整理回应 | Claude 将结构化结果转化为自然语言回复 |
借助这个机制,Cursor 可以:
- 访问你的本地数据
- 运行本地代码逻辑
- 操作文件系统
- 集成业务系统 API
让 AI 成为你真正的"本地开发助手"。
后续如果需要发布为插件、支持云部署或与其他编辑器集成,也可以基于这个原型继续拓展。
参考文章: juejin.cn/post/751424...