The MCP architecture consists of three layers: hosts, clients, and servers. A host is the AI application the user interacts with (Claude Desktop, an IDE plugin, a custom chatbot). Inside the host, one or more MCP clients manage connections to MCP servers. Each client maintains a 1:1 connection with a single server, handling the protocol lifecycle from initialization through shutdown. Servers expose tools, resources, and prompts to clients over a transport layer. MCP supports multiple transports: stdio for local process communication, and Streamable HTTP for remote server communication. All messages follow the JSON-RPC 2.0 format, providing a language-agnostic, well-structured wire protocol. During initialization, clients and servers negotiate capabilities to establish what features are available for the session.
A host typically manages multiple MCP clients, each connected to a specialized server. This pattern lets the AI model access file system operations, database queries, and API calls through a unified interface. The host aggregates tool lists from all servers and presents them to the model as a single collection. Each client-server connection is independent and isolated.
This shows the complete message flow of an MCP session using JSON-RPC 2.0. Each request has a unique id that the response echoes back, enabling the client to match responses to requests. Notifications lack an id and expect no response. The initialize/initialized exchange must complete before any tool or resource requests. Every message has the jsonrpc: 2.0 version field.
With stdio transport, the client spawns the server as a child process and communicates via stdin/stdout pipes. Environment variables are passed to the child process, which is how servers receive configuration like database URLs and API keys. The cwd option sets the server's working directory. This transport requires no network configuration and works entirely within the local machine.
Streamable HTTP transport connects to remote servers over HTTPS. The client sends JSON-RPC requests as HTTP POST, receives responses in the POST body, and can open a GET-based SSE stream for server-initiated notifications. Session IDs are managed via the mcp-session-id header. The DELETE method terminates the session. This transport works with standard HTTP infrastructure including load balancers, CDNs, and authentication proxies.
After initialization, the client should check the server's declared capabilities before calling any methods. This prevents errors from calling unsupported methods and allows the host to adapt its behavior based on what each server offers. For example, a server that only exposes tools will not have a resources capability, so the host should skip resource listing for that server.
Assuming all MCP servers run on the same transport. Developers hardcode stdio assumptions and then cannot connect to remote HTTP servers, or vice versa.
Design your host/client code to support multiple transports. Use configuration (like Claude Desktop's mcpServers config) to specify the transport per server. The MCP client SDK handles the transport abstraction -- just instantiate the correct transport class.
Sending requests before the initialization handshake completes. For example, calling tools/list immediately after connecting without waiting for the initialize response and sending notifications/initialized.
Always follow the initialization sequence: send initialize request, wait for the response, send notifications/initialized, then proceed with normal requests. The SDK handles this automatically when you call client.connect(), but if you are implementing the protocol manually, the order is critical.
Exposing an MCP HTTP server on a public network without authentication or TLS, allowing anyone to invoke tools and read resources.
Always use HTTPS (TLS) for remote MCP servers. Add authentication middleware (API keys, OAuth, JWT) to the HTTP transport. The MCP protocol itself does not define authentication -- it is the server operator's responsibility to secure the transport layer.
Treating the client-server relationship as many-to-one. Developers try to have multiple clients share a single transport or server instance, causing message routing conflicts.
Each MCP client maintains exactly one connection to one server. If you need multiple servers, create multiple client instances. The Streamable HTTP transport supports multiple clients through session management, but each session is still a distinct 1:1 connection.
Ignoring JSON-RPC error codes and treating all errors the same, missing the distinction between parse errors (-32700), invalid requests (-32600), method not found (-32601), and internal errors (-32603).
Handle different JSON-RPC error codes appropriately. Method not found (-32601) means the server does not support that capability -- check capabilities. Invalid params (-32602) means bad arguments -- fix the request. Internal error (-32603) means a server-side failure -- retry or report.
The MCP architecture is built on three layers: hosts (AI applications), clients (protocol session managers), and servers (capability providers). Communication uses JSON-RPC 2.0 messages over pluggable transports -- stdio for local processes and Streamable HTTP for remote servers. During initialization, clients and servers negotiate capabilities to establish what features are available. A single host can manage multiple clients, each connected to a different server, aggregating tools, resources, and prompts into a unified interface for the AI model. Security is transport-dependent: stdio inherits process permissions, while HTTP requires explicit authentication and TLS.
Interactive lessons and challenges on Stanza, practice in VS Code, Cursor, or the web.
Interactive lessons and challenges, right in your code editor.
Check the free courses. No credit card.