議:從 JSON-RPC 底層通信到 MySQL 實(shí)戰(zhàn)接入 TaoToken)
1. 為什么你的 MySQL 查詢總在 MCP 里斷聯(lián)很多人第一次接觸 MCP 協(xié)議腦子里裝的全是“AI 的 USB-C 接口”這種比喻真到動(dòng)手把 MySQL 接進(jìn)去的時(shí)候發(fā)現(xiàn)連不上、報(bào)錯(cuò)看不懂、工具調(diào)不動(dòng)。我試過用最笨的辦法排查先確認(rèn) MCP 服務(wù)端到底有沒有把tools/list暴露出來再確認(rèn)客戶端發(fā)出去的 JSON-RPC 請(qǐng)求長什么樣最后才去看 MySQL 連接本身。這個(gè)順序能幫你省掉大量瞎猜的時(shí)間。MCP 全稱 Model Context Protocol它要解決的核心問題很具體讓任何支持該協(xié)議的 AI 客戶端都能用同一套標(biāo)準(zhǔn)去調(diào)用你寫的外部工具。你寫一次 MySQL 查詢服務(wù)端Claude Desktop、Cursor、Cline 這些宿主應(yīng)用都能直接接。它底層用的消息格式是 JSON-RPC 2.0傳輸通道有 stdio 和 HTTP 兩種。你不需要理解全部規(guī)范但必須搞清楚三件事請(qǐng)求長什么樣、服務(wù)端怎么啟動(dòng)、客戶端配置寫在哪里。這篇文章面向的是已經(jīng)會(huì)寫 Python、手頭有 MySQL 庫、想讓 AI 直接查數(shù)據(jù)的開發(fā)者。我會(huì)從 JSON-RPC 的消息結(jié)構(gòu)講起然后給你一份可復(fù)制的config.toml和settings.json骨架接著用 TaoToken 的統(tǒng)一 API 通道把服務(wù)端接進(jìn)去最后用真實(shí)的 JSON-RPC 請(qǐng)求驗(yàn)證 MySQL 工具調(diào)用是否生效。全程不繞彎每一步都有命令和結(jié)果說明。先說清楚 TaoToken 在這里的角色。TaoToken 提供統(tǒng)一的 API Key 和模型接入通道官網(wǎng)是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。你寫好的 MCP 服務(wù)端通過它來調(diào)用模型能力這樣你不需要在本地維護(hù)多個(gè)廠商的 Key一個(gè) Key 就能跑通整個(gè)鏈路。下面進(jìn)入正題。2. JSON-RPC 消息格式與 stdio/HTTP 傳輸通道拆解MCP 的通信層沒有魔法它就是 JSON-RPC 2.0。一條請(qǐng)求由四個(gè)字段組成jsonrpc固定為2.0id用來匹配請(qǐng)求和響應(yīng)method是你要調(diào)用的方法名params是參數(shù)對(duì)象。服務(wù)端返回時(shí)帶上同樣的id把結(jié)果放在result里出錯(cuò)則放在error里。MCP 定義了幾個(gè)核心方法你寫服務(wù)端時(shí)最常打交道的是這三個(gè)initialize用于握手協(xié)商能力tools/list用于暴露工具清單tools/call用于實(shí)際執(zhí)行某個(gè)工具??蛻舳藛?dòng)后會(huì)先發(fā)initialize再發(fā)tools/list拿到你注冊(cè)的所有工具之后模型決定調(diào)用哪個(gè)工具時(shí)客戶端就發(fā)tools/call。一條tools/call請(qǐng)求的真實(shí)樣子是這樣的{ jsonrpc: 2.0, id: 1, method: tools/call, params: { name: query_data, arguments: { sql: SELECT id, name FROM users LIMIT 3 } } }服務(wù)端執(zhí)行完 MySQL 查詢后返回{ jsonrpc: 2.0, id: 1, result: { content: [ { type: text, text: [{\id\: 1, \name\: \張三\}, {\id\: 2, \name\: \李四\}] } ] } }注意result.content是一個(gè)數(shù)組里面每個(gè)元素有type和text。這是 MCP 規(guī)定的返回結(jié)構(gòu)模型讀到text字段后把它轉(zhuǎn)成自然語言給你。你寫服務(wù)端時(shí)只要保證返回這個(gè)結(jié)構(gòu)客戶端就能正確解析。接下來是傳輸通道。stdio 模式下MCP 服務(wù)端作為宿主應(yīng)用的子進(jìn)程運(yùn)行雙方通過標(biāo)準(zhǔn)輸入輸出交換 JSON-RPC 消息。它的優(yōu)點(diǎn)是配置極簡不需要開端口本地開發(fā)首選。缺點(diǎn)是只能本機(jī)用沒法遠(yuǎn)程訪問。HTTP 模式下服務(wù)端作為獨(dú)立進(jìn)程監(jiān)聽端口客戶端通過 HTTP POST 發(fā)送 JSON-RPC 請(qǐng)求可選 SSE 做流式推送。它適合多客戶端連接和遠(yuǎn)程部署但配置項(xiàng)更多。這里有個(gè)我踩過的坑早期 MCP 用的是 SSE 傳輸后來協(xié)議做了破壞性更新改成 Streamable HTTP。如果你照著老教程配 SSE連接會(huì)一直斷。判斷方法很簡單運(yùn)行pip show mcp看版本0.9.0 以上才支持新的傳輸規(guī)范。版本不對(duì)就升級(jí)別在舊實(shí)現(xiàn)上浪費(fèi)時(shí)間。兩種通道的選擇邏輯很清晰本地單機(jī)調(diào)試用 stdio需要多人共用或遠(yuǎn)程訪問用 HTTP。下面兩節(jié)我會(huì)分別給出可復(fù)制的配置。3. 可復(fù)制配置config.toml 與 settings.json 骨架這一節(jié)給你兩份能直接改改就用的配置骨架。第一份是 MCP 服務(wù)端的config.toml第二份是客戶端側(cè)的settings.json。兩份配置里的 Base URL、Key、Model ID 三件套必須寫全缺一個(gè)都會(huì)在驗(yàn)證階段報(bào)錯(cuò)。先看服務(wù)端的config.toml。這個(gè)文件放在你的 MCP 項(xiàng)目根目錄用來管理數(shù)據(jù)庫連接和 TaoToken 通道參數(shù)# config.toml - MCP MySQL 服務(wù)端配置 [server] name mysql-assistant version 0.1.0 transport stdio # 可選 stdio 或 http [transport.http] host 0.0.0.0 port 8000 path /mcp [database] host 127.0.0.1 port 3306 user root password your_password database your_db charset utf8mb4 [taotoken] base_url https://taotoken.net/api api_key sk-你的TaoToken密鑰 model_id claude-3-5-sonnettransport字段決定用哪種通道。改成http后服務(wù)端會(huì)讀取[transport.http]段啟動(dòng) HTTP 監(jiān)聽。[taotoken]段里的base_url固定寫https://taotoken.net/apiapi_key從 TaoToken 控制臺(tái)生成model_id填你要用的模型標(biāo)識(shí)。再看客戶端側(cè)的settings.json。如果你用的是 Cline 或 Claude Code 這類支持 MCP 的客戶端配置寫在這里{ mcpServers: { mysql-assistant: { command: python, args: [/絕對(duì)路徑/mysql_mcp_server.py], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: sk-你的TaoToken密鑰, TAOTOKEN_MODEL_ID: claude-3-5-sonnet } } } }如果你走 HTTP 模式settings.json改成 URL 形式{ mcpServers: { mysql-assistant: { url: http://127.0.0.1:8000/mcp, headers: { Authorization: Bearer sk-你的TaoToken密鑰 } } } }三件套的對(duì)應(yīng)關(guān)系是Base URL 填https://taotoken.net/apiKey 填你生成的sk-開頭密鑰Model ID 填模型標(biāo)識(shí)。這三個(gè)值在 stdio 模式下通過env傳入在 HTTP 模式下通過headers傳入。寫錯(cuò)任何一個(gè)驗(yàn)證階段都會(huì)看到 401 或模型找不到的報(bào)錯(cuò)。配置寫完后stdio 模式直接啟動(dòng) Python 腳本即可HTTP 模式需要先啟動(dòng)服務(wù)端再啟動(dòng)客戶端。切換步驟在下一節(jié)結(jié)合驗(yàn)證一起講。4. 驗(yàn)證請(qǐng)求用 JSON-RPC 確認(rèn) MySQL 工具調(diào)用生效配置寫完不等于接通必須用真實(shí)的 JSON-RPC 請(qǐng)求驗(yàn)證一遍。我習(xí)慣分三步走先驗(yàn)證服務(wù)端能列出工具再驗(yàn)證工具能查到數(shù)據(jù)最后驗(yàn)證模型能通過 TaoToken 通道調(diào)用工具。第一步驗(yàn)證tools/list。如果你走 HTTP 模式服務(wù)端啟動(dòng)后直接用 curl 發(fā)請(qǐng)求curl -X POST http://127.0.0.1:8000/mcp \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的TaoToken密鑰 \ -d { jsonrpc: 2.0, id: 1, method: tools/list, params: {} }正常返回會(huì)列出你注冊(cè)的所有工具比如query_data、get_table_schema、list_tables。如果返回空數(shù)組說明工具注冊(cè)沒生效檢查mcp.tool()裝飾器有沒有寫對(duì)。第二步驗(yàn)證tools/call能查到 MySQL 數(shù)據(jù)curl -X POST http://127.0.0.1:8000/mcp \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的TaoToken密鑰 \ -d { jsonrpc: 2.0, id: 2, method: tools/call, params: { name: query_data, arguments: { sql: SELECT id, name FROM users LIMIT 3 } } }返回的result.content[0].text里應(yīng)該有你數(shù)據(jù)庫里的真實(shí)數(shù)據(jù)。如果返回“數(shù)據(jù)庫錯(cuò)誤”先檢查config.toml里的數(shù)據(jù)庫賬號(hào)密碼再確認(rèn) MySQL 服務(wù)是否在跑。第三步驗(yàn)證模型調(diào)用鏈路。在客戶端里直接問“幫我查一下 users 表里前三條記錄”??蛻舳藭?huì)先發(fā)tools/list拿到工具清單模型決定調(diào)用query_data客戶端發(fā)tools/call服務(wù)端查完 MySQL 返回結(jié)果模型再把結(jié)果轉(zhuǎn)成自然語言。整個(gè)過程你能在客戶端日志里看到完整的 JSON-RPC 消息流。stdio 模式的驗(yàn)證方式略有不同因?yàn)橄⒆邩?biāo)準(zhǔn)輸入輸出沒法用 curl。你可以在服務(wù)端加一行日志把收到的每條請(qǐng)求打印出來然后在客戶端觸發(fā)一次查詢看日志里有沒有tools/call進(jìn)來。確認(rèn)有請(qǐng)求進(jìn)來且返回了數(shù)據(jù)就說明鏈路通了。驗(yàn)證通過后你可以把transport從stdio改成http重啟服務(wù)端把客戶端的settings.json從command形式改成url形式再跑一遍上面三步。兩種模式切換的核心就是改配置里的傳輸字段和客戶端的連接方式工具代碼本身不用動(dòng)。5. 常見報(bào)錯(cuò)排查401、local proxy failed 與 reading choices這一節(jié)列出我實(shí)際遇到過的幾類報(bào)錯(cuò)以及對(duì)應(yīng)的排查動(dòng)作。你按順序?qū)φ栈灸芨采w九成以上的接入問題。第一類401 Unauthorized。這個(gè)最直接就是 Key 不對(duì)或沒傳。檢查三處config.toml里的api_key是不是sk-開頭且沒有多余空格settings.json里的TAOTOKEN_API_KEY或Authorization頭有沒有寫對(duì)HTTP 模式下Bearer后面有沒有跟空格。如果 Key 是從控制臺(tái)復(fù)制的注意別把換行符帶進(jìn)去。第二類local proxy failed。這個(gè)報(bào)錯(cuò)通常出現(xiàn)在客戶端嘗試連接 MCP 服務(wù)端時(shí)。排查順序是先確認(rèn)服務(wù)端進(jìn)程有沒有真的啟動(dòng)ps aux | grep mysql_mcp_server看一眼再確認(rèn)端口有沒有被占用lsof -i :8000檢查最后確認(rèn)settings.json里的路徑或 URL 寫對(duì)了。stdio 模式下最常見的原因是 Python 路徑不對(duì)args里必須寫絕對(duì)路徑。第三類reading choices 相關(guān)報(bào)錯(cuò)。這個(gè)一般出現(xiàn)在模型返回階段說明模型返回的內(nèi)容格式不符合預(yù)期。檢查model_id有沒有寫錯(cuò)以及 TaoToken 通道是否正常。你可以先用模型對(duì)話功能單獨(dú)測(cè)一下模型能不能正常返回確認(rèn)通道沒問題后再排查 MCP 側(cè)。第四類OAuth 相關(guān)報(bào)錯(cuò)。如果你用的是 Claude Code 這類帶 OAuth 流程的客戶端可能會(huì)遇到 token 過期或回調(diào)失敗。這類問題的排查重點(diǎn)是確認(rèn)客戶端的登錄狀態(tài)以及settings.json里的配置有沒有覆蓋掉 OAuth 流程。如果你走的是 TaoToken 的 Key 通道一般不會(huì)觸發(fā) OAuth遇到這類報(bào)錯(cuò)先檢查是不是配置寫混了。第五類工具調(diào)用返回空結(jié)果。JSON-RPC 請(qǐng)求發(fā)出去了服務(wù)端也返回了但result.content是空的。這種情況多半是工具函數(shù)的返回值沒有按 MCP 規(guī)范包裝。記住返回結(jié)構(gòu)必須是{content: [{type: text, text: ...}]}直接返回字符串或字典都不行。排查時(shí)有個(gè)通用技巧把服務(wù)端的日志級(jí)別調(diào)到 DEBUG把每條收到的 JSON-RPC 請(qǐng)求和返回都打出來。這樣你能清楚看到請(qǐng)求有沒有進(jìn)來、參數(shù)對(duì)不對(duì)、返回結(jié)構(gòu)符不符合規(guī)范。大部分問題看一眼日志就能定位。6. 把 MySQL 查詢接進(jìn)你的 AI 工作流走到這里你已經(jīng)有了一個(gè)能跑的 MCP MySQL 服務(wù)端兩種傳輸通道都驗(yàn)證過常見報(bào)錯(cuò)也能自己排查。接下來就是把它接進(jìn)日常開發(fā)流程。如果你只是偶爾查一下數(shù)據(jù)stdio 模式足夠用配置簡單啟動(dòng)快。如果你要和團(tuán)隊(duì)共用或者需要遠(yuǎn)程訪問就切到 HTTP 模式把服務(wù)端部署在一臺(tái)內(nèi)網(wǎng)機(jī)器上其他人通過 URL 接入。切換時(shí)記得同步改客戶端的settings.jsonstdio 用commandHTTP 用url。TaoToken 的接入點(diǎn)在這里你的 MCP 服務(wù)端通過https://taotoken.net/api調(diào)用模型能力一個(gè) Key 管所有模型。需要生成或管理 Key 就去 API Keys 頁面接入細(xì)節(jié)看接入文檔。如果你要驗(yàn)證模型返回效果用模型對(duì)話功能單獨(dú)測(cè)。如果你打算長期跑編碼類 Agent 任務(wù)Coding Plan 更適合。最后留一個(gè)實(shí)用建議工具描述docstring比工具代碼本身更影響實(shí)際可用性。模型是通過讀你的描述來決定調(diào)不調(diào)、怎么調(diào)的。描述里寫清楚“只允許 SELECT”“查詢前先用 get_table_schema 了解表結(jié)構(gòu)”模型的行為會(huì)準(zhǔn)確很多。這個(gè)細(xì)節(jié)很多教程不提但它直接決定你的 MCP 服務(wù)端好不好用。