AlgoMaster Logo

Exercise: Building MCP Clients

3 min readUpdated June 22, 2026
Listen to this chapter
Unlock Audio

Exercise 1: Drive the MCP Client Flow

Implement the client side of an MCP session: initialize the connection, list the server's tools, then call one tool and read its result. To keep the exercise self-contained, you talk to a mock transport that returns canned JSON-RPC responses, so you can focus on the request/response sequence rather than networking.

An MCP client follows the same handshake every time: initialize, discover what the server offers, then invoke tools. The real SDK wraps this in stdio_client and ClientSession, but the logic underneath is a sequence of JSON-RPC requests and responses. Driving that sequence by hand is the clearest way to understand what the SDK does for you.

Requirements

  • Send an initialize request and confirm the server responds.
  • Send a tools/list request and print the available tool names.
  • Send a tools/call request for one tool and print the result.
  • Use the provided transport(request) function, which returns the server's JSON-RPC response.
main.py
Loading...

Expected Output

The client completes the handshake, lists tools, and gets a tool result back.

Solution

main.py
Loading...

The request helper builds a JSON-RPC message and hands it to the transport, which is exactly the boundary the real SDK draws between protocol logic and the connection. The handshake order is not arbitrary: a client initializes first, then discovers tools, then calls them, because it cannot invoke a tool it has not learned about. Swapping the mock transport for stdio_client and ClientSession connects this same flow to a real server without changing how you initialize, list, and call.

Exercise 2: Handle a Tool Error and Retry

A JSON-RPC response carries either a result or an error, and a robust client checks which it got. Call a tool with a wrong name, detect the error response, and retry with the correct name. Distinguishing result from error is the basic reliability check every MCP client needs.

Requirements

  • Use the provided mock transport that returns an error object for an unknown tool.
  • Call the tool with a wrong name and check whether the response contains error.
  • On error, retry with the correct name, then print the error message and the final result.
main.py
Loading...

Expected Output

The first call returns a JSON-RPC error; the client detects it and retries with the valid tool name.

Solution

main.py
Loading...

Checking for an error key before reaching for result is mandatory in JSON-RPC, because a response has exactly one of the two. Treating the error as a recoverable signal (retry with a corrected call) rather than a crash is what makes a client resilient to a bad tool name or arguments. Swapping the mock transport for the real stdio_client and ClientSession keeps this same result-or-error handling, which is the part that matters for reliability.