Course: Introduction to Model Context Protocol
Mirrors: Anthropic Academy — Introduction to Model Context Protocol · https://anthropic.skilljar.com/introduction-to-model-context-protocol Audience: Developers. Comfortable with Python and JSON. · Time: ~75 min + project Prereqs: Python 3.10+, API basics, a terminal. · Backing notes: mcp-overview, mcp-tools, mcp-resources, mcp-prompts, mcp-server-python, mcp-transports Project: p12-build-an-mcp-server
MCP is the open standard that lets Claude plug into your systems — files, databases, APIs, internal tools — without you re-implementing tool plumbing for every app. By the end you can explain why MCP exists, name its three primitives and who controls each, and build and wire up a working Python server.
Learning objectives
After this course you can:
- Explain the M×N integration problem MCP solves (the "USB-C for AI tools" pitch).
- Diagram the architecture: host, client, server, and the JSON-RPC connection between them.
- Distinguish the three server primitives — tools, resources, prompts — by who controls each.
- Pick the right transport (stdio vs Streamable HTTP) for a deployment.
- Build a server in Python with FastMCP exposing one tool, one resource, and one prompt.
- Wire that server into Claude Code via a
.mcp.jsonfile and call it.
Module 1 — Why MCP exists
🎞 Frame 1 · The M×N integration problem · ⏱ ~3 min
🎬 Scene — A grid fills the screen: M AI apps down the side, N tools across the top. Every cell is a custom integration someone has to write and maintain.
🧠 Concept — Before MCP, every AI application wired up every tool with bespoke glue code. M apps × N tools = M×N integrations. MCP turns that into M + N: each app speaks MCP once, each tool exposes MCP once, and they all interoperate.
🖼 On screen
Without MCP: Claude Desktop ──┐
Cursor ──────────┼── each writes its own
your app ────────┘ Slack + GitHub + Postgres + ... glue
With MCP: any MCP host ──→ [MCP] ──→ any MCP server
write the connector ONCE on each side
✅ Checkpoint — Why is "M + N" dramatically better than "M × N" as the tool ecosystem grows?
🎞 Frame 2 · USB-C for AI tools · ⏱ ~2 min
🎬 Scene — A laptop with one USB-C port; monitors, drives, and chargers all plug into the same connector.
🧠 Concept — MCP is a standard connector, not a tool. Standardize the plug and any compliant tool plugs into any compliant client. Anthropic released MCP as an open protocol in late 2024; it's now adopted broadly. (Deeper: mcp-overview.)
🖼 On screen
| Aspect | Raw API tool use | MCP |
|---|---|---|
| Where the tool lives | In your app code | In a separate server |
| Reusability | Per-app | Any MCP-aware client |
| Discovery | Hardcoded | Server advertises capabilities |
| Ecosystem | None | Growing registry (Slack, Linear, Postgres…) |
✅ Checkpoint — In one sentence, what does standardizing the "connector" buy a tool author?
🎞 Frame 3 · Two layers: data and transport · ⏱ ~2 min
🎬 Scene — A diagram splits into an inner ring ("what is said") and an outer ring ("how it travels").
🧠 Concept — MCP separates what from how. The data layer is JSON-RPC 2.0 (lifecycle, primitives, notifications). The transport layer (stdio or Streamable HTTP) just carries those messages. Same message format on every transport.
🖼 On screen
Data layer → JSON-RPC 2.0: initialize, tools/call, resources/read, prompts/get …
Transport layer → stdio (local subprocess) | Streamable HTTP (remote service)
✅ Checkpoint — If you switch a server from stdio to Streamable HTTP, do the JSON-RPC messages change? (No — only the transport.)
Module 2 — Architecture and the three primitives
🎞 Frame 4 · Host, client, server · ⏱ ~3 min
🎬 Scene — A host application (Claude Code) holds several "client" sockets, each running a dedicated wire to a different server.
🧠 Concept — Three roles: the host is the AI app, it spins up one client per connection, and each client talks to exactly one server. A host can run many clients at once. (Deeper: mcp-overview.)
🖼 On screen
flowchart TB
subgraph Host["MCP Host (e.g. Claude Code)"]
C1[MCP Client 1]
C2[MCP Client 2]
end
SA["Server A (local, stdio)<br/>Filesystem"]
SB["Server B (remote, HTTP)<br/>GitHub"]
C1 -- dedicated connection --> SA
C2 -- dedicated connection --> SB
✅ Checkpoint — How many servers does a single MCP client connect to? (Exactly one — the host runs one client per server.)
🎞 Frame 5 · Tools — model-controlled · ⏱ ~3 min
🎬 Scene — Mid-conversation, Claude decides on its own to call
search_ticketsand shows the result inline.
🧠 Concept — Tools are actions the model chooses to invoke. They can have side effects. Each has a name, a description that teaches when to use it, and a JSON input schema. (Deeper: mcp-tools.)
🖼 On screen
Tool(
name="search_tickets",
description="Search Linear tickets by query. Use when the user asks about tickets, issues, or bugs.",
inputSchema={
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
)
⚠️ Gotcha — A vague description makes the model pick the wrong tool. Say when to use it and when not to.
✅ Checkpoint — Who decides a tool runs — the user, the host, or the model? (The model.)
🎞 Frame 6 · Resources — application-controlled · ⏱ ~3 min
🎬 Scene — A picker UI lists "Users table", "design.md", "current screenshot"; the user attaches one as context.
🧠 Concept — Resources are read-only data identified by a URI (file://…, postgres://…). Claude doesn't "call" a resource; the host application surfaces them and the user/app attaches them to context. No side effects. (Deeper: mcp-resources.)
🖼 On screen
Resource(
uri="postgres://main/users",
name="Users table",
description="Production users; PII redacted on read.",
mimeType="application/json",
)
✅ Checkpoint — "Get me X, no decision required" → resource or tool? (Resource.)
🎞 Frame 7 · Prompts — user-controlled · ⏱ ~2 min
🎬 Scene — The user types
/review_prand a slash-command menu pops up offering apr_urlargument.
🧠 Concept — Prompts are parameterized message templates the user invokes, usually as slash commands. The server returns ready-to-send messages, often pre-filled with data (e.g., the PR diff). (Deeper: mcp-prompts.)
🖼 On screen
| Primitive | Decided by | Surfaced as |
|---|---|---|
| Tools | Model | Tool calls in conversation |
| Resources | Application / host | Attached context, picker UI |
| Prompts | User | Slash command menu |
✅ Checkpoint — Without looking, match each primitive to who controls it. (Tools→model, Resources→app, Prompts→user.)
Module 3 — Transports
🎞 Frame 8 · stdio: the local default · ⏱ ~2 min
🎬 Scene — The host launches the server as a subprocess; messages flow over stdin/stdout.
🧠 Concept — stdio is for servers that run as a local subprocess of the client (Claude Code, Claude Desktop). No ports, no auth — easiest dev experience. (Deeper: mcp-transports.)
⚠️ Gotcha — With stdio, stdout is the wire. Never print() from the server; log to stderr or you corrupt the protocol.
✅ Checkpoint — Why must a stdio server avoid printing to stdout?
🎞 Frame 9 · Streamable HTTP: the remote standard · ⏱ ~2 min
🎬 Scene — A cloud-hosted server serves a fleet of users behind one HTTP endpoint.
🧠 Concept — Streamable HTTP is the current standard for remote servers. A single HTTP endpoint; requests are POSTed, responses can be JSON or an SSE stream. Supports sessions and OAuth. (SSE is the legacy variant it supersedes.)
🖼 On screen
| Transport | Local | Remote | Multi-client | Auth |
|---|---|---|---|---|
| stdio | ✅ | ❌ | ❌ | No |
| Streamable HTTP | ⚠️ | ✅ | ✅ | Yes |
✅ Checkpoint — You must expose an internal server to many users without each installing it. Which transport? (Streamable HTTP, with OAuth.)
🎞 Frame 10 · Local vs remote is about transport · ⏱ ~2 min
🎬 Scene — Two servers, same code; one labeled "local", one "remote" — the only difference is how they're connected.
🧠 Concept — "Local" vs "remote" is decided by transport, not where the code physically runs. stdio ⇒ local subprocess; Streamable HTTP ⇒ remote service.
✅ Checkpoint — What single property determines whether an MCP server is "local" or "remote"? (Its transport.)
Module 4 — Build and wire up a server
🎞 Frame 11 · FastMCP: server in 15 lines · ⏱ ~3 min
🎬 Scene —
pip install mcp, a handful of decorators, and a working server appears.
🧠 Concept — The high-level FastMCP API hides the JSON-RPC boilerplate. A decorated function's name + docstring become the primitive's name + description; type hints become the JSON schema. (Deeper: mcp-server-python.)
🖼 On screen
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("hello-mcp")
@mcp.tool()
def echo(text: str) -> str:
"""Echo a string back. Use to verify the server is reachable."""
return text
@mcp.resource("file://greeting")
def greeting() -> str:
"""A static greeting."""
return "Hello, world!"
@mcp.prompt()
def summarize(text: str) -> str:
"""Produce a summary prompt."""
return f"Summarize:\n\n{text}"
if __name__ == "__main__":
mcp.run()
✅ Checkpoint — Where does FastMCP get a tool's description from? (The function's docstring.)
🎞 Frame 12 · One tool, one resource, one prompt · ⏱ ~3 min
🎬 Scene — The three decorators above are highlighted in turn, each labeled with who controls it.
🧠 Concept — A complete starter server exposes exactly one of each primitive so you internalize the difference: @mcp.tool() (model-controlled action), @mcp.resource() (app-controlled read), @mcp.prompt() (user-controlled template).
🖼 On screen
@mcp.tool() → model invokes → can have side effects
@mcp.resource() → user/app attaches → read-only, URI-addressed
@mcp.prompt() → user runs (slash) → returns seed messages
✅ Checkpoint — Which of the three would you reach for to let Claude write a row to a database? (A tool.)
🎞 Frame 13 · Wire it into Claude Code with .mcp.json · ⏱ ~3 min
🎬 Scene — A
.mcp.jsonfile at the repo root; Claude Code restarts and the new tools appear.
🧠 Concept — Claude Code reads a .mcp.json at the project root listing servers under mcpServers. For a local stdio server you give the command and args to launch it; project-scoped config is committed so the whole team gets the server.
🖼 On screen
{
"mcpServers": {
"hello": {
"command": "python",
"args": ["server.py"]
}
}
}
🛠 Try it now — Add the block above, run claude, and ask Claude to call the echo tool. Use npx @modelcontextprotocol/inspector python server.py to poke the server directly if it doesn't show up.
✅ Checkpoint — What file tells Claude Code which MCP servers to launch, and what's the top-level key? (.mcp.json, key mcpServers.)
🛠 Project
Complete p12-build-an-mcp-server — Build Your First MCP Server. You'll write a FastMCP server in Python exposing one tool, one resource, and one prompt; register it in a project .mcp.json; and verify each primitive from both the MCP Inspector and Claude Code.
🧪 Self-check quiz
- State the integration problem MCP solves, in "M×N → M+N" terms.
- Name the three roles in MCP architecture.
- For each of tools / resources / prompts, who controls invocation?
- Which transport is the standard for remote servers? Which for local subprocesses?
- Why must a stdio server never write to stdout?
- In FastMCP, where does a tool get its name and description?
- What file wires a server into Claude Code, and what is its top-level key?
- "User wants to attach the latest churn report as context." Which primitive?
- Every app re-implements every tool (M×N); MCP standardizes the connector so each side implements it once (M+N). 2. Host, client, server. 3. Tools→model, resources→application/host, prompts→user. 4. Streamable HTTP for remote; stdio for local. 5. stdout is the JSON-RPC wire; printing corrupts it — log to stderr. 6. The function's name and docstring (type hints become the schema). 7.
.mcp.json, keymcpServers. 8. A resource.
🎓 Certificate criteria
You've "passed" Introduction to MCP when you can:
- Explain the M×N problem and the host/client/server architecture without notes.
- State who controls each of the three primitives.
- Choose stdio vs Streamable HTTP for a given deployment and justify it.
- Complete p12-build-an-mcp-server with one working tool, resource, and prompt wired into Claude Code via
.mcp.json.
Tick this course off in progress and record the date you earned Anthropic's official certificate.
🔗 Sources & deeper notes
- Official course: https://anthropic.skilljar.com/introduction-to-model-context-protocol
- Spec: https://modelcontextprotocol.io
- Vault notes: mcp-overview, mcp-tools, mcp-resources, mcp-prompts, mcp-server-python, mcp-transports
- Next course: mcp-advanced-topics