9Model Context Protocol

MCP review

6 min read1,163 words

Eleven lessons ago, "MCP" was a three-letter acronym on a slide. Now you have a working CLI chatbot with a custom MCP server exposing tools, resources, and prompts, plus a custom client that discovers and invokes all three. This lesson steps back and recaps the whole architecture in one piece — how the parts fit together, when to use each primitive, and what you should take away about MCP as an ecosystem.

The architecture, in one picture

Think of MCP as three concentric layers:

  • Your application — a chatbot, a CLI, a web app, an IDE extension. The thing a human uses.
  • The MCP client — a library inside your application that speaks the MCP protocol and handles session management.
  • One or more MCP servers — dedicated processes wrapping external services or custom tooling. Each exposes some mix of tools, resources, and prompts.

Your application talks to the client. The client talks to the servers over whatever transport makes sense (stdio, HTTP, WebSockets). Each server handles its own domain: a GitHub MCP server wraps GitHub, a filesystem MCP server wraps the filesystem, your custom document server wraps your document store.

The application layer doesn't care what's on the other side of the client. It asks for tools, resources, and prompts; whatever the connected servers provide, it gets.

The three primitives

MCP servers expose three kinds of endpoints. Each solves a different problem.

| Primitive | Used by | Purpose | Example | |---|---|---|---| | Tools | Claude (via tool-use protocol) | Actions that change state or fetch dynamic data based on reasoning | read_doc_contents, edit_document, create_github_issue | | Resources | Your application (directly) | Static or parameterised data fetched without Claude's involvement | docs://documents, docs://documents/{doc_id}, users://{user_id}/profile | | Prompts | Your application (on user selection) | Pre-authored, expert-level prompt templates with parameters | /format, /summarise, /write-release-notes |

Knowing which primitive fits a task is a design skill. Three rules of thumb:

Use a tool when Claude needs to decide. The user asks "summarise the document about the condenser tower." Claude has to figure out which document that refers to. Tools let Claude search and read as part of its reasoning.

Use a resource when your application already knows. The user types @report.pdf — the application knows exactly which document they mean. No need to involve Claude in the decision; fetch the resource directly and splice it into the prompt.

Use a prompt when you want to ship an expert-authored template. The user wants to run format on a document. Your MCP server has a carefully-tested prompt for that operation. Ship the template, expose it as a command, save the user from writing their own prompt.

Many operations combine all three. A format prompt (prompt) tells Claude to use the edit_document tool (tool) to apply changes to a document that was referenced via @report.pdf (resource). All three working together is the normal case, not the exception.

Client and server roles, recapped

  • MCP server — owns tool implementations, resource handlers, and prompt templates. Connected to some external service or data source (or, in this module's case, an in-memory dict). Typically written once by a team or developer and consumed by many applications.
  • MCP client — owns the session to one or more servers. Handles the protocol, transport, and resource cleanup. Exposes a simple high-level API (list_tools, call_tool, read_resource, list_prompts, get_prompt) to your application. Typically a thin wrapper around the SDK's ClientSession.

You normally build one side or the other. In real projects:

  • You build an MCP server when you want to expose some capability — your internal APIs, a niche service, a custom data source — to any MCP-capable application.
  • You build an MCP client when you want to consume existing MCP servers from your Claude-powered application.

We built both sides in this module for learning. In production, pick the side that matches what you're shipping and plug into existing work on the other.

Transport options

MCP is deliberately transport-agnostic:

  • stdio — the simplest and most common. The server is a subprocess; the client talks to it through stdin/stdout. Perfect for local development and single-user applications.
  • HTTP — use for remote servers, shared services, or multi-tenant deployments.
  • WebSockets and others — for persistent bidirectional connections over the network.

The protocol messages are identical regardless of transport. You can develop against a stdio server and switch to HTTP later without changing your tool definitions or application logic.

The ecosystem value

Here's the point it all adds up to:

MCP servers are reusable integrations. Once someone writes a GitHub MCP server, every Claude-powered application that needs GitHub can connect to it — IDE extensions, chatbots, agent workflows, documentation tools. The alternative is every one of those applications re-writing the GitHub integration from scratch.

The same applies in reverse: when you ship an MCP server for your own service, every Claude-powered application in your org (or in the world, if you open-source it) can plug in immediately. You write the integration once, you maintain it in one place, and you don't have to chase down every consumer when the upstream API changes — they're reading from your server, not from your old schemas.

This is the economic argument for MCP. Tool use gave us the mechanism for Claude to invoke external functions. MCP gives us the packaging and reuse story that makes that mechanism scale across the ecosystem.

What comes next

In the remaining modules you'll use Claude Code (which is itself an MCP client — you can add MCP servers to it), then build agents and workflows that use tools in more sophisticated ways. Much of what you learned in Module 6 (tool use) and this module (MCP) carries directly into those lessons. The mechanics are the same; the applications get more ambitious.

Take the module quiz when you're confident on the three primitives, the client/server split, and the transport options. Then move on to Claude Code.

Key Takeaways

  • 1MCP splits into three layers: your application, an MCP client that handles protocol and transport, and one or more MCP servers that wrap external services or custom tooling.
  • 2Tools are for actions Claude decides to take; resources are for data your application fetches directly; prompts are for expert-authored templates users invoke by name.
  • 3Many operations combine all three: a prompt directs Claude to use tools against data fetched via resources — that combination is the normal case, not the exception.
  • 4In real projects you build one side of an MCP connection, not both: MCP servers expose capabilities, MCP clients consume them.
  • 5MCP is transport-agnostic — stdio for local, HTTP for shared services, WebSockets for persistent network connections — and the protocol is identical across all of them.
  • 6The ecosystem payoff is reuse: write an integration once as an MCP server and every Claude-powered application can plug in, amortising integration work across projects and teams.