載入中

現在我們的 MCP 伺服器已經可以運作了,接下來該建構客戶端了。客戶端是讓我們的應用程式能夠與 MCP 伺服器通訊並存取其功能的部分。

了解客戶端架構

在深入程式碼之前,讓我們先澄清一個關於 MCP 專案的重要觀點。通常,您會實作 MCP 客戶端或 MCP 伺服器其中之一——而不是兩者都實作。我們在這個專案中同時建構兩者,只是為了讓您能看到它們如何協同運作。

MCP 客戶端由兩個協同運作的主要元件組成:

  • MCP Client - 我們建立的自訂類別,用於讓使用 session 更容易
  • Client Session - 與伺服器的實際連線(屬於 MCP Python SDK 的一部分)

client session 處理低層級的通訊,但在您的程式關閉時需要謹慎地清理資源。這就是為什麼我們將它包裝在自己的類別中——以自動管理該清理工作。

客戶端如何融入我們的應用程式

還記得我們的應用程式流程圖嗎?客戶端在兩個關鍵時刻扮演著至關重要的角色:

我們的 CLI 程式碼使用客戶端來:

  • 取得可用工具清單以傳送給 Claude
  • 在 Claude 請求時執行工具

實作核心客戶端函式

讓我們來實作兩個必要的函式:list_tools 和 call_tool。

對於 list_tools,我們需要連接到我們的 session 並請求可用的工具:

python
async def list_tools(self) -> list[types.Tool]:
    result = await self.session().list_tools()
    return result.tools

對於 call_tool,我們將工具名稱和輸入參數傳遞給伺服器:

python
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 會為我們處理所有複雜的通訊細節。

測試客戶端

客戶端檔案底部包含一個簡單的測試工具。您可以直接執行它來驗證一切是否正常運作:

bash
uv run mcp_client.py

這將連接到您的 MCP 伺服器並印出可用的工具。您應該會看到顯示工具定義的輸出,包括名稱、描述和輸入結構。

重要的結構差異

這裡有一個您需要知道的陷阱:MCP 工具定義與 Claude 所期望的並不完全相符。MCP 規格有自己的工具結構格式,這與 Bedrock 所要求的略有不同。

別擔心——專案中已經有程式碼能自動處理這種轉換。core/bedrock.py 中的 to_bedrock_tools 函式會將 MCP 工具定義轉換為 Claude 能理解的格式。

與 Claude 進行測試

現在伺服器和客戶端都已經可以運作了,您可以測試完整的流程。試著執行您的主應用程式,並要求 Claude 讀取一份文件:

bash
uv run main.py

然後詢問:「report.pdf 文件的內容是什麼?」

Claude 將會:

  1. 從您的客戶端接收可用工具清單
  2. 決定使用 read_doc_contents 工具
  3. 您的客戶端將在 MCP 伺服器上執行該工具
  4. Claude 將接收文件內容並做出回應

客戶端充當您的應用程式程式碼與 MCP 伺服器之間的橋樑,讓您能輕鬆地將伺服器功能公開給 Claude 和系統的其他部分。