Mission
By the end, you can explain MCP’s host-client-server architecture, distinguish its three server primitives from client capabilities, and design a versioned connection that preserves identity, consent, and least privilege.
Prerequisite: Chapter 3.1. Familiarity with JSON and HTTP helps. Build artifact: an MCP architecture and threat-model card. Time: 70-90 minutes.
Before you read: Predict → Commit → Connect
A product connects to three MCP servers: a local file server, a remote issue tracker, and a remote customer database.
- Is there one shared MCP client or one client connection per server?
- Does discovering a tool mean the user authorized its execution?
- Are sampling and elicitation two more server primitives alongside tools, resources, and prompts?
Commit your answers before reading. At least one popular MCP diagram on the internet would lead you astray.
MCP standardizes a seam, not an agent
The Model Context Protocol (MCP) standardizes how an AI application exchanges capabilities and context with external programs. It helps a host discover and invoke tools, read resources, and expose prompts through a common protocol.
MCP does not decide:
- what the agent’s goal is;
- which evidence is trustworthy;
- whether the current user is authorized;
- whether a side effect needs approval;
- how the model plans or stops;
- how your application evaluates success;
- which data may be sent to a model.
Those remain application responsibilities. MCP replaces bespoke connection glue; it does not replace the deterministic envelope from Chapter 1.2.
The topology: one host, several isolated clients
An MCP host is the AI application. It creates one MCP client for each MCP server it connects to. Each client maintains a dedicated connection with its corresponding server.
This is not an all-to-all agent bus. Server A does not automatically see Server B, the complete conversation, or the user’s credentials. The host chooses what crosses each connection.
Local versus remote describes deployment, not trust. A local server launched over standard input/output can still be malicious or overprivileged. A remote server may be carefully governed. Evaluate code provenance, permissions, data flow, and operating controls in both cases.
Two protocol layers
MCP separates:
- Data layer: JSON-RPC 2.0 messages, lifecycle, capability negotiation, requests, results, errors, and notifications.
- Transport layer: how those messages move.
The current released specification supports two principal transports:
- stdio: the host launches or connects to a local process and exchanges messages over standard input/output;
- Streamable HTTP: clients send messages over HTTP, with optional server-sent events for streaming.
Do not confuse transport with capability. The same tool contract can travel over either transport. Security controls differ: a local process needs sandboxing and constrained environment access; a remote endpoint needs network and authorization controls.
Exactly three server primitives
In the current protocol revision, servers expose three core primitives:
| Primitive | Typical controller | Purpose | Example |
|---|---|---|---|
| Prompts | User | Reusable interaction template selected by a person | “Prepare incident review” |
| Resources | Application | Addressable context selected or attached by the host | Policy text, repository file |
| Tools | Model, inside host controls | Callable operation that reads or acts | Search tickets, create draft |
The control labels describe the intended interaction model. They are not security guarantees. A host can still require confirmation before a tool, filter a resource, or decline a prompt.
Client capabilities are different
The current 2025-11-25 specification also describes server-to-client requests or client features, including:
- elicitation: a server asks the host to gather structured user input;
- sampling: a server asks the client/host to obtain a model completion;
- roots: a client can expose filesystem scope information;
- utility behavior such as progress, cancellation, completion, and logging.
Sampling, elicitation, and roots are not additional server primitives. Direction and ownership matter. If a server can ask your host to sample a model, the host still controls consent, model access, data policy, and allowed tools.
Tasks require an experimental label
The 2025-11-25 specification introduced Tasks as experimental durable state machines for long-running requests. Experimental means the design may change. Treat Tasks as version-gated, test both parties’ advertised support, and keep your application’s durable state independent of experimental wire details.
By July 2026, maintainers had finalized a newer Tasks-extension direction for the forthcoming protocol generation. Do not silently mix the current-revision Tasks messages with draft or extension messages. Record the negotiated protocol version and explicit extensions on every connection.
Lifecycle and capability negotiation
Under the current revision, a connection begins with initialization:
- the client sends its supported protocol version, capabilities, and implementation identity;
- the server returns its selected version, capabilities, and identity;
- the client sends an initialized notification;
- both sides use only negotiated features.
Production clients should:
- support an explicit set of versions;
- reject an unsupported version rather than guessing;
- validate server identity and capability payloads;
- namespace tools by server origin to avoid collisions;
- refresh catalogs only through declared change notifications or policy;
- cap catalog size and schema complexity;
- log the negotiated version, server, transport, and capability set.
Discovery is not authorization. A server may advertise delete_project; the host can hide it, deny it, or expose it only after a task enters a reviewed state.
The 2026 date stamp: current now, release candidate next
MCP uses date-based protocol revisions. As of 2026-07-17:
2025-11-25is the current specification, ready for use;2026-07-28is a locked release candidate, not yet the final current revision;- the release candidate proposes major changes, including a stateless protocol core, extension-based Tasks, and deprecation notices for roots, sampling, and protocol logging.
Use MCP’s publication states precisely: Current is the revision ready for current use and can still receive compatible corrections; Final describes an older frozen revision. Therefore 2025-11-25 is current, not “the final specification.”
This distinction prevents two opposite mistakes: teaching old protocol behavior forever, or presenting a future release candidate as already final.
SEP-2577 is a finalized direction to deprecate roots, sampling, and protocol logging in the next specification release. It does not change 2025-11-25 wire behavior today. For greenfield designs, avoid making those capabilities foundational unless compatibility requires them; for current implementations, continue negotiating and handling them correctly.
Version rule: put protocol-version facts in a dated compatibility note. Keep durable concepts—least privilege, capability negotiation, provenance, approval, and validation—in the main architecture.
Authorization: never pass trust through
For protected HTTP-based MCP deployments, the current authorization specification builds on OAuth. Important properties include:
- protected-resource metadata tells clients which authorization server protects the MCP resource;
- authorization-server discovery supports OAuth metadata and OpenID Connect discovery;
- clients request a token for the specific MCP resource using a resource indicator;
- public clients use authorization code flow with PKCE;
- access tokens travel in the
Authorizationheader, never the query string; - the MCP server validates audience and scopes;
- an MCP server must not pass its inbound MCP token through to an upstream API.
Token passthrough breaks audience boundaries and can create a confused deputy. If an MCP server calls an upstream service, it obtains and protects a separate upstream credential appropriate to that service.
OAuth proves and limits delegated access; it does not decide whether a model-proposed action makes sense. The host still shows the user a comprehensible preview and enforces action policy.
Secure the whole connection
For every server:
- Identify: verify origin, package, publisher, endpoint, and expected version.
- Constrain: sandbox local processes; restrict files, environment variables, network, and subprocesses.
- Authorize: request minimum scopes, bind tokens to the intended resource, and use step-up consent when needed.
- Filter: expose only task-relevant primitives and safe resource slices.
- Validate: treat tool arguments and all returned content as untrusted.
- Approve: pause before consequential or surprising actions.
- Observe: record origin, call, result, approval, latency, and failure without secrets.
- Revoke: support disabling one server, credential, scope, or tool quickly.
Tool annotations and server descriptions are hints from the server, not trustworthy declarations of safety.
I do: translate a local tool registry into MCP shape
The laboratory is not an MCP implementation; it gives us stable tool contracts to translate. Run:
PYTHONPATH=courses/ai-agents/labs python3 - <<'PY'
import json
from agent_lab.capstones.research import build_registry
tools = []
for schema in build_registry().schemas():
tools.append({
"name": schema["name"],
"description": schema["description"],
"inputSchema": schema["parameters"],
})
print(json.dumps({"tools": tools}, indent=2))
PY
The transformation keeps the portable contract: name, description, and JSON input schema. The laboratory’s requires_approval flag is deliberately not smuggled into standard MCP shape. Approval policy remains with the host unless a negotiated extension explicitly represents it.
We do: locate ownership in a remote call
Scenario: the issue server advertises close_issue(issue_id, reason).
Complete the ownership map:
| Concern | Owner |
|---|---|
| Advertise tool contract | MCP server |
| Decide whether tool is visible now | Host policy |
| Propose the call | Model inside the host |
| Authenticate the user | Host and authorization system |
| Validate issue belongs to allowed project | Host and issue service |
| Display exact preview | Host UI |
| Approve or deny | Authorized human/policy |
| Execute close operation | Server adapter and issue service |
| Return result | MCP server |
| Decide whether result completes the goal | Host agent loop |
If your design assigns all rows to “MCP,” redraw it. A protocol coordinates responsibilities; it does not erase them.
You do: LAB-8 — MCP architecture and threat-model card
Choose one imaginary local server and one imaginary remote server. Do not connect to real accounts.
This is a paper architecture exercise plus a local schema-shape check. It does not run MCP transport, initialization, version negotiation, discovery, or tool invocation, so it is not MCP interoperability or conformance evidence.
- Name host, one client per server, server process/endpoint, transport, and server owner.
- Declare the exact protocol revision you support.
- List negotiated server primitives and client capabilities separately.
- Namespace every tool with its server origin in your application inventory.
- For each tool, add side-effect class, resource scope, approval rule, and output cap.
- Draw the identity and token path. Prove no token is passed through to an upstream service.
- Write failure behavior for version mismatch, unknown capability, server timeout, malicious description, and oversized result.
- Add a migration watch item for the
2026-07-28release candidate; do not change current behavior until the final spec and your SDK support are verified.
Use this contract check after the translation above:
PYTHONPATH=courses/ai-agents/labs python3 - <<'PY'
from agent_lab.capstones.research import build_registry
origin = "course-research"
catalog = []
for raw in build_registry().schemas():
item = {
"origin": origin,
"qualified_name": f"{origin}.{raw['name']}",
"name": raw["name"],
"description": raw["description"],
"inputSchema": raw["parameters"],
}
assert item["inputSchema"]["additionalProperties"] is False
assert item["qualified_name"].startswith(origin + ".")
catalog.append(item)
assert len({item["qualified_name"] for item in catalog}) == len(catalog)
print("PASS", [item["qualified_name"] for item in catalog])
PY
Done when: another engineer can review the proposed connection, negotiated behavior, identity boundary, approval owner, data path, and rollback plan without using “MCP handles it” as an explanation—and the artifact is labeled as architecture, not interoperability proof.
Pause & Recall
Without looking back:
- What is the relationship among host, client, and server?
- Name the three server primitives and their typical controllers.
- Why are sampling and elicitation not server primitives?
- Which protocol revision is current on 2026-07-17?
- What is token passthrough, and why is it forbidden?
- What does capability negotiation fail to authorize?
Production lens
Maintain a connection registry containing server origin, owner, transport, supported revisions, extensions, package or certificate identity, scopes, tools, data classes, and last security review. Pin dependencies where practical and test upgrades in isolation.
Run conformance and negative tests: malformed JSON-RPC, capability mismatch, duplicate IDs, cancellation, oversized catalogs, slow streams, hostile tool descriptions, injection in resources, token audience mismatch, redirect abuse, approval denial, and server revocation.
Do not make a protocol upgrade and a model upgrade in the same unobserved release. Preserve traces that let you distinguish model selection changes from protocol, server, schema, or policy changes.
Chapter compression
- MCP standardizes context and capability exchange; it does not create or secure an agent by itself.
- A host creates one dedicated client connection per server.
- Servers expose prompts, resources, and tools; client capabilities such as elicitation and sampling are different.
- Negotiate and record versions and capabilities; discovery is not authorization.
- As of 2026-07-17,
2025-11-25is current and2026-07-28is a release candidate. - Bind tokens to the intended resource, forbid token passthrough, and keep host approval in control.
Memory hook: Standardize the wire; preserve the boundary.
Retrieval deck
- Q: How many MCP clients does a host create for three servers?
A: Three client instances, each with a dedicated server connection. - Q: What are the three server primitives?
A: Prompts, resources, and tools. - Q: Does a listed tool have permission to run?
A: No. The host and action service must still authorize the actor, resource, and task and apply approval policy. - Q: How should a course treat a release candidate?
A: As a dated migration watchlist, not current released behavior.
Spaced review
- Now: redraw the host-client-server topology.
- +1 day: classify ten MCP nouns as primitive, client feature, utility, transport, or application control.
- +3 days: threat-model a malicious local stdio server.
- +7 days: explain the OAuth resource and token-audience boundary.
- +14 days: recheck the MCP versioning page and update only the dated compatibility note if status changed.