08 — MCP fundamentals
In short: MCP, the standard way for an agent to plug into outside tools and data, has a few parts that fit together the same way every time. Learn them once, and any MCP server makes sense at a glance.
You'll learn:
- the roles: host, client, server
- the three things a server offers, and who controls each
- how messages travel, and how the protocol changed in 2026
A server, listed
Server: notes, protocol 2025-11-25
Tools (the model decides when to call them):
add_note — Save a note. A note with the same title is replaced.
list_notes — List the titles of all notes.
search_notes — Find notes whose title or text contains the query (not case-sensitive).
delete_note — Delete the note with this exact title.
Resources (the app or you attach them):
notes://all — All notes
Prompts (you pick them):
summarize_notes — Ask the model to summarize every note.
That's the real output of npm run list in labs/notes-mcp. It asked the server three questions (tools/list, resources/list, prompts/list) and printed the answers. You'll run it in the hands-on below.
Roles
| Role | What it is | In Claude Code |
|---|---|---|
| Host | The AI app you use. It coordinates everything. | Claude Code itself |
| Client | The piece inside the host that holds one connection to one server | One per server you add |
| Server | A program that offers tools, resources or prompts | notes, GitHub, a database server... |
MCP has two layers. The data layer is the JSON-RPC messages: what to ask and what comes back. The transport layer is how those messages travel, plus connection setup and auth, and the messages look the same on every transport.
The three server primitives
A primitive is one kind of thing a server can offer.
| Primitive | Who controls it | Methods | In Claude Code |
|---|---|---|---|
| Tools | The model: it decides when to call one | tools/list, tools/call |
Called as mcp__<server>__<tool> |
| Resources | The app: it decides what to attach | resources/list, resources/read |
Type @server:uri, like @notes:notes://all |
| Prompts | You: you pick when to use one | prompts/list, prompts/get |
Run /mcp__server__prompt, or pick it from the / menu |
- Every resource has a URI (an address), like
notes://all. - A server declares a capability for each primitive it offers, such as
tools. - The spec says a human should be able to deny any tool call. That's what Claude Code's permission prompts are for.
Client features
The client can offer features to the server too. In spec 2026-07-28:
| Feature | What it does | Status |
|---|---|---|
| Elicitation | The server asks the user a question mid-call | Current. Servers must never ask for passwords or API keys in a form. They send you to a URL instead. |
| Roots | Tells a server which folders to work in | Deprecated |
| Sampling | The server asks the client's model for a completion | Deprecated |
| Logging | Log messages over MCP | Deprecated. On stdio, log to stderr. |
Transports
| stdio | Streamable HTTP | |
|---|---|---|
| Who starts the server | The client, as a child process | It's already running at a URL |
| How messages travel | One JSON message per line on stdin and stdout | Each message is an HTTP POST to one endpoint, like /mcp |
| Logging | Only to stderr. stdout is for MCP messages. | Normal server logs |
| Security basics | Runs with your user's rights | Check the Origin header, listen only on 127.0.0.1 when local, require auth |
How the protocol changed in 2026
Spec 2026-07-28 is stateless: there's no initialize handshake any more. Every request carries its protocol version and the client's capabilities in _meta. A client can also ask server/discover what a server supports.
Over HTTP, sessions are gone too, and each POST carries headers like MCP-Protocol-Version. Change notifications, such as "the tool list changed", now arrive on a stream the client opens with subscriptions/listen.
Versions 2025-11-25 and earlier are called "legacy", and they start with the initialize handshake. The list script uses it, which is why its output says protocol 2025-11-25.
Claude Code speaks both. As of October 2026, its default MCP client (built on MCP TypeScript SDK 2.0) asks stdio and HTTP servers whether they speak 2026-07-28, and keeps the legacy handshake for the others (docs).
Two kinds of errors
| Kind | Looks like | Example |
|---|---|---|
| Protocol error | A JSON-RPC error object |
Unknown tool name, malformed request |
| Tool execution error | A normal result with isError: true |
Invalid input (wrong date format), a failed operation |
The spec says clients SHOULD pass tool execution errors to the model, so it can read the text and correct itself.
The Claude Code side
| Task | How |
|---|---|
| Add a local server | claude mcp add --transport stdio <name> -- <command> [args...] |
| Add a remote server | claude mcp add --transport http <name> <url>, plus --header "Authorization: Bearer ..." if needed |
| Pick who gets it | --scope local (default: you, this project), project (a shared .mcp.json), user (you, every project) |
| See what's connected | /mcp in a session |
Hands-on: list a server's primitives
1. Build the notes server. Same on macOS, Linux and Windows:
cd labs/notes-mcp
npm install
npm run build
2. List what it offers.
npm run list
You should see: the output at the top of this chapter, with four tools, one resource and one prompt.
3. Read it like a host. Answer these from the output:
- Which items could Claude call on its own? (The tools.)
- Which one would you attach with
@? (notes://all.) - Which one would you run from the
/menu? (summarize_notes.)
4. Look at the raw messages (optional).
npm run demo
You should see: every request and reply, including "protocolVersion": "2025-11-25" in the first reply and "isError": true at the very end.
Nothing is connected to Claude Code yet. That's the next step.
Common mistakes
| Mistake | Reality |
|---|---|
| "Resources and prompts are tools" | Tools are for the model. Resources are attached by the app. Prompts are picked by you. |
| "MCP needs HTTP" | stdio is a standard transport, and most local servers use it. |
"Every MCP session starts with initialize" |
Only legacy versions do. 2026-07-28 is stateless. |
Remember:
- The host holds one client per server.
- Tools are model-controlled, resources app-controlled, prompts user-controlled.
- JSON-RPC messages are the same on every transport.
- Spec
2026-07-28dropped the handshake. Claude Code still speaks both versions.
Test yourself with the quiz: 5 questions.
Sources
- MCP architecture: https://modelcontextprotocol.io/docs/2026-07-28/learn/architecture
- Server concepts: https://modelcontextprotocol.io/docs/2026-07-28/learn/server-concepts
- Client concepts: https://modelcontextprotocol.io/docs/2026-07-28/learn/client-concepts
- Elicitation: https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation
- Transports: https://modelcontextprotocol.io/specification/2026-07-28/basic/transports
- Changelog 2026-07-28: https://modelcontextprotocol.io/specification/2026-07-28/changelog
- Claude Code MCP: https://code.claude.com/docs/en/mcp