Session 12. MCP architecture and primitives — Tue 29 Sep

Host, client, server, and which one you are writing

Three parts, and the one everybody skips

Week 0 gave you the shape: a host is the application a person uses, a client is one connection inside it, a server is a set of capabilities. The host starts the client, the client starts the server, the server starts nothing.

That is the plumbing. Here is the part the diagram leaves out.

Part Owns Cannot do
Host the model, the system prompt, the conversation, the person see inside a server
Client one connection: the handshake, the listings, every call and result decide what a server offers
Server its tools, resources and prompts, and the code behind them reach the model, except by being read

Read the third column again. The server cannot reach the model. It can only be read by the model — and everything it publishes is read. That single asymmetry is the whole security story of this session, and it is why a description is not documentation.

One client per server

A client is a connection, not a component you write once. Three servers means three clients inside the same host, each with its own handshake, its own listings, its own lifetime.

        host (your assistant)
          |            |            |
      client A     client B     client C
          |            |            |
      server A     server B     server C
      16 tools     30 tools      4 tools

The model does not see three servers. It sees one list of fifty tools, flattened, with no visual break between the one you wrote and the one you installed from a README last Tuesday. Every tool description on that list occupies the same context, at the same trust level, in front of the same model.

That is why the tool count is the number worth writing down. Week 0's third question about a third-party server — surface area — has an answer that is a number, and this is the number.

Which one you are writing today

You have written a server. Unit 9 was forty lines to a running one; unit 11 put a database and a credential behind it. Session 13 goes back to the server side and secures one.

Today you write neither the host nor the server. You write the code a client runs at its boundary: read the handshake, read the listings, decide what this surface is, decide what is safe to put in front of the model. No transport, no async with, no process to start — that part you already did, and repeating it would hide the part you have not done.

Session You write The boundary sits
w09 to w11 a server, and a client that talks to it inside your own code
12 the judgement a client makes about a server between you and a stranger
13 a server other people connect to between you and your callers

The decision the protocol does not make for you

MCP standardises how a server describes itself. It does not standardise whether you should believe it. There is no signature on a tool description, no provenance field, no authority that vouches for read_only: true. The spec's own annotations are documented as hints.

So the protocol hands your client a list and stops. What happens next is application code, and if you do not write it, the default is to trust everything:

tools = await session.list_tools()
# and straight into the model's context, all of it, exactly as received

That line is the default in nearly every MCP client in existence, and for a server you wrote it is fine. For one you did not, it is the decision to trust a stranger, made by not making it.

Where each failure lands

The two failures this session handles land in different places, and neither of them lands on the server.

Failure The server did Your client should
a capability announced with nothing behind it answer the handshake honestly and the listing emptily notice the two disagree, and say so
a description carrying an instruction publish text, which is all it can do read it as data, and refuse to pass it on

In both cases the server is behaving exactly as the protocol allows. Nothing is malformed. Nothing raises. The failure only exists at the client, because the client is the only part that sees both the claim and the evidence.

What a client actually learns on connect

Four things, and it is worth being precise about how thin that is:

You will spend the rest of this session working with those four things, because they are all there is. Session 13 has more to work with — it runs the server — and that difference is exactly why the two sessions are separate.