Lesson 07 Sampling & Elicitation
Theme:
Lesson 07 · Slide 1

Lesson 07 — Sampling & Elicitation

The server asks the LLM. The server asks the user. Both need consent.

MCP Servers Module 3

Lesson 07 · Slide 2

The inversion

L04–L06

Client asks server: tools, resources, prompts. Every read or call flows one direction.

L07

The server asks back — either the LLM (sampling) or the user (elicitation).

This is where MCP stops being a one-way API.

Lesson 07 · Slide 3

Sampling: what it is

A tool can request the client's LLM to generate a completion mid-execution. The server doesn't hold the API key — the client does. The server says "summarize this", the client routes the request through its own LLM, and returns the result.

Cost lives with the user, not the server operator. Their tokens, their consent.

Lesson 07 · Slide 4

Why sampling matters

Lesson 07 · Slide 5

The sampling API

from mcp.server.fastmcp import Context
from mcp.types import SamplingMessage, TextContent

@mcp.tool()
async def summarize(id: str, ctx: Context) -> str:
    """Summarize a note via the client's LLM."""
    body = NOTES[id]
    result = await ctx.session.create_message(
        messages=[SamplingMessage(
            role="user",
            content=TextContent(type="text", text=f"Summarize in 2 sentences:\n\n{body}"),
        )],
        max_tokens=200,
    )
    return result.content.text

ctx.session.create_message is the server-initiated LLM call.

Lesson 07 · Slide 6

Cost & consent risks

Sampling spends the user's tokens.

Always:

  • Cap max_tokens.
  • Let the client gate with a consent prompt.
  • Never recurse without a user-visible reason.
  • Never sample in a loop without a hard counter.
Lesson 07 · Slide 7

Elicitation: what it is

A tool can request structured input from the user mid-execution. Example: pkb.write_note mid-call asks "what title?" if the LLM didn't pass one.

The client surfaces a form; the user fills it; the value comes back to the server. Nothing is guessed and nothing is silently defaulted.

Lesson 07 · Slide 8

The elicitation API (preview)

from mcp.types import ElicitationSchema

result = await ctx.session.elicit(
    message="Pick a title for the new note:",
    requested_schema={
        "type": "object",
        "properties": {"title": {"type": "string"}},
        "required": ["title"],
    },
)
title = result.content["title"] if result.action == "accept" else None

The client owns the UX; the server only declares the shape it needs.

Lesson 07 · Slide 9

When sampling vs elicitation

Sampling

You want the LLM's synthesis — summarize, classify, rephrase, extract.

Elicitation

You want the user's clarification — pick a folder, confirm an action, supply a missing arg.

Never use sampling to ask the user for input — that's smuggling.

Lesson 07 · Slide 10

What we'll build today

Lesson 07 · Slide 11

Common gotchas

Lesson 07 · Slide 12

Recap & what's next

Coming up: Lesson 08 — wire summarize into a real multi-tool flow with write and composition.
1 / ?