The MCP Handshake

Part of the free Generative AI course on LogicWiz, module: Nova Joins the Network.

Episode 34: The MCP Handshake

Nova connected to the server and went quiet. "What can it even do?" Arjun muttered. Then Nova asked the server exactly that — and it answered with a menu.


Opening the Conversation

Nova binds to one MCP server now instead of a hundred tools. But binding to a server raises an obvious question: how does she find out what's on it, and how does she run something?

Every MCP interaction is the same short conversation. Step through it once and you'll recognise it everywhere:

{{visual:mcp-handshake}}

It always starts with a handshake. The client opens a connection and authenticates — it presents credentials to prove it's an allowed caller. This is the gate: only permitted agents get past it, which is how a server protects sensitive tools. Nothing is trusted until the handshake succeeds.

list_tools: What Can You Do?

Once the handshake succeeds, the client doesn't already know the toolset — it asks. It calls a standard method, list_tools, and the server responds with a catalog describing everything it hosts. For each tool the server sends three things:

  • Name — the tool's unique identifier, e.g. lookup_ticket.
  • Description — a plain-language sentence on what the tool does. This is what the model reads to decide whether to use it.
  • Signature — the arguments the tool needs and their types (ticket_id: str). This is what the model needs to build a valid call.

That bundle — name, description, signature — is the tool's metadata, and it's the only thing the model has to reason with. It never sees the tool's code; it sees the description. (Which is why, back in Episode 33, the docstring mattered so much.)

💡 This is why MCP tool discovery is dynamic. In old direct-binding setups, every tool was hard-coded into the agent ahead of time. With list_tools, the agent asks at runtime — so if the server gains a tool tomorrow, the agent simply sees it in the next catalog. No re-wiring.

call_tool: Please Run This One

Discovery tells the model what's available. To actually use one, the client calls the second standard method: call_tool, passing the chosen tool's name and arguments.

That completes a four-beat loop you'll see in every agent:

Discovery → Intent → Execution → Result. The client discovers tools (list_tools), the model forms an intent (pick a tool + arguments), the server executes it (call_tool), and returns a result the model turns into an answer.

Notice the division of labour hasn't changed since Episode 31: the model only ever expresses intent — "call check_order with A-42". The server does the real execution. MCP just standardises the two messages in the middle so any agent can talk to any server.

The Dispatch Loop, For Real

Let's run the real thing. This time the model faces a menu of tools and has to pick the right one — then our code dispatches to whichever function it named. Walk the code first:

{{visual:mcp-dispatch-walkthrough}}

The new move is dispatch: REGISTRY[call.function.name](**args) looks up the tool the model chose and runs it. That one line is what an MCP server does for you — route a tool name to the tool code. Now run it and watch the model choose check_order over lookup_ticket on its own:

{{cell:l34-dispatch}}

How the Bytes Travel: Transports & JSON-RPC

Two last pieces make MCP concrete: how the messages move, and what shape they're in.

Transports — the channel between client and server:

  • STDIO (standard input/output) — used when client and server run on the same machine. They pipe data through local streams, like one program feeding another. Fast, no network.
  • HTTP — used when the server lives somewhere else on the network. The common choice for remote or shared servers.
  • SSE (server-sent events) — a streaming channel for real-time server-to-client updates; used less often in modern setups.

Data format — whatever the transport, the messages themselves are JSON-RPC: a simple, standard way to encode "call this method with these arguments" and "here's the result." It's what makes list_tools and call_tool machine-readable and consistent. And you rarely touch it — the framework's MCP client formats every message for you.

⚠️ One sharp edge: a running MCP server holds a fixed set of tools. If you change the server's tools, a live agent won't see the change until both restart — because discovery happens at the handshake. Great for stability, but plan for a coordinated restart when you ship new tools.

What Nova Learns Next

Nova can now discover and call tools on any MCP server through one clean loop. But should she always reach for MCP? In Episode 35 we weigh the costs — the extra hop, the latency, the cases where a direct wire is still the smarter choice.