??目錄 1 什么是 MCP 2 MCP Server 開發(fā) 3 MCP Client 開發(fā) 4 MCP的工作原理 5 效果呈現(xiàn) 6 寫在最后 01MCP(Model Context Protocol,模型上下文協(xié)議) 起源于 2024 年 11 月 25 日 Anthropic 發(fā)布的文章:Introducing the Model Context Protocol。 可以用“AI 擴(kuò)展塢”來比喻 MCP 在 AI 領(lǐng)域的作用。就像現(xiàn)代擴(kuò)展塢可以連接顯示器、鍵盤、移動硬盤等多種外設(shè),為筆記本電腦瞬間擴(kuò)展功能一樣,MCP Server 作為一個智能中樞平臺,能夠動態(tài)接入各類專業(yè)能力模塊(如知識庫、計算工具、領(lǐng)域模型等)。當(dāng) LLM 需要完成特定任務(wù)時,可以像'即插即用'般調(diào)用這些模塊,實時獲得精準(zhǔn)的上下文支持,從而實現(xiàn)能力的彈性擴(kuò)展。這種架構(gòu)打破了傳統(tǒng) AI 模型的封閉性,讓大語言模型像搭載了多功能擴(kuò)展塢的超級工作站,隨時都能獲取最合適的專業(yè)工具。 ![]() 終結(jié)工具調(diào)用碎片化 不同模型在定義 Function Call(函數(shù)調(diào)用)時,采用的結(jié)構(gòu)和參數(shù)格式各不相同,使得對多模型集成、統(tǒng)一管理和標(biāo)準(zhǔn)化接入變得復(fù)雜而繁瑣。
![]() 對于開發(fā)者來說,針對不同模型去實現(xiàn)不同的工具調(diào)用方法,所謂的定制化開發(fā)不僅消耗大量時間和資源,而且維護(hù)也變得困難。 而 MCP 作為一種 AI 模型的標(biāo)準(zhǔn)化接入?yún)f(xié)議,能夠顯著簡化模型之間的集成。 實現(xiàn)多功能應(yīng)用與創(chuàng)新體驗的突破 MCP 的潛力不僅限于連接現(xiàn)有工具,它還在推動客戶端應(yīng)用向“萬能應(yīng)用”演進(jìn),并創(chuàng)造全新的用戶體驗。 以代碼編輯器 Cursor 為例,作為 MCP 客戶端,用戶可以通過集成不同的 MCP 服務(wù)器,將其轉(zhuǎn)變?yōu)榫邆?Slack 消息收發(fā)、郵件發(fā)送(Resend MCP)、甚至圖像生成(Replicate MCP)等多種功能的綜合工作站。 更具創(chuàng)造力的是,在單一客戶端中組合多個 MCP 服務(wù)器可以解鎖復(fù)雜的新流程。例如,AI 代理可以一邊生成前端界面代碼,一邊調(diào)用圖像生成服務(wù)器為主頁創(chuàng)作視覺元素。這種模式超越了傳統(tǒng)應(yīng)用的單一功能限制,為用戶帶來多樣化的操作體驗。 02MCP server 是 MCP 架構(gòu)中的關(guān)鍵組件,目前提供 3 種主要類型的功能,
還有其他兩種(samping 和 roots)但是目前還沒被很好的支持。 ![]() 以開發(fā)一個企業(yè)微信機器人 mcp server 為例,用到的是社區(qū)sdk typescript-sdk 。(https://github.com/modelcontextprotocol/typescript-sdk) 可以參考官方 quickstart(https:///quickstart/server) 環(huán)境: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 函數(shù)。 創(chuàng)建 tools 工具定義 mcp 提供給 client 或者 llm 使用的工具,企業(yè)微信機器人主要就是 發(fā)送文本、發(fā)送 markdown、發(fā)送圖片等等,這里我們舉例一個發(fā)送文本的工具實現(xiàn)
// 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 注冊發(fā)送文本工具,注冊工具有四個函數(shù),比如有些可以加描述,有些是0參數(shù)調(diào)用等等,選一個合適自己的即可。我們這里必須需要知道回調(diào)的 webhook key 和 content 。 ![]()
發(fā)送文本工具就注冊好了,其他功能工具開發(fā)類似。 創(chuàng)建resource資源 這里我們放一個企業(yè)微信機器人的文檔。 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: '讀取文件失敗' }] }; } } ); 創(chuàng)建prompt 提示符是可重用的模板,可以幫助LLMs有效地與服務(wù)器交互。這里我們可以做一個參數(shù)檢查的prompt。
可以使用社區(qū)Inspector工具來調(diào)試我們的mcp。我使用的版本是v0.6.0,如果是用devcloud開發(fā)的同學(xué)可能會無法調(diào)試使用,因為代理地址寫死了是localhost,導(dǎo)致連接失敗,已經(jīng)給社區(qū)提了PR #201并合并,遠(yuǎn)程開發(fā)的同學(xué)可以直接拉源碼或者等待工具發(fā)布新版本。(寫完的時候發(fā)現(xiàn)已經(jīng)發(fā)布v0.7.0,大家可以直接用最新版本了https://github.com/modelcontextprotocol/inspector) 調(diào)試tools ![]() ![]() 調(diào)試resource ![]() 調(diào)試prompt ![]() 03MCP Client的主要任務(wù)是連接到MCP Server,可以通過標(biāo)準(zhǔn)輸入/輸出或 SSE (Server-Sent Events) 與 MCP 服務(wù)器進(jìn)行通信。 初始化客戶端和會話對象 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服務(wù)
有兩種連接方式,分別是:
清理資源 class MCPClient: def __init__(self): # 初始化 session 和 client 對象 self.session: Optional[ClientSession] = None
async def connect_to_sse_server(self, server_url: str): '''連接到使用 SSE 傳輸?shù)?MCP 服務(wù)器''' if not server_url.startswith(' http://' ) and not server_url.startswith(' https://' ): raise ValueError('服務(wù)器 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結(jié)構(gòu),一個MCP host應(yīng)用可以鏈接多個MCP servers。 ![]()
![]() 在我們用inspector調(diào)試我們的mcp-server時,請求參數(shù)里會有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) #... 省略了無關(guān)緊要的代碼 async def start(self) -> None: '''Main chat session handler.''' try: #... 省略了無關(guān)緊要的代碼 all_tools = [] # 獲取現(xiàn)在所有的工具列表 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]) # 定義一個善于調(diào)用各種工具的助手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() #... 省略了無關(guān)緊要的代碼 messages.append({'role': 'user', 'content': user_input}) #問模型我現(xiàn)在應(yīng)該執(zhí)行哪些工具 llm_response = self.llm_client.get_response(messages) # 執(zhí)行工具 result = await self.process_llm_response(llm_response) #... 省略了無關(guān)緊要的代碼 except KeyboardInterrupt: #... 省略了無關(guān)緊要的代碼 finally: await self.cleanup_servers()
Host應(yīng)用(如Cursor)作為交互入口,通過內(nèi)置的Client模塊與多個專用Server建立一對一連接。當(dāng)用戶提問時,Host借助大模型分析請求并選擇工具:首先獲取所有Server注冊的工具列表,通過結(jié)構(gòu)化提示詞引導(dǎo)模型生成JSON格式的調(diào)用指令,再通過JSON-RPC 2.0協(xié)議將指令路由到對應(yīng)Server執(zhí)行具體操作(如文件掃描)。執(zhí)行結(jié)果經(jīng)Host處理后轉(zhuǎn)化為自然語言響應(yīng)返回用戶,實現(xiàn)模型決策與工具執(zhí)行的解耦,通過輕量級通信協(xié)議完成分布式任務(wù)處理。 05結(jié)合我們的mcp server 和 mcp client的示例,實現(xiàn)一個通過查詢知識庫數(shù)據(jù)后將結(jié)果通過企業(yè)微信機器人群聊內(nèi)。 ![]() ![]() 06這篇文章是記錄自己在學(xué)習(xí)MCP過程中的一些感受和想法,可能存在疏漏和不準(zhǔn)確的地方。如果有不對的地方,還請各位批評指正。同時,也歡迎大家一起交流討論,共同探索MCP及其應(yīng)用的更多可能性。 ![]() |
|