日照网站建设咨询报价4001688688人工服务
概览
本文将会介绍一些 mcp 的基本前置知识,并手摸手带大家完成一个 **具有 github 仓库搜索功能的 mcp 工具 **的小demo,借此和大家介绍一遍 mcp工具的开发流程!
什么是MCP
MCP(Model Context Protocol)是 Anthropic 提出并开源的一种协议,旨在让 基于 LLM 的 AI 系统具备使用工具和访问资源的能力。简单来说,MCP 为大型语言模型和外部资源之间提供了一个统一的“插头”或接口。以前每当需要让 AI 连接新的数据库、文件系统或服务时,开发者都必须为每种资源写专门的对接代码;有了 MCP,基于LLM 的 AI 系统可以通过标准协议“即插即用”地访问各种数据源,再也不必困在“信息孤岛”中。
暂时无法在飞书文档外展示此内容
工作原理
暂时无法在飞书文档外展示此内容
初始化连接:客户端向服务器发送连接请求,建立通信通道。
发送请求:客户端根据需求构建请求消息,并发送给服务器。
处理请求:服务器接收到请求后,解析请求内容,执行相应的操作(如查询数据库、读取文件等)。
返回结果:服务器将处理结果封装成响应消息,发送回客户端。
断开连接:任务完成后,客户端可以主动关闭连接或等待服务器超时关闭。
数据安全性
暂时无法在飞书文档外展示此内容
从上面这个结构图可以看出,MCP 服务器可以自己控制资源,不需要将 API 密钥等敏感信息提供给 LLM 提供商。这样也可以在使用ai工具的过程中很大程度上降低敏感数据泄露的风险。
什么是大语言模型中的 Function Calling
在介绍过mcp的定义中,大家肯定会想起我们的另外一个老朋友Function Calling,那么他和 mcp 是什么关系呢?
首先我们先回顾一下 Function Calling的定义
Function Calling 是一种让大型语言模型(LLM)调用外部函数或API的功能。它不是直接执行函数,而是通过返回一个结构化的输出(比如JSON)来告诉应用程序应该调用哪个函数以及使用什么参数。然后,应用程序会执行这个函数并把结果返回给模型。所以,LLM就像一个规划者,它决定是否、何时、如何使用某个函数,而实际的执行则由你的代码来完成。
举个 GPT-4 的API工作流程的例子
暂时无法在飞书文档外展示此内容
1、定义可用的函数:开发者在提示或 API 调用中向模型提供一个函数定义的列表(名称、描述和预期参数)
2、模型选择函数:用户提出问题,模型处理查询以及函数定义。如果它决定需要使用某个函数,则会以 JSON 格式返回一个 Function Calling(包括函数名和参数),而不是正常答案。例如,如果用户询问天气,模型可能会输出一个调用 get_current_weather 的函数,参数为位置。
3、执行函数:应用程序解析模型的 JSON 输出,识别要调用的函数,然后使用提供的参数在代码中调用相应的函数。它收集函数的结果(例如,从 API 获取的实际天气数据)。
4、将结果返回给模型:函数的输出被反馈回模型,通常作为对话中的一条特殊消息,或通过另一个调用模型的请求的结果。然后模型可以使用这些数据来形成其最终回答。
5、如果任务需要多个 Function Calling,它可能会在后续步骤中重复执行3、4两步。这个循环会持续,直到模型为用户产生最终答案。
MCP 与 Function Calling 的区别
类别 | MCP | Function Calling |
---|---|---|
性质 | 协议 | 功能 |
实现 | 基于标准协议 | 依赖于特定的模型 |
交互的灵活性 | 引入了分层上下文的概念(通过资源、提示等),使 AI 能够与涉及工具的更复杂的对话进行交互 | 提供了结构化但相对刚性的接口(模型的动作局限于事先定义的一组固定函数) |
适应性和工具发现 | AI Agent可以在运行时动态查询每个服务器可用的工具和资源 | 模型提前被告知哪些函数存在,不太适合一些用户需要创造性的组合步骤,或超出了预定义函数的场景。 |
可扩展性和生态系统 | 只需一次实现 MCP 服务器,而任何兼容的 AI 客户端都可以使用它们。 | 当有 n 个不同的工具时,你需要定义 n 个函数并保持更新。当切换 不同的 LLM 供应商的时候,可能需要重新定义这些函数。 |
具体可以参考文章 https://geekpm.com/archives/mcp-fuctioncalling
如何开发一个mcp工具
接下来本文将以一个 github 仓库搜索工具为例,从 0 - 1 手摸手教程❤️
项目初始化
npx @modelcontextprotocol/create-server github_mcp
? What is the name of your MCP server? github_mcp
? What is the description of your server? A Model Context Protocol server
? Would you like to install this server for Claude.app? No
✔ MCP server created successfully!Next steps:cd github_mcpnpm installnpm run build # or: npm run watchnpm link # optional, to make available globally
可以看到我们的项目结构已经初始化好了
功能编写
#!/usr/bin/env node
/**
* index.ts
**/
import * as repository from "./search_repositories.js";// 创建MCP服务器实例
const server = new Server({name: "github_mcp",version: "0.1.0",},{capabilities: {resources: {},tools: {},prompts: {},},}
);// 定义工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => {return {tools: [{name: "search_repositories",description: "Search for GitHub repositories",inputSchema: {type: "object",properties: {query: {type: "string",description: "搜索关键词",},page: {type: "number",optional: true,description: "页码 (默认: 1)",},size: {type: "number",optional: true,description: "每页的条数 (默认: 30, 最大: 100)",},},required: ["query"],},}],};
});//使用对应的工具并返回数据
server.setRequestHandler(CallToolRequestSchema, async request => {if (!request.params.arguments) {throw new Error("Arguments are required");}switch (request.params.name) {case "search_repositories": {const args = repository.SearchRepositoriesSchema.parse(request.params.arguments);const results = await repository.searchRepositories(args.query,args.page,args.size);return {content: [{ type: "text", text: JSON.stringify(results, null, 2) }],};}default:throw new Error(`Unknown tool: ${request.params.name}`);}
});// 使用stdio传输启动服务器。这允许服务器通过标准输入/输出流进行通信
async function runServer() {const transport = new StdioServerTransport();await server.connect(transport);console.error("GitHub MCP Server running on stdio");
}runServer().catch((error) => {console.error("Fatal error in main():", error);process.exit(1);
});
/**
* search_repositories.ts
**/export const SearchRepositoriesSchema = z.object({query: z.string().describe("搜索关键词"),page: z.number().optional().describe("页码 (默认: 1)"),size: z.number().optional().describe("每页的条数 (默认: 30, 最大: 100)"),
});
export async function searchRepositories(query: string,page: number = 1,size: number = 30
) {const url = new URL("https://api.github.com/search/repositories");url.searchParams.append("q", query);url.searchParams.append("page", page.toString());url.searchParams.append("size", size.toString());const response = await fetch(url.toString());const data = await response.json();return data;
}
调试
cd github_mcp
pnpm i
pnpm run build
pnpm run inspector
成功运行之后我们访问 http://localhost:5173 就会看到一个调试界面,按步骤点击就可以开始调试啦。
我们用 react 作为关键词搜索看看
工具链路成功走通了。
ps: 这里有一点地方要注意,@modelcontextprotocol/inspector 这个调试工具 默认的超时时间是 10s,如果超过10s会提示超时如下图
博主在 @ent-platform/inspector 中将默认超时时间改成了 80s,大家可以直接使用(有什么问题或者好玩的想法的话也可以联系博主,欢迎互相交流学习❤️!)使用姿势如下
只需要把 @modelcontextprotocol/inspector 替换为 @ent-platform/inspector 就好了。
接下来就是让我们 ai 来使用工具了!
配置mcp
如何配置的帖子已经有很多了,本文以 cline 为例。
{"mcpServers": {"github_mcp": {"command": "node","args": [ "/Users/bytedance/code/github_mcp/build/index.js"], // 本地产物路径"disabled": false,"autoApprove": []}}
}
到这,cline上的mcp配置就ok了,想了解其他ai工具中如何配置mcp的可以参考文章 https://bytetech.info/articles/7470141463196598298#Scgddm5gjoYt1VxzAV1cLHhAnPf
使用
好了让我们来看看我们工具的效果
ai通过我们的自然语言描述自己找到了对应的工具并使用了它!
但是这个返回结构很不直观,我们让他在这里面挑选3条点赞数最高的。
可以看到,ai已经帮我们总结了一下内容!
到这,我们已经成功走完了一个 mcp 工具的开发链路!快亲自动手试试吧🎉,看到这方便的话给博主留个赞吧嘻嘻
如果有对这块感兴趣,或者有什么好玩的想法的也可以联系博主 @林昊鹏 ,一起交流学习!happy coding🎉