MCP Architecture Explained: Host, Client, Server and Transports

To test something well, you must know how its parts talk to each other. MCP architecture has only a few parts, and each has a clear job. In this lesson you will follow one tool call from start to finish, using a small program that you can run yourself.

📖 What You’ll Learn

  • What the host, client and server each do
  • How messages travel between them
  • The difference between stdio and Streamable HTTP
  • What changed in the 2026-07-28 protocol

💡 MCP Architecture: The Three Parts

Explain Like I’m 5: Ordering by Phone

Imagine: You want pizza. Your parent holds the phone and speaks to the shop. The shop makes the pizza.

What it really means: The host is the app, the client handles the call and the server does the work.

In testing: An AI assistant asks a browser server to read a page.

PartJobQA example
HostThe AI application the user works inAn AI coding assistant
ClientKeeps the connection to one serverThe assistant’s link to the browser server
ServerOffers the tools and does the workPlaywright MCP

One host can have several clients, and each client talks to one server. The model does not connect to the server directly. It asks the host, and the host’s client makes the call.


🔍 How One Tool Call Travels

  1. The client asks the server for its tools with tools/list.
  2. The host gives those tool descriptions to the model.
  3. The model asks to use a tool.
  4. The host can ask a person to approve it.
  5. The client sends tools/call to the server.
  6. The server runs the tool and returns the result.
  7. The host gives the result back to the model.

Step 4 is your safety point. You met this same idea in the agent loop.


🧩 Two Ways to Connect

Explain Like I’m 5: Talking or Posting

Imagine: You can talk to someone sitting next to you, or post a letter to someone far away.

What it really means: Stdio is for a local helper, and HTTP is for a server elsewhere.

In testing: Run a test helper on your laptop, or share a team server.

PointstdioStreamable HTTP
Where it runsOn the same machineOn a local or remote server
Who starts itThe client starts it as a processIt runs independently
How messages moveOne JSON message per lineEach message is an HTTP POST
Main riskIt runs with your local accessIt is reachable over a network

Never print to stdout in a stdio server

On stdio, the output stream carries only protocol messages. One stray console.log can break the connection. Write your logs to stderr instead.


🛠️ See the Messages

MCP messages use a format called JSON-RPC. This small program has no dependencies. It is a simplified model of a stdio exchange, with text passing in and out one line at a time.

type RpcRequest = {
  jsonrpc: '2.0';
  id: number;
  method: string;
  params: {
    name?: string;
    arguments?: Record<string, string>;
    _meta: { 'io.modelcontextprotocol/protocolVersion': string };
  };
};

const VERSION = '2026-07-28';

// The server: one line in, one line out.
function server(line: string): string {
  const req = JSON.parse(line) as RpcRequest;
  const reply = (body: object) => JSON.stringify({ jsonrpc: '2.0', id: req.id, ...body });

  if (req.params._meta['io.modelcontextprotocol/protocolVersion'] !== VERSION) {
    return reply({ error: { code: -32022, message: 'Unsupported protocol version' } });
  }
  if (req.method === 'tools/list') {
    return reply({ result: { resultType: 'complete', tools: [{ name: 'get_run_status' }] } });
  }
  if (req.method === 'tools/call' && req.params.name === 'get_run_status') {
    const text = `Run ${req.params.arguments?.runId}: 2 failed`;
    return reply({ result: { resultType: 'complete', content: [{ type: 'text', text }] } });
  }
  return reply({ error: { code: -32602, message: 'Unknown tool' } });
}

// The client: sends a request and reads the reply.
let nextId = 1;
function send(method: string, extra: object = {}, version = VERSION) {
  const params = { ...extra, _meta: { 'io.modelcontextprotocol/protocolVersion': version } };
  return JSON.parse(server(JSON.stringify({ jsonrpc: '2.0', id: nextId++, method, params })));
}

console.log(send('tools/list').result.tools[0].name);
console.log(send('tools/call', { name: 'get_run_status', arguments: { runId: '17' } }).result.content[0].text);
console.log(send('tools/call', { name: 'delete_everything' }).error.code);
console.log(send('tools/list', {}, '2020-01-01').error.code);
get_run_status
Run 17: 2 failed
-32602
-32022

Real responses have a few more required fields, and real projects use an SDK. You will use one in Build an MCP Server for QA.


📌 What Changed in the 2026-07-28 Revision

Explain Like I’m 5: No More Name Badges

Imagine: Instead of checking in at the door once, every note you pass says who you are.

What it really means: Each request now carries its own version and details.

In testing: A server can handle any request without remembering the last one.

Older revisions2026-07-28 revision
Start with an initialize handshakeNo handshake, details travel in _meta
Sessions tied to a connectionNo protocol-level sessions
Server could start requestsServer answers, and asks for input in its results

Many servers and clients still use the older style. Modern and older software do not always work together, so check the versions when a connection fails.


🌍 Real-Life Example: The Silent Server

A tester adds a debug message to a local MCP server. The server starts, but the assistant reports a connection error. The stray message went to stdout and broke the protocol stream. Moving the message to stderr fixes it immediately.


🧪 Try It Yourself

  1. Run the example with npx tsx messages.ts.
  2. Add a second tool to the server.
  3. Print the raw JSON line for one request.
  4. Find the id in the request and the matching response.
  5. Change the version and read the error code.

📋 Ready-to-Copy Prompt

You are an MCP expert teaching a software tester.

Here is a JSON-RPC message from an MCP connection:
[paste a message with no secrets]

Explain in simple words:
1. Who sent it: the client or the server
2. What it is asking for or returning
3. Which fields a tester should check
4. What a bad version of this message might look like

Check your answer against the 2026-07-28 revision. Tell me if you are unsure.

⚠️ Common Mistakes

  • Thinking that the model connects directly to the server
  • Mixing up the host and the client
  • Writing logs to stdout on a stdio server
  • Exposing an HTTP server without authentication
  • Debugging with a guide written for an older revision

🎯 Key Takeaways

  • The host is the app, and the client talks to one server.
  • Tools are discovered with tools/list and run with tools/call.
  • Use stdio locally and Streamable HTTP for shared servers.
  • The newest revision carries its details in every request.

🎤 Interview Questions

1. Explain the host, client and server in MCP.

Model answer: The host is the AI application. It creates a client for each server, and the client manages that connection. The server exposes the tools and carries out the work.

2. What are the MCP transports?

Model answer: The standard transports are stdio and Streamable HTTP. Stdio suits a local process started by the client. Streamable HTTP suits a server that runs independently and may be shared.

3. Why must a stdio server not write logs to stdout?

Model answer: Stdout is reserved for protocol messages, so anything else can corrupt the stream. Logs should go to stderr.

4. What changed in the 2026-07-28 revision?

Model answer: The handshake and protocol-level sessions were removed. Each request carries its own version and capability details in metadata, which makes servers stateless at the protocol level.

5. How would you debug a failed MCP connection?

Model answer: I would check the launch command, the protocol versions and the server’s stderr output. I would also look for stray stdout output, then call tools/list from a test client.


📝 Assignment

Draw the path of one tool call for an AI assistant using a test-report server. Label the host, client, server, transport and human approval point. Then list one failure that could happen at each arrow.


❓ FAQ

Do I need to write JSON-RPC by hand?

No. SDKs handle it for you. Reading the messages is still useful when you are debugging.

Can one AI application use several MCP servers?

Yes. It creates one client for each server. Remember that each extra server adds more tools and more risk.


🚀 Next Steps

Well done on finishing this lesson. Complete the assignment, then continue with Playwright MCP Workflow for Testers: Explore Safely, Then Automate.