Lesson 07 Sampling & Elicitation
Theme:

Homework — Sampling & Elicitation

Lesson 07 · MCP Servers · three short extensions to the lab's PKB server

These three tasks layer on top of the lab. You'll be editing the same mcp-servers/sample-server/python/pkb/ package — extend the existing summarize tool, add two new ones, and keep the user-pays-for-tokens discipline you practised in the lab.

Before you start

Finish the lab first. PKB must already expose echo, search, and the sampling-powered summarize. Each task below is independently testable in Inspector — do them in order and reinstall (pip install -e .) only when Python complains about a missing import.

Task 1 — Add a summarize_all tool

Add a new tool that summarises every note in the store in one call:

@mcp.tool()
async def summarize_all(ctx: Context) -> dict[str, str]:
    ...

The tool runs sampling once per note in NOTES and returns a mapping {title: 2-sentence-summary}. Because each call costs the user real tokens, enforce a hard cap: if len(NOTES) > 5, raise McpError(INVALID_PARAMS) with a message citing the cap, and don't issue any sampling requests at all.

✓ Self-check: calling with 3 notes in the store returns a 3-key dict; padding the store to 6 notes and calling again returns an INVALID_PARAMS error citing the cap (no consent dialog appears).

Task 2 — Add an elicitation step to write_note

Add a tool that lets the user create a new note:

@mcp.tool()
async def write_note(body: str, ctx: Context) -> str:
    ...

If the LLM didn't pass a title, use ctx.session.elicit(...) to ask the user for one (an object schema with a single required title: string field is enough). On accept, save the new note to NOTES under the supplied title and return "saved: <title>". On any non-accept action, return "write cancelled by user" without writing anything.

✓ Self-check: in Inspector, calling write_note with only body triggers an elicitation form; filling in title=demo and accepting saves the note (re-list via search to confirm); declining returns "write cancelled by user" and leaves NOTES untouched.

Task 3 — Cost-aware sampling in summarize

Modify summarize_via_sampling in pkb/tools.py so it short-circuits when the note body is too small to be worth summarising: if len(body) < 80, return the body itself plus the suffix "Note too short to summarize." and never issue a sampling request.

Pick the threshold by characters, not words — token cost correlates with character count much more reliably than word count for short snippets.

✓ Self-check: calling summarize(id="todo") (a 21-char body) returns the body plus the trailer "Note too short to summarize.", with no consent dialog and no sampling request observable in Inspector's network/log pane.

You're spending other people's tokens

Every sampling call inside these tools bills the user, not your server. Caps (Task 1) and short-circuits (Task 3) aren't optimisations — they're the contract you owe anyone who installs your server. Test the caps before you ship.

View solutions →