How MCP Clients Work — Connecting AI to Servers

How MCP Clients Work — Connecting AI to Servers

2026-03-24

The MCP server exposes capabilities. The MCP client is the component inside the AI application that discovers, connects to, and communicates with servers. Every AI application that supports MCP — Claude Code, Cursor, VS Code, ChatGPT — contains MCP client logic.

The client is not the user. The client is the software that manages the connection on behalf of the AI model.

One Client Per Server

A host application creates one MCP client for each server it connects to. If Claude Code is configured to use three MCP servers (filesystem, GitHub, database), it creates three independent clients — each maintaining its own connection, its own capability set, and its own lifecycle.

This isolation is deliberate. A failure in the GitHub server doesn't affect the filesystem connection. A slow database query doesn't block tool discovery on the filesystem server.

The Initialization Handshake

Before anything useful happens, the client and server must agree on what they support. This happens through a capability negotiation handshake — similar in concept to a TLS handshake.

Client Server initialize protocolVersion + client capabilities initialize response protocolVersion + server capabilities + serverInfo notifications/initialized client confirms ready Connection established tools/list, resources/list, prompts/list discovery begins

Step 1: The client sends initialize with its protocol version and capabilities. Client capabilities tell the server what the client supports — for example, elicitation (the server can ask the user for input) or sampling (the server can request LLM completions).

Step 2: The server responds with its protocol version, capabilities, and server info. The client now knows exactly what this server offers: tools, resources, prompts, and which notification features are supported.

Step 3: The client sends notifications/initialized — a notification (no response expected) confirming the handshake is complete.

If the protocol versions are incompatible, the connection fails here. No ambiguity, no partial connections.

Discovery

After initialization, the client discovers what the server offers:

tools/list      → [{ name, description, inputSchema }, ...]
resources/list  → [{ uri, name, mimeType }, ...]
prompts/list    → [{ name, description, arguments }, ...]

The client stores this information in a registry. When the AI model needs to decide which tools to use, the client provides the registry — the model sees all available tools across all connected servers.

Discovery is dynamic. If the server declared listChanged: true in its capabilities, it can send notifications/tools/list_changed at any time. The client responds by re-fetching the tool list. Tools can appear and disappear based on server state, user permissions, or external conditions.

Routing Tool Calls

When the AI model decides to call a tool, the flow is:

  1. Model outputs a tool call — the model generates a structured tool call (name + arguments) based on the conversation
  2. Host intercepts — the AI application catches the tool call before execution
  3. Client routes — the host finds which client (which server) owns this tool
  4. Client sends tools/call — the request goes to the correct server
  5. Server executes and returns — the result comes back through the client
  6. Host feeds result to model — the tool result becomes context for the next model response

The client is the router. The model doesn't know which server a tool belongs to. The host manages the mapping.

Client Capabilities

Clients can also expose capabilities TO servers:

Sampling — the server can request the client's AI model to generate a completion. This is powerful: an MCP server can ask the AI to reason about something without embedding its own LLM. The server stays model-agnostic.

Elicitation — the server can ask the user for input. "Please confirm you want to delete this file." The host shows the prompt to the user and returns the response to the server.

Roots — the client can declare which project roots (directories, repositories) are relevant. Servers use this to scope their operations — a filesystem server only shows files within the declared roots.

Error Handling

The client handles two types of errors:

Protocol errors — invalid JSON-RPC, unknown methods, malformed requests. These are standard JSON-RPC error responses with error codes.

Server failures — the server crashes, becomes unresponsive, or returns unexpected data. The client should handle this gracefully — timeout, retry logic, and fallback to operating without that server's capabilities.

A well-built client never crashes the host application because of a misbehaving server. The isolation (one client per server) is the defense.

What the User Sees

The user doesn't see MCP clients. They see:

  • A list of connected tools in their AI application's settings
  • Tool call indicators during conversations ("Using GitHub: create_issue...")
  • Confirmation prompts for sensitive operations
  • Error messages when a server fails

The client is invisible infrastructure. The user experience is "my AI can do X" — the MCP client is how "X" actually happens.

Next Steps