Deprecated Primitives
Sampling, Roots, and Logging — deprecated in spec 2026-07-28, what each was for, and exactly what to do instead
Deprecated Primitives
TL;DR
Three client-side primitives — Sampling, Roots, and Logging (as a protocol feature) — were deprecated in spec version 2026-07-28. All three still technically work under the feature lifecycle policy, but new implementations should not adopt them, and a great deal of MCP content written before this change still teaches them as current. This page exists to correct that.
| Property | Value |
|---|---|
| Level | Intermediate |
| Reading time | ~16 minutes |
| Prerequisites | Resources & Prompts |
| You will understand | What each deprecated primitive was for, why it was deprecated, and exactly what to build instead |
Why This Page Exists
If a tutorial, blog post, or SDK example still teaches these as current features, it predates 2026-07-28
Sampling in particular was, for a long time, one of the more frequently discussed MCP features — a server asking the client's LLM to run a completion on its behalf. It is deprecated now. If you're reading older material, or working from an LLM's training-data knowledge of MCP, treat anything describing sampling, roots, or protocol-level logging as current with suspicion and check the date it was written.
Under MCP's feature lifecycle policy, a deprecated feature doesn't vanish overnight — it remains in the specification for at least twelve months after the deprecating revision's release before becoming eligible for removal. That's a deliberate grace period for existing implementations to migrate, not a signal that these features are still a good foundation for new work. New implementations should not adopt them; existing ones should migrate.
Sampling — Deprecated
What it was for: Sampling let a server ask the client's AI application to run a language model completion on its behalf, via sampling/createMessage. The idea was to let server authors get access to an LLM without bundling their own model SDK or API key into the server — the client supplied the model, keeping the server model-independent.
Server: "I need an LLM to summarize this. sampling/createMessage(...)"
Client: runs the completion using its own configured model, returns the result
Server: uses that result to continue its own logicWhy it's deprecated: The spec doesn't require server authors to guess at the reasoning, but the practical shift is toward every server maintainer integrating directly with an LLM provider's own API rather than routing through the client for something as fundamental as model access — simpler to reason about, and it removes a layer of indirection that made a server's actual behavior harder to predict.
Migration: "New implementations should integrate directly with LLM provider APIs." If you're building a server today that needs to call an LLM, use a provider SDK (like the Anthropic SDK) directly in your server code, the same way any other application would.
Roots — Deprecated
What it was for: Roots let a client expose filesystem "roots" — directories and files the client considers relevant — to a server, via roots/list. A root looked like this:
{ "uri": "file:///home/user/projects/myproject", "name": "My Project" }The uri field was required to be a file:// URI in the spec that defined roots. The intent was to inform a server which parts of the filesystem were in scope for the current session, so a filesystem-touching server could focus its operations accordingly.
The most common misconception about Roots, worth internalizing even though it's deprecated
Roots were always informational guidance, never an access-control mechanism. The protocol never enforced that a server actually stayed within the declared roots — a well-behaved server would respect them, but nothing prevented a server from reading files outside the declared root set. If you ever saw roots described as a security boundary, that was a misunderstanding even while the feature was current, not something the deprecation changed.
Why it's deprecated: Formalized in SEP-2577, the deprecation reflects that "which directories matter" is better expressed through mechanisms that are actually enforced or explicitly scoped, rather than a hint the server was free to ignore.
Migration: "Existing implementations should migrate to passing directories or files via tool parameters, resource URIs, or server configuration." Concretely: if a tool needs to know which directory to operate in, make that an explicit argument in the tool's inputSchema — don't rely on a separately-declared root the server has to remember and cross-reference.
Logging (as a Protocol Primitive) — Deprecated
What it was for: A dedicated mechanism for a server to send log messages to the client, for debugging and monitoring purposes — log lines flowing through the MCP connection itself as a distinct message type.
Why it's deprecated: Standard, already-solved observability tooling does this job better than a bespoke protocol-level channel. Routing debug output through the same connection carrying tool calls and resource reads adds complexity without a corresponding benefit over tools built for exactly this purpose.
Migration: "New implementations should log to stderr (stdio transport) or use OpenTelemetry." For a local stdio server, writing to stderr is simple and doesn't interfere with the stdout stream carrying protocol messages. For anything more sophisticated — structured logs, distributed tracing across a remote server's requests — OpenTelemetry is the standard tool built for that job.
What's Still Current
Don't over-correct
Deprecating Sampling, Roots, and Logging doesn't touch the rest of the protocol. Tools, Resources, and Prompts (the three server primitives) are unaffected, and Elicitation — the one remaining client-side primitive — is fully current, covered in depth on the next page. If a source is confidently wrong about sampling being current, don't assume everything else it says about MCP is also wrong — check specifics against the spec, not the whole document.
| Primitive | Status |
|---|---|
| Tools | Current |
| Resources | Current |
| Prompts | Current |
| Elicitation | Current |
| Sampling | Deprecated |
| Roots | Deprecated |
| Logging (protocol-level) | Deprecated |
Concept Checks
Check yourself
A tutorial you're reading has a server call sampling/createMessage to get an LLM completion from the client. Is this still the recommended approach?
No. Sampling was deprecated in spec version 2026-07-28. The current recommendation is for the server to integrate directly with an LLM provider's API rather than routing model access through the client. The tutorial likely predates the deprecation.
Before roots were deprecated, could a client rely on a server never reading files outside the declared root directories?
No, and this was true even while roots were fully current — roots were always informational guidance, not an enforced access-control mechanism. The protocol never prevented a server from reading outside the declared roots; a well-behaved server simply chose to respect them. This is a common misconception about what roots ever guaranteed, independent of the later deprecation.
Does the twelve-month grace period under the feature lifecycle policy mean it's fine to build new integrations on Sampling, Roots, or Logging today?
No. The grace period exists so that existing implementations have time to migrate away, not to signal that these are still a reasonable foundation for new work. New implementations should not adopt deprecated primitives — the migration guidance (direct LLM provider integration, tool parameters/resource URIs/config, and stderr/OpenTelemetry respectively) is what new work should build on instead.
Key Concepts Recap
| Concept | One-line summary |
|---|---|
| Deprecated as of 2026-07-28 | Sampling, Roots, and Logging (as a protocol primitive) |
| Sampling | Was: server asks client's LLM for a completion. Now: integrate an LLM provider API directly. |
| Roots | Was: client tells server which directories are relevant. Now: pass paths via tool params, resource URIs, or config. |
| Roots were never access control | Always informational guidance — the protocol never enforced them, even before deprecation |
| Logging (protocol-level) | Was: server sends log messages over the MCP connection. Now: stderr or OpenTelemetry. |
| Feature lifecycle policy | Deprecated features stay in the spec at least twelve months before becoming removable |
| Still current | Tools, Resources, Prompts, and Elicitation are entirely unaffected by these deprecations |
Next
The one client-side primitive that's still fully current: Elicitation.