C.W.K.
Stream
Lesson 03 of 05 · published

Host, Client, Server

~24 min · host, client, server, topology

Level 0Curious Reader
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

MCP's architecture is a triangle. Three roles, three responsibilities, and a strict rule about who talks to whom.

  • Host — the application the user actually uses. Claude Desktop, VS Code with Copilot, Cursor, your custom assistant. The host owns the user experience, runs the LLM (or the API call to it), and is responsible for security decisions like asking the user to approve tool runs.
  • Client — a piece of code inside the host that speaks MCP to one server. A host that uses three MCP servers maintains three client objects, one per connection. Clients are paired 1:1 with servers; they are not pooled.
  • Server — a separate process (or remote service) that exposes tools, resources, and prompts to a client. A weather server, a GitHub server, a Postgres server. Servers know nothing about each other; they each speak only to their paired client.

The strict rule is: a server never talks to another server, and a server never reaches the host directly. All cross-server coordination goes through the host. This is on purpose. It keeps every server's blast radius bounded — the worst a malicious or buggy server can do is misbehave to the one client that hosts it. The host is the security boundary; the protocol enforces it by topology.

Two consequences fall out of this. First, capability composition is the host's job: if the user asks "look up this user in Postgres and post their summary to Slack," the host orchestrates one tool call to the Postgres server, then one to the Slack server. Neither server learns about the other. Second, permissions are per-server: granting "read code" to a GitHub server does not grant the same to a filesystem server, and vice versa. The triangle is the trust model.

Code

Host with two MCP servers — two clients, no cross-talk·python
# Pseudocode for a host runtime
from mcp.client.stdio import stdio_client
from mcp.client.session import ClientSession

async def host_runtime():
    # One client per server. Each session is independent.
    github_session  = await connect_to_server("github_mcp", argv=["uvx","github-mcp"])
    postgres_session = await connect_to_server("postgres_mcp", argv=["uvx","postgres-mcp","--dsn","..."])

    # The HOST orchestrates. Servers do not talk to each other.
    github_data   = await github_session.call_tool("search_issues", {"query": "..."})
    postgres_data = await postgres_session.call_tool("query", {"sql": "select ..."})
    return summarize(github_data, postgres_data)

External links

Exercise

Sketch your favorite MCP-using product (Claude Desktop, Cursor, your own assistant) as a triangle: name the host, list every server it uses, and draw the per-server client connections. Notice that the diagram has no arrow between any two servers. That missing arrow is the security model.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.