Topic 1: Module 4 at a glance, and the setup
3 min read·22 Sept 2026
By the end of this module, you'll have:
- A prototype notes server (
examples/m04_server.py) that exposes thenotes://indexresource, thenotes://{note_id}resource template, and thesummarise_topicprompt next to Module 3's two tools, with hostile URIs rejected by three separate layers. - A live change feed: a client that opens a
subscriptions/listenstream and refetches notes when another client creates one or a colleague edits a file on disk, seen both through the SDK and as raw frames on the wire. - A tiny host that turns server prompts into slash commands, so typing
/summarise_topic sleeprenders the prompt and runs the agent loop. - A
create_notethat asks the user to confirm (form-mode elicitation) only when similar notes already exist, and animport_zoterotool that sends the user to a web page for their API key (URL-mode elicitation), both answered by a clientelicitation_callback. - A working understanding of Multi Round-Trip Requests, driven by hand round by round, including a resumed call in a second client and a rejected, tampered
request_state. - A clear picture of why sampling and roots are deprecated, what replaces them, and why a secret must never travel through a form field.
Prerequisites: Modules 1 to 3 (host, client and server roles; JSON-RPC and the 2026-07-28 stateless lifecycle; defining tools with MCPServer). Comfort with async/await and anyio.
Where we are: Module 3 gave the notes server its two tools, search_notes and create_note, and showed how a model picks between them. Tools are only one of the three server primitives. In this module we add the other two (resources and prompts), then look at the moments when a server needs something only the user can give: a confirmation, a click, a credential.