Skip to content
datarekha

Advanced MCP primitives

Tools, resources, and prompts are only half of MCP. Servers can also ask the user for input mid-call, run long jobs, and return UI. The 2026-07-28 revision reshaped this layer: multi round-trip requests replace server-initiated calls, and sampling, roots, and logging are deprecated.

8 min read Advanced Agentic AI Lesson 14 of 71

What you'll learn

  • What MCP's server-initiated primitives were, and what the 2026-07-28 revision did to them
  • Multi round-trip requests — how elicitation works on a stateless protocol
  • Sampling, roots, and logging — deprecated, and what to use instead
  • The tasks and MCP Apps extensions

Before you start

The Model Context Protocol intro covered the basics: a server exposes tools, resources, and prompts, and the host (the LLM app) invokes them. That makes MCP sound one-directional — host calls server. For the protocol’s first two years it wasn’t: the server could call back to the host’s model, ask the user a question mid-operation, be confined to declared boundaries, and stream progress on long jobs.

The 2026-07-28 revision changed the shape of that layer. With sessions gone, a server has no open channel to push a request down, so the parts worth keeping were folded into the request/response cycle, and the parts nobody used were deprecated. You need both pictures: the new one to build against, the old one because most servers running today were written before it.

Here is the whole change in one table.

PrimitiveStatus after 2026-07-28What to use instead
Sampling (sampling/createMessage)Deprecated (SEP-2577)Call an LLM provider API directly from the server
Roots (roots/list)Deprecated (SEP-2577)State the scope explicitly — a tool parameter, a resource URI, server config, or an env var
Logging (logging/setLevel, notifications/message)Deprecated (SEP-2577)stderr for stdio servers; OpenTelemetry for structured observability
ElicitationKept, reshapedMulti round-trip requests
Async tasksMoved out of coreThe io.modelcontextprotocol/tasks extension
Apps / UIFormalizedThe MCP Apps extension

Deprecated does not mean broken. Wire behaviour is unchanged, and the features stay in the spec for at least twelve months under the revision’s new deprecation policy — long enough to migrate, short enough that you should not start anything new on them.

One round trip, then anotherHost / ClientLLMuserthe LLM appMCP Servertools, data,capabilitieshost invokes → tools · resources · promptsserver answers ← resultType: “input_required” + inputRequestsclient re-sends the same call with inputResponses — a multi round-trip requestdeprecated 2026-07-28: sampling · roots · logging
With sessions gone, a server can no longer push a request at the host. It asks by returning, and the client comes back with the answers.

Multi round-trip requests: asking by returning

Elicitation — a server pausing to ask the user for a missing value, a confirmation, or a choice — is the callback that earned its keep. On a stateless protocol it works by inversion: the server does not push a question at the host, it returns one. A tools/call, prompts/get, or resources/read can come back with resultType: "input_required" in place of a result:

{
  "resultType": "input_required",
  "inputRequests": {
    "env": {
      "message": "Which environment should I deploy to?",
      "requestedSchema": { "type": "object",
        "properties": { "env": { "type": "string", "enum": ["staging", "prod"] } } }
    }
  },
  "requestState": "opaque-blob-the-client-hands-back"
}

The client collects the answers, then re-issues the same call with inputResponses and the requestState string it was given. The server picks up where it left off. All of the state rides in the payload, which is what lets the second half of the exchange land on a different server instance than the first.

Sampling: the server borrows the host’s LLM (deprecated)

For two years the most powerful advanced primitive was sampling: the server requested a completion from the client’s LLM. Instead of bringing its own model and API key, a server could delegate a reasoning sub-task back to the host — and the host stayed in control, able to review, modify, or deny the request (human-in-the-loop). A server that, say, processes a document could ask the host model to summarize a section:

{
  "method": "sampling/createMessage",
  "params": {
    "messages": [{ "role": "user", "content": { "type": "text", "text": "Summarize the section above." } }],
    "maxTokens": 200,
    "modelPreferences": { "hints": [{ "name": "claude-sonnet" }] }
  }
}

That inverted the usual flow — the server prompting the host’s model — and it is why MCP servers could be intelligent without each shipping (and paying for) their own LLM. You will still meet it in deployed servers, so it is worth recognising on sight.

SEP-2577 deprecated it, for three reasons worth knowing. Few clients ever implemented it: doing sampling correctly means human-in-the-loop approval, model selection, and a tool loop. Servers that want a model can simply call a provider API, with full control over model, parameters, and streaming. And it was the most security-sensitive primitive in the protocol — a server prompting the host’s model is a ready-made channel for prompt injection and context exfiltration. Writing a server today, call an LLM API directly.

Roots, logging, tasks, and apps

  • Roots (host → server, deprecated): the client declared the filesystem paths or URIs the server was allowed to operate within — part convenience (the server knows the workspace), part boundary (the server isn’t handed the whole disk). Two problems sank it: few clients implemented it, and the spec only ever called it informational — servers were never required to respect a root, which is a weak thing to lean on for security. State the scope explicitly instead: a path parameter on the tool, a resource URI, server config, or an environment variable. Real confinement comes from sandboxing the server, not from telling it where to behave.
  • Logging (server → host, deprecated): servers could push structured log messages down the protocol. Use what the rest of your stack already uses — stderr for a stdio server, OpenTelemetry when you want structured, queryable traces.
  • Async tasks: long-running work moved out of the core into the io.modelcontextprotocol/tasks extension. The server hands back a task handle and the client polls tasks/get; tasks/update feeds input into a running task, and subscriptions/listen covers streams of updates. The blocking tasks/result and the tasks/list enumeration were removed — holding a request open until a slow job finishes is exactly what pins a client to one server instance.
  • Apps / UI: no longer emerging. MCP Apps is a formal extension: the server ships an interactive HTML interface that the host renders in a sandboxed iframe — a form, a chart, a picker instead of a wall of text. Anything the user triggers in that UI goes back through the same JSON-RPC path as any other call, so it inherits the same consent prompts and the same audit trail.
  • Enterprise Managed Authorization (EMA) is the third extension in the framework: organisation-level control over which servers and scopes its users may reach.

In one breath

  • Beyond host-invoked tools/resources/prompts, MCP servers could once initiate — the 2026-07-28 revision folded the useful half of that back into request/response.
  • Elicitation survives as a multi round-trip request: the server returns resultType: "input_required", the client re-sends the same call with inputResponses and the echoed requestState, so all the state rides in the payload.
  • Sampling, roots, and logging are deprecated (SEP-2577) — call an LLM API directly, pass the scope as an explicit argument, and log to stderr or OpenTelemetry. They keep working for at least twelve months, so you will still meet them.
  • Async tasks moved to the io.modelcontextprotocol/tasks extension (poll tasks/get; blocking tasks/result and tasks/list are gone), and MCP Apps is now a formal extension for servers that return interactive UI in a sandboxed iframe.
  • These powers widen the attack surface — an input_required result is still a server questioning your user — so keep humans in the loop, sandbox the server, and distrust anything a server authors (MCP security).

Quick check

Quick check

0/5
Q1What does MCP 'sampling' let a server do?
Q2'Roots' let the client declare the paths a server may operate within. What is their status after the 2026-07-28 revision?
Q3A stateless MCP server needs a value from the user before it can finish a tools/call. How does it ask?
Q4What is 'elicitation'?
Q5Why does a server asking things of the host raise security concerns?

Next

These primitives sit alongside the cross-protocol view in MCP vs A2A vs ACP vs ANP, and the threats they introduce are covered in MCP security. To build a server that uses them, see FastMCP.

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Related lessons

Explore further