Agent 與 MCP
把 MCP 接進 Claude:client 實作與整合全流程
把 MCP 接進 Claude:client 實作與整合全流程
server 寫好了,誰來用它?答案是 MCP client。這篇先帶你在自己的應用裡把 client 實作出來,看懂 list_tools 與 call_tool 怎麼跟 Claude API 的對話迴圈接在一起,再把 resources 與 prompts 也接進來;最後談談 Claude 桌面應用與 Claude Code 這些現成的 client,你會發現它們做的事一模一樣。
你將學到什麼
client 的架構定位
ClientSession 管連線,外層類別管資源清理。
兩個核心方法
list_tools 拿清單、call_tool 執行,各三行搞定。
接回 Claude 的迴圈
工具清單、tool use 請求、結果回填怎麼串。
現成的 client
Claude 桌面應用與 Claude Code 背後做的同一件事。
client 在架構裡的位置
MCP client 是你的應用與 MCP server 之間的橋樑,所有訊息傳遞與協定細節都由它處理。用 Python SDK 實作時,通常包成兩層:SDK 提供的 ClientSession 負責真正的連線,外面再包一個自己的 MCPClient 類別。
為什麼要多包一層?因為 session 的連線需要好好收尾:用完要清理資源,出錯也要正確關閉。把這些細節收進自己的類別,應用程式碼就能用乾淨的 async with 語法開關連線,不必到處記得清理。
回顧一下應用流程:CLI 程式需要 client 做的其實就是兩個時點的事,一是對話開始前拿工具清單給 Claude,二是 Claude 點名工具時代為執行。整個 client 的介面,就繞著這兩件事設計。
兩個核心方法:list_tools 與 call_tool
你的應用只需要 client 做兩件事:拿工具清單、執行工具。對應兩個方法:
async def list_tools(self) -> list[types.Tool]:
result = await self.session().list_tools()
return result.tools
async def call_tool(
self, tool_name: str, tool_input: dict
) -> types.CallToolResult | None:
return await self.session().call_tool(tool_name, tool_input)
兩個方法都只是薄薄一層:透過 session 呼叫 SDK 內建的功能,把結果傳回去。tool_name 與 tool_input 是 Claude 在 tool use 回應裡給的,原封不動轉交即可。
寫完可以先單測 client,不急著接 Claude。用測試 harness 連上 server,把工具定義印出來看:
async with MCPClient(
command="uv", args=["run", "mcp_server.py"]
) as client:
result = await client.list_tools()
print(result)
看到 read_doc_contents 與 edit_document 兩個工具的名稱、描述、輸入 schema 都印出來,這一層就通了。
接回 Claude 的對話迴圈
有了這兩個方法,完整流程就通了。問一句「report.pdf 這份文件的內容是什麼?」,背後發生的事:
- 你的應用用 client 取得可用的工具清單。
- 工具清單連同問題一起送給 Claude。
- Claude 決定使用 read_doc_contents 工具,回覆 tool use 請求。
- 你的應用用 client 執行該工具,拿到文件內容。
- 結果回傳給 Claude,Claude 整理出最終回答給使用者。
實際跑一次最有感:問這句話,你會在回答裡看到 server 裡預先放好的那份「20 公尺冷凝塔報告」的內容,證明整條線是通的。
這條迴圈就是 tool use 的標準流程,差別只在一件事:工具不是你寫的,是 MCP server 提供的。你的程式碼從「維護一堆整合」變成「轉接一條協定」。順帶一提,如果 server 端的工具有增減,MCP 也定義了工具清單變更的通知訊息,client 可以據此更新給 Claude 的清單。
resources 與 prompts 也接進來
resources 讓使用者用 @ 提及文件時,內容直接進 prompt,不必繞工具呼叫。client 端實作一個 read_resource,依回應的 MIME type 決定怎麼解析:JSON 就 parse 成物件,其他當純文字回傳:
import json
from pydantic import AnyUrl
async def read_resource(self, uri: str) -> Any:
result = await self.session().read_resource(AnyUrl(uri))
resource = result.contents[0]
if isinstance(resource, types.TextResourceContents):
if resource.mimeType == "application/json":
return json.loads(resource.text)
return resource.text
從使用者眼裡看,整條路是這樣:
- 輸入 @,畫面列出可選的資源清單做自動完成。
- 選定文件,送出訊息。
- 應用自動抓取該資源的內容,直接塞進 prompt。
- Claude 拿著現成的內容立刻回答,不再發工具呼叫。
prompts 則是兩個方法:list_prompts 列出可用範本,get_prompt 帶引數取回已把變數安插好的完整訊息。CLI 裡輸入 slash 就列出指令,選了 format 再選文件,完整的 prompt 就送向 Claude:
async def list_prompts(self) -> list[types.Prompt]:
result = await self.session().list_prompts()
return result.prompts
async def get_prompt(self, prompt_name, args: dict[str, str]):
result = await self.session().get_prompt(prompt_name, args)
return result.messages
職責切乾淨的好處在這裡看得最清楚:client 負責跟 server 溝通,應用邏輯負責決定資料怎麼用。read_resource 與 get_prompt 都是積木,聊天介面、指令選單這些功能,拿著積木組就好。
不想自己寫?現成的 client 就在你手邊
實務上,多數人不需要自己實作 client。Claude 桌面應用與 Claude Code 本身就是 MCP client:把 server 的位置與啟動方式告訴它們,剩下的握手、列工具、執行工具,全部照這篇講的流程自動發生,工具、資源、提示就直接進到你的對話裡。
自己實作 client 的價值,在於把 MCP 接進你自己的產品:你的聊天介面、你的內部工具,都能透過同一套協定,取用整個 MCP 生態的 server。
這個 CLI 專案其實就是一個縮小版的聊天應用:main.py 管對話迴圈,mcp_client.py 管 server 溝通。把這兩層看懂,換到任何框架、任何產品,接法都一樣。
延伸學習
高效思維與腦內模擬:30 日練習與行動系統
每天一件事,三十天把「想到就做」換成「先在腦中跑一遍再動手」。六週依序練目標設定、腦內模擬、結果檢查、反饋與應變、知識萃取、總結與新目標,每天一課圖文,附可以直接填的練習表。週一給概念、週二實作、週三看案例、週四反思、週五收束,跟著節奏走就好,不必自己安排。
NT$ 1,599
HE201|Harness Engineering System Design(6 小時)
六小時的實作課:從 Blueprint 走到可以跑的規格,再用 No-code、n8n 低程式碼與程式碼三條路各做一次同一個 harness,最後處理可靠度——重試、錯誤處理、人工覆核。7 章 54 課,含常見坑與排錯、Capstone 實作,附學員講義 PDF。
NT$ 5,999

