Building MCP Servers & Clients: overview
- Source
- From the RAG & Agents Engineering course
- By
- Sourav Banerjee
- Last updated
- 8 Nov 2026
Larkspur connects more than one MCP server and makes repeated tool calls. You will inspect name ownership, partial failures and session lifetime, then trace where responses travel over SSE and Streamable HTTP. The tutorials cover multi-server clients, held sessions and the two HTTP transports.
The running example is the module's lab brief applied to Larkspur Cloud, the fictional host whose handbook runs through T5.1 to T5.3: a support assistant with two MCP servers. handbook wraps a retriever over the handbook (search_handbook), and status stands in for web search over Larkspur's status pages (search_status, canned results, no network). The golden questions are How long does a refund take?, which belongs to the handbook, and Is there an outage right now?, which belongs to the status pages. Every count on these pages was recorded by driving those two servers through the installed SDK: mcp 1.30.0 and langchain-mcp-adapters 0.3.2.
In short
- A multi-server client keeps one session per server and merges their tools into one list for the model. Tool names must be unique across servers;
tool_name_prefix=Trueturnssearchintohandbook_search. - A session is one
initializehandshake followed by requests over the same transport until it closes. Over stdio a session is a server process. MultiServerMCPClient.get_tools()opens a new session for every tool call. Over stdio, 8 calls start 10 server processes and send 38 JSON-RPC messages; one held session per server needs 2 processes and 14 messages.- SSE keeps a
GET /ssestream open for every reply and answers each POST with202 Accepted. Streamable HTTP answers each POST on/mcpitself and ties requests together with anmcp-session-idheader. stateless_http=Truedrops the session id, the server-to-client stream and the closingDELETE: 8 held calls cost 14 HTTP requests instead of 18, and the server keeps nothing between requests.
Mental model
- The client opens one session per server. Over stdio that starts the handbook server as a child process; over HTTP it posts to a server that is already running.
- Each session starts with an
initializehandshake and the initialized notification. - Each session sends
tools/list. The handbook listssearch_handbook; the status server listssearch_status. - The client merges both into one list. The model never learns there are two servers.
- A question comes in, How long does a refund take?, and the model picks
search_handbookby its description. - The call goes down the session of the server that listed the tool. Held open, that session serves every later call without another handshake.
The client is the only piece that knows there are two servers. The model sees one list of tools, and each call goes back down the session of the server that listed the tool. Everything in T12.2 is about the middle column: how many sessions there are, how long each one lives, and what carries its messages.
Interactive lab
Sessions on the wire: open the file in a browser. Start with stdio and held sessions, and slide the tool calls to 8: 2 server processes, 14 messages. Switch the client to get_tools(): 10 processes and 38 messages, and every call lands on a process that has never seen the one before it. Then try Streamable HTTP with each client, and the stateless server, to see what each transport adds per call.
How it connects
- Before: T12.1 builds the first server and client, the three things a server offers, and a remote server over SSE. T7.1 builds the tool-calling loop the clients here run, and T9.4 makes retrieval a tool, the job the
handbookserver does behind a protocol. - Next: T12.3 builds MCP applications and RAG over MCP on these clients and transports. T12.4 moves from tools to agents with the A2A protocol.
Key Takeaways
- Give each server one session and hold it for the life of the agent. A session per call costs a handshake every time, and over stdio a process, and loses whatever the server kept in memory.
- Merge tools from several servers into one list only after checking names: prefix them by server, and give each a description that says which questions it answers.
- Pick the transport by where the server runs: stdio for a local subprocess, Streamable HTTP for anything shared, and stateless mode when replicas must answer any request.
- Treat an MCP server that runs commands as a remote shell. Narrow tools, authentication and a sandbox come before the first deployment.