Agent 與 MCP

把 MCP 接進 Claude:client 實作與整合全流程

把 MCP 接進 Claude 有兩條路:用現成的 MCP client,例如 Claude 桌面應用與 Claude Code,設定好 server 就能用;或在自己的應用裡實作 client,透過 SDK 的 session 呼叫 list_tools 與 call_tool 取得並執行工具,把結果接回 Claude API 的 tool use 對話迴圈。
把 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 的介面,就繞著這兩件事設計。

使用者 提問 你的應用 問題+工具清單、結果往返 Claude 取得 / 執行工具 MCP client ListTools / CallTool MCP server 背後再連向外部服務
上排是與 Claude 的對話迴圈,下排是與 MCP server 的工具通道,你的應用站在中間把兩邊接起來。

兩個核心方法: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_nametool_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 這份文件的內容是什麼?」,背後發生的事:

  1. 你的應用用 client 取得可用的工具清單。
  2. 工具清單連同問題一起送給 Claude。
  3. Claude 決定使用 read_doc_contents 工具,回覆 tool use 請求。
  4. 你的應用用 client 執行該工具,拿到文件內容。
  5. 結果回傳給 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

從使用者眼裡看,整條路是這樣:

  1. 輸入 @,畫面列出可選的資源清單做自動完成。
  2. 選定文件,送出訊息。
  3. 應用自動抓取該資源的內容,直接塞進 prompt。
  4. 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 溝通。把這兩層看懂,換到任何框架、任何產品,接法都一樣。

記住分工真實專案裡你通常只寫其中一邊:要把自家服務開放給大家,寫 server;要讓自家應用用上別人的服務,寫 client;只是想在 Claude 裡用某個服務,兩邊都不用寫,設定現成的 client 就好。
參考出處本文取材自 Anthropic 官方 Claude Academy 免費課程「Building with the Claude API」,由酒Ann 消化後以自己的視角重新編寫。想看英文原版課程,可到 Claude Academy 修習。

延伸學習

把這篇文章分享給需要的人FacebookLINEThreadsX

常見問答

我需要同時寫 client 跟 server 嗎?
通常不用。要開放自家服務給別人接,寫 server;要在自家應用裡使用現成服務,寫 client。教學專案兩邊都寫,只是為了看懂它們怎麼配合。
Claude 桌面應用跟 Claude Code 算 MCP client 嗎?
算。它們內建了 client 的角色,設定好要連的 MCP server 之後,server 提供的工具與資源就能直接在對話中使用,不必自己寫程式。
client 拿到工具清單之後做什麼?
把工具清單連同使用者的問題一起送給 Claude。Claude 決定要呼叫哪個工具時,client 再透過 call_tool 執行,並把結果回傳給 Claude 完成回答。
resources 跟工具呼叫拿資料差在哪?
resources 由應用主動抓取,內容直接放進 prompt,Claude 不必再發工具呼叫,互動更快;工具呼叫則由 Claude 在對話中自主決定,多一來一回。