👉目录 1 什么是 MCP 2 MCP Server 开发 3 MCP Client 开发 4 MCP的工作原理 5 效果呈现 6 写在最后 01MCP(Model Context Protocol,模型上下文协议) 起源于 2024 年 11 月 25 日 Anthropic 发布的文章:Introducing the Model Context Protocol。 可以用“AI 扩展坞”来比喻 MCP 在 AI 领域的作用。就像现代扩展坞可以连接显示器、键盘、移动硬盘等多种外设,为笔记本电脑瞬间扩展功能一样,MCP Server 作为一个智能中枢平台,能够动态接入各类专业能力模块(如知识库、计算工具、领域模型等)。当 LLM 需要完成特定任务时,可以像'即插即用'般调用这些模块,实时获得精准的上下文支持,从而实现能力的弹性扩展。这种架构打破了传统 AI 模型的封闭性,让大语言模型像搭载了多功能扩展坞的超级工作站,随时都能获取最合适的专业工具。 ![]() 终结工具调用碎片化 不同模型在定义 Function Call(函数调用)时,采用的结构和参数格式各不相同,使得对多模型集成、统一管理和标准化接入变得复杂而繁琐。
![]() 对于开发者来说,针对不同模型去实现不同的工具调用方法,所谓的定制化开发不仅消耗大量时间和资源,而且维护也变得困难。 而 MCP 作为一种 AI 模型的标准化接入协议,能够显著简化模型之间的集成。 实现多功能应用与创新体验的突破 MCP 的潜力不仅限于连接现有工具,它还在推动客户端应用向“万能应用”演进,并创造全新的用户体验。 以代码编辑器 Cursor 为例,作为 MCP 客户端,用户可以通过集成不同的 MCP 服务器,将其转变为具备 Slack 消息收发、邮件发送(Resend MCP)、甚至图像生成(Replicate MCP)等多种功能的综合工作站。 更具创造力的是,在单一客户端中组合多个 MCP 服务器可以解锁复杂的新流程。例如,AI 代理可以一边生成前端界面代码,一边调用图像生成服务器为主页创作视觉元素。这种模式超越了传统应用的单一功能限制,为用户带来多样化的操作体验。 02MCP server 是 MCP 架构中的关键组件,目前提供 3 种主要类型的功能,
还有其他两种(samping 和 roots)但是目前还没被很好的支持。 ![]() 以开发一个企业微信机器人 mcp server 为例,用到的是社区sdk typescript-sdk 。(https://github.com/modelcontextprotocol/typescript-sdk) 可以参考官方 quickstart(https:///quickstart/server) 环境:nodejs > v16 (我用的是 v22.6) npm init -y
# Install dependencies npm install @modelcontextprotocol/sdk zod npm install -D @types/node typescript mkdir src touch src/index.ts
可以直接使用 sdk 封装好的 McpServer 函数。 创建 tools 工具定义 mcp 提供给 client 或者 llm 使用的工具,企业微信机器人主要就是 发送文本、发送 markdown、发送图片等等,这里我们举例一个发送文本的工具实现
// Helper function for sending WeChat messages export async function sendWeChatTextMessage(webhookKey: string, content: string, chatid: string = '@all_group', mentioned_list?: string[], mentioned_mobile_list?: string[], visible_to_user?: string): Promise<boolean> { const WECHAT_API_BASE = ` http://in.qyapi.wbin/webhook/send?key=${ webhookKey}`; const headers = { 'Content-Type': 'application/json', }; const body = JSON.stringify({ 'msgtype': 'text', 'text': { 'content': content, 'mentioned_list': mentioned_list, 'mentioned_mobile_list': mentioned_mobile_list }, 'chatid': chatid, 'visible_to_user': visible_to_user ? visible_to_user.split('|') : undefined }); try { const response = await fetch(WECHAT_API_BASE, { headers, method: 'POST', body }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return true; } catch (error) { console.error('Error sending WeChat message:', error); return false; } } 通过 server.tool 注册发送文本工具,注册工具有四个函数,比如有些可以加描述,有些是0参数调用等等,选一个合适自己的即可。我们这里必须需要知道回调的 webhook key 和 content 。 ![]()
发送文本工具就注册好了,其他功能工具开发类似。 创建resource资源 这里我们放一个企业微信机器人的文档。 server.resource( 'api', 'file:///api.md', async (uri) => { try { console.info(uri) const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const filePath = path.join(__dirname.replace('build', 'assets'), 'api.md'); const content = await fs.promises.readFile(filePath, 'utf-8');
return { contents: [{ uri: uri.href, text: content }] }; } catch (error) { return { contents: [{ uri: uri.href, text: '读取文件失败' }] }; } } ); 创建prompt 提示符是可重用的模板,可以帮助LLMs有效地与服务器交互。这里我们可以做一个参数检查的prompt。
可以使用社区Inspector工具来调试我们的mcp。我使用的版本是v0.6.0,如果是用devcloud开发的同学可能会无法调试使用,因为代理地址写死了是localhost,导致连接失败,已经给社区提了PR #201并合并,远程开发的同学可以直接拉源码或者等待工具发布新版本。(写完的时候发现已经发布v0.7.0,大家可以直接用最新版本了https://github.com/modelcontextprotocol/inspector) 调试tools ![]() ![]() 调试resource ![]() 调试prompt ![]() 03MCP Client的主要任务是连接到MCP Server,可以通过标准输入/输出或 SSE (Server-Sent Events) 与 MCP 服务器进行通信。 初始化客户端和会话对象 class MCPClient: def __init__(self): # 初始化 session 和 client 对象 self.session: Optional[ClientSession] = None self._streams_context: Optional[sse_client] = None self._session_context: Optional[ClientSession] = None self.exit_stack = AsyncExitStack() # 初始化异步退出栈 连接到MCP服务
有两种连接方式,分别是:
清理资源 class MCPClient: def __init__(self): # 初始化 session 和 client 对象 self.session: Optional[ClientSession] = None
async def connect_to_sse_server(self, server_url: str): '''连接到使用 SSE 传输的 MCP 服务器''' if not server_url.startswith(' http://' ) and not server_url.startswith(' https://' ): raise ValueError('服务器 URL 必须以 ' http://' 或 'https://' 开头')
# 存储上下文管理器以保持其存活 self._streams_context = sse_client(url=server_url) streams = await self._streams_context.__aenter__()
self._session_context = ClientSession(*streams) self.session: ClientSession = await self._session_context.__aenter__()
# 初始化 await self.session.initialize()
async def cleanup(self): '''清理 session 和 streams''' if self._session_context: await self._session_context.__aexit__(None, None, None) if self._streams_context: await self._streams_context.__aexit__(None, None, None)
![]() 04MCP采用的是C/S结构,一个MCP host应用可以链接多个MCP servers。 ![]()
![]() 在我们用inspector调试我们的mcp-server时,请求参数里会有jsonrpc字段,在mcp中 client 和 server 之间的传输均采用了JSON-RPC 2.0 来交换消息。 ![]() 主要特点包括:
有了MCP Server 提供的众多工具,模型如何确定该使用哪些工具? 这里可以参考 官方 python-sdk 给的一个example示例:mcp_simple_chatbot(https://github.com/modelcontextprotocol/python-sdk/tree/main/examples/clients/simple-chatbot/mcp_simple_chatbot) #... 省略了无关紧要的代码 async def start(self) -> None: '''Main chat session handler.''' try: #... 省略了无关紧要的代码 all_tools = [] # 获取现在所有的工具列表 for server in self.servers: tools = await server.list_tools() all_tools.extend(tools)
tools_description = '\n'.join([tool.format_for_llm() for tool in all_tools]) # 定义一个善于调用各种工具的助手prompt system_message = ( 'You are a helpful assistant with access to these tools:\n\n' f'{tools_description}\n' 'Choose the appropriate tool based on the user's question. ' 'If no tool is needed, reply directly.\n\n' 'IMPORTANT: When you need to use a tool, you must ONLY respond with ' 'the exact JSON object format below, nothing else:\n' '{\n' ' 'tool': 'tool-name',\n' ' 'arguments': {\n' ' 'argument-name': 'value'\n' ' }\n' '}\n\n' 'After receiving a tool's response:\n' '1. Transform the raw data into a natural, conversational response\n' '2. Keep responses concise but informative\n' '3. Focus on the most relevant information\n' '4. Use appropriate context from the user's question\n' '5. Avoid simply repeating the raw data\n\n' 'Please use only the tools that are explicitly defined above.' )
messages = [{'role': 'system', 'content': system_message}]
while True: try: user_input = input('You: ').strip().lower() #... 省略了无关紧要的代码 messages.append({'role': 'user', 'content': user_input}) #问模型我现在应该执行哪些工具 llm_response = self.llm_client.get_response(messages) # 执行工具 result = await self.process_llm_response(llm_response) #... 省略了无关紧要的代码 except KeyboardInterrupt: #... 省略了无关紧要的代码 finally: await self.cleanup_servers()
Host应用(如Cursor)作为交互入口,通过内置的Client模块与多个专用Server建立一对一连接。当用户提问时,Host借助大模型分析请求并选择工具:首先获取所有Server注册的工具列表,通过结构化提示词引导模型生成JSON格式的调用指令,再通过JSON-RPC 2.0协议将指令路由到对应Server执行具体操作(如文件扫描)。执行结果经Host处理后转化为自然语言响应返回用户,实现模型决策与工具执行的解耦,通过轻量级通信协议完成分布式任务处理。 05结合我们的mcp server 和 mcp client的示例,实现一个通过查询知识库数据后将结果通过企业微信机器人群聊内。 ![]() ![]() 06这篇文章是记录自己在学习MCP过程中的一些感受和想法,可能存在疏漏和不准确的地方。如果有不对的地方,还请各位批评指正。同时,也欢迎大家一起交流讨论,共同探索MCP及其应用的更多可能性。 ![]() |
|