模型上下文協議(Model Context Protocol,簡稱MCP) 是一種全新的開放協議,專門用于標準化地為大語言模型(LLMs)提供應用場景和數據背景。 你可以把MCP想象成AI領域的“USB-C接口”,它能讓不同的AI模型與外部工具和數據源輕松連接
近來學習了一下,先是使用stdio的方式叫cursor做了一個,完全沒有問題。但是sse的方式叫cursor 干始終不成功, 找了一輪,發現youtube的教程視頻里主持,也沒有搞定sse的服務器,balahblah說了一堆,就要move on ....于是研究了一下。
1. 首先MCP SSE是基于http協議的一個應用,服務器和客戶端主要通過json rc的方式進行溝通。
2. MCP SSE Client會發起多個連接,但是第一個連接是http://yourhost:port/sse,? 這個連接是溝通的第一步,它會使用chunked的回傳數據,意思是不告訴client這個數據有多少,這樣就它就可以一直連著了。 所以這個鏈接就是一個用來通知的鏈接。你現在就明白了為什么 ,就叫SSE(Server-Sent Events )。 它首先按以下格式信息給client, 然后就是定時的ping包了, 每次都只是一個chunk,估計后期server會有推送也會使用這個鏈接通知client.
event: 事件的名字
data: 事件的數據
? ? ? 2.1 第一個event是,這個直接返回,就是給client分配一個session_id, 方便后面多個連接過來服務器可以分清誰和誰。
51
event: endpoint
data: /messages/?session_id=07aa8f90d79a49eaad802693cdd05b5b
? ? ? client收到這個,就會以http://yourhost:port/messages/?session_id=07aa8f90d79a49eaad802693cdd05b5b , 新發起一個連接去請求mcp sse server
? ? ?2.2 第二個event是event: message, 這個data 是一個json來的,就是告訴client,當前mcp server的能力,還有服務器的基本信息。
124
event: message
data: {"jsonrpc": "2.0","id": 0,"result": {"protocolVersion": "2024-11-05","capabilities": {"experimental": {},"prompts": {"listChanged": false},"resources": {"subscribe": false,"listChanged": false},"tools": {"listChanged": false}},"serverInfo": {"name": "mem0-mcp","version": "1.3.0"}}
}
? ? ?2.3 第三個event也是一個message , 用來告訴client 服務器提供的tools有哪些。
{"jsonrpc": "2.0","id": 1,"result": {"tools": [{"name": "add_coding_preference","description": "Add a new coding preference to mem0. This tool stores code snippets, implementation details,\n and coding patterns for future reference. Store every code snippet. When storing code, you should include:\n - Complete code with all necessary imports and dependencies\n - Language/framework version information (e.g., \"Python 3.9\", \"React 18\")\n - Full implementation context and any required setup/configuration\n - Detailed comments explaining the logic, especially for complex sections\n - Example usage or test cases demonstrating the code\n - Any known limitations, edge cases, or performance considerations\n - Related patterns or alternative approaches\n - Links to relevant documentation or resources\n - Environment setup requirements (if applicable)\n - Error handling and debugging tips\n The preference will be indexed for semantic search and can be retrieved later using natural language queries.","inputSchema": {"properties": {"text": {"title": "Text","type": "string"}},"required": ["text"],"title": "add_coding_preferenceArguments","type": "object"}},{"name": "get_all_coding_preferences","description": "Retrieve all stored coding preferences for the default user. Call this tool when you need \n complete context of all previously stored preferences. This is useful when:\n - You need to analyze all available code patterns\n - You want to check all stored implementation examples\n - You need to review the full history of stored solutions\n - You want to ensure no relevant information is missed\n Returns a comprehensive list of:\n - Code snippets and implementation patterns\n - Programming knowledge and best practices\n - Technical documentation and examples\n - Setup and configuration guides\n Results are returned in JSON format with metadata.","inputSchema": {"properties": {},"title": "get_all_coding_preferencesArguments","type": "object"}},{"name": "search_coding_preferences","description": "Search through stored coding preferences using semantic search. This tool should be called \n for EVERY user query to find relevant code and implementation details. It helps find:\n - Specific code implementations or patterns\n - Solutions to programming problems\n - Best practices and coding standards\n - Setup and configuration guides\n - Technical documentation and examples\n The search uses natural language understanding to find relevant matches, so you can\n describe what you're looking for in plain English. Always search the preferences before \n providing answers to ensure you leverage existing knowledge.","inputSchema": {"properties": {"query": {"title": "Query","type": "string"}},"required": ["query"],"title": "search_coding_preferencesArguments","type": "object"}}]}
}
跟著就是ping包的返回,防止client死了。
2d
: ping - 2025-03-12 08:16:23.071429+00:00
3. endpoint請求
? ?拿到endpont后,client 使用post的請求endpoint,? 這個只處理請求,目前看?返回則在第一個http連接里。
第二個鏈接 請求如下:, 這個調用initialize,對應上面的第一個message的event.
第二個鏈接, 這個只回復202 AcceptedPOST /messages/?session_id=9aa12073a4494d5580a5c30ed54c4bfd HTTP/1.1
host: 10.0.105.64:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 253{"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"tools":true,"prompts":false,"resources":true,"logging":false,"roots":{"listChanged":false}},"clientInfo":{"name":"cursor-vscode","version":"1.0.0"}},"jsonrpc":"2.0","id":0}
HTTP/1.1 202 Accepteddate: Wed, 12 Mar 2025 08:08:32 GMT
server: uvicorn
content-length: 8Accepted
第三個鏈接,請求如下:
第三個鏈接,僅回復 202 AcceptedPOST /messages/?session_id=9aa12073a4494d5580a5c30ed54c4bfd HTTP/1.1
host: 10.0.105.64:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 54{"method":"notifications/initialized","jsonrpc":"2.0"}
HTTP/1.1 202 Accepted
date: Wed, 12 Mar 2025 08:08:32 GMT
server: uvicorn
content-length: 8Accepted
第四個鏈接,請求如下,請求tools/list, 服務器在第一個get的鏈接,通過event的方式返回了這個列表給mcp sse client
第四個鏈接,僅加復 202 AcceptedPOST /messages/?session_id=9aa12073a4494d5580a5c30ed54c4bfd HTTP/1.1
host: 10.0.105.64:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 46{"method":"tools/list","jsonrpc":"2.0","id":1}
HTTP/1.1 202 Accepted
date: Wed, 12 Mar 2025 08:08:32 GMT
server: uvicorn
content-length: 8Accepted
1-3完成就是屬于初始化完成,mcp sse的client和server 連接起來了。
然后后面使用mcp call 調用的,在cursor chat里輸入
call mcp tool search_coding_preferences about StdioServerTransport
就是新起一個http短鏈接,post到endpoint,如下
POST /messages/?session_id=97a44bcff590415e99cf803350ffd542 HTTP/1.1
host: 10.0.105.64:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 143{"method":"tools/call","params":{"name":"search_coding_preferences","arguments":{"query":"about StdioServerTransport"}},"jsonrpc":"2.0","id":3}HTTP/1.1 202 Accepted
date: Wed, 12 Mar 2025 09:10:43 GMT
server: uvicorn
content-length: 8HTTP/1.1 202 Accepted
date: Wed, 12 Mar 2025 09:10:43 GMT
server: uvicorn
content-length: 8Accepted
第一個鏈接就是會有一個通知返回如下:
event: message
data: {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"[]"}],"isError":false}}