TL;DR
An MCP connection has two phases. Discover happens once at connect: the client
asks tools/list and the server returns tool definitions. Call happens on every
tool use: the client sends tools/call, the server runs the tool and returns the
result. The model never talks to the server directly — the MCP client does.
Two phases: discover, then call
Discover runs once at connect (tools/list → definitions). Call runs on every tool use (tools/call → result). The agent's MCP client makes both requests.
Discovery happens once, when you connect: the client asks the server "what tools do you have?" and the server replies with a list — each entry a name, a description, and a parameter schema. That's the exact tool shape you wrote by hand in Module 2, except the server wrote it.
// One line replaces a stack of hand-written tool() calls:
const tools = await MCPClient.connect("helpdesk");
// tools is now [lookup_order, list_orders, issue_refund, create_ticket, list_tickets]
Calling happens every time the model uses a tool. The model picks a tool and
fills in the arguments, exactly as before. The difference is the last hop: the MCP
client sends a tools/call request to the server, the server runs the tool and
returns a result, and the client hands that result back to the model. So the answer
to the checkpoint is: the MCP client makes the request, not the model. The model
only ever emits a tool-use request (Module 2); some code always does the actual call.
Analogy
Discovery is reading the menu when you sit down; calling is placing an order. You read the menu once, then order as many times as you like. The waiter (the MCP client) carries every order to the kitchen — you never walk back there yourself.
Follow one call through the trace
The agent loop from Module 2 is unchanged — the model still decides, calls, reads
the result, and continues. MCP only changes how the tool runs: a tools/call
round-trip to the server instead of your local handler. It still surfaces as a tool
span, so the trace reads the same way:
The model never knows it's talking to MCP. From its side, a tool is a tool. The protocol lives entirely between your agent's client and the server.
Common mistake
Picturing the model reaching out over the network to the MCP server. It doesn't —
the model produces a structured tool-use request, and the MCP client in your
agent makes the actual tools/call. Keeping that boundary straight is what lets you
reason about where auth, errors, and latency actually live (your client side).
Key takeaways
Key takeaways
- MCP has two phases: discover (once,
tools/list) and call (per use,tools/call). - Discovery returns the same name/description/schema tool shape — written by the server.
- The MCP client makes the real request; the model only emits a tool-use intent.
- The agent loop and traces look the same; only the tool's execution hop changes.
Go deeper: dynamic discovery means capabilities aren't frozen in your code
Because discovery is dynamic, the agent's capabilities aren't baked into your build:
- New tools appear on reconnect. The Help Desk server could add a
cancel_ordertool tomorrow and your agent would pick it up on the next connect — no redeploy. - Tools can change shape. If the server tightens a parameter schema, the agent discovers the new schema and the model calls it correctly — without you editing a hand-written definition.
- The protocol is JSON-RPC under the hood.
tools/listandtools/callare JSON-RPC 2.0 methods. That's why the same client works against any server and any transport (next lesson) — the message format is fixed even when the connection isn't.
The real shift MCP makes: tools become something you connect to, not something you
write. In the lab you'll see both halves for real — the discovered tool list, and a
genuine tools/call span for every action your agent takes against the sandbox Help
Desk.
