One request through an MCP server, end to end A walkthrough published as part 30 of a series on the Model Context Protocol (MCP) 2026-07-28 specification traces a single user request through an MCP server in seven phases, from discovery to app teardown, showing that one request touches most of a server's duties. The author reports that nothing is remembered between requests — each carries its own `_meta` envelope — and that the server asks for a missing date range via `input_required`, with the answer arriving on a retry under a new request ID. The piece also notes that hosts differ as of October 2026: Claude Code gives the model `structuredContent` in place of text, while ChatGPT lets the model see it, and advises checking the whole sequence in one test using a fake host and a recorder kept in the Python SDK server's middleware. One request through an MCP server, end to end Twenty-nine parts took a Model Context Protocol MCP server apart one duty at a time. This one puts them back together, to show how they fit in one request. A user asks an AI agent for Q3 sales by region, the server needs a date range it wasn’t given, it renders an interactive dashboard, and later its tool list changes. This is part 30 of my series on what an MCP server does under the 2026-07-28 specification, after part 29 on extensions https://pournasserian.com/writing/mcp-2026-experimental-extensions . Each phase links to the part that explains it. The facts are as I read them in October 2026. In brief 1. One request touches most of a server’s duties, in seven phases, from discovery to the app’s teardown. 2. Nothing is remembered between requests. Each carries its own meta envelope. The server asks for the missing date range with input required , and the answer arrives on a retry with a new request ID. 3. Under the MCP Apps convention, the data goes to the app and the text to the model, so write text that stands on its own. Hosts differ, as of October 2026: Claude Code gives the model structuredContent in place of the text, and ChatGPT lets the model see it. 4. My advice: check the whole sequence in one test, with a fake host and a recorder that keeps every message. In the Python software development kit SDK , the recorder fits in the server’s middleware. Phases 1 to 3: setup, the user’s turn and a question back Six parties take part, including the large language model LLM : | Participant | Role | |---|---| | User | Asks the question and interacts with the dashboard | | App view | An MCP App running in a sandboxed iframe inside the host | | Host + MCP client | The AI application for example Claude or VS Code and its MCP client | | LLM | The model reasoning inside the host | | MCP server | A sales-analytics server speaking 2026-07-28 | | Backend | The data warehouse behind the server | - 1. Discovery and setup. There’s no initialize handshake: the host calls server/discover https://pournasserian.com/writing/mcp-2026-server-discover , which this server lets it cache for an hour, and lists the tools with the per-request meta envelope https://pournasserian.com/writing/mcp-2026-stateless-requests ; they come back with their caching hints https://pournasserian.com/writing/mcp-2026-caching-and-pagination . It prefetches the user interface UI template that meta.ui.resourceUri names, to review and cache it before any tool runs, and opens one subscriptions/listen https://pournasserian.com/writing/mcp-2026-subscriptions-listen stream for tool-list changes. This server requires authorization, so every request over remote Hypertext Transfer Protocol HTTP https://pournasserian.com/writing/mcp-2026-transports carries the bearer token https://pournasserian.com/writing/mcp-2026-oauth-resource-server . - 2. The user’s turn. The host builds the model’s context: this one puts the server instructions https://pournasserian.com/writing/mcp-2026-server-instructions in the system prompt a host’s choice, not a protocol rule and the tool definitions https://pournasserian.com/writing/mcp-2026-tool-definitions in up front or through tool search. The model decides to call get sales . - 3. A question back. The date range is missing, so instead of holding the connection open the server returns input required with an elicitation https://pournasserian.com/writing/mcp-2026-elicitation form and a sealed requestState https://pournasserian.com/writing/mcp-2026-request-state . That exchange is a multi round-trip request MRTR https://pournasserian.com/writing/mcp-2026-multi-round-trip-requests . The client asks the user and retries with a new request ID, and any server instance can complete the call in Python, given a shared sealing key . Progress https://pournasserian.com/writing/mcp-2026-progress-and-cancellation flows on the retry’s own response stream, and the trace context https://pournasserian.com/writing/mcp-2026-opentelemetry continues through meta.traceparent . Phases 4 to 7: the app, the answer and what follows - 4. The app renders. Having negotiated the UI extension, the host loads the cached template in a sandboxed iframe, under a Content Security Policy CSP built from meta.ui.csp . After the ui/initialize handshake it sends the tool’s input, then its result, and the app renders from structuredContent part 24 https://pournasserian.com/writing/mcp-2026-apps and part 25 https://pournasserian.com/writing/mcp-2026-apps-building . - 5. The model answers. Under the MCP Apps convention https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx , the model sees only the text content . Hosts differ: as of October 2026, Claude Code and its Agent SDK https://code.claude.com/docs/en/agent-sdk/custom-tools pass structuredContent to the model in place of the text blocks, and ChatGPT lets the model see it per OpenAI’s Apps SDK documentation . A text-only host stops here, with a usable answer if the text stands on its own, as part 8 https://pournasserian.com/writing/mcp-2026-tool-definitions advises. - 6. Interaction. The user drills into a region: the app calls an app-only tool https://pournasserian.com/writing/mcp-2026-apps-building , visibility: "app" , through the host, which checks policy before forwarding it. The app then updates the model’s context with the region in view. - 7. Change and teardown. A new tool appears, perhaps because a feature flag flipped: the server signals list changed https://pournasserian.com/writing/mcp-2026-subscriptions-listen on the listen stream, and the host lists the tools again. When the conversation moves on, the host tears the app down gracefully. Testing the whole sequence Each phase leaned on a different part of the server: My advice is to test those duties together: simulate the whole sequence in an integration test, with a fake host that records every message. Assert the envelope on each request, the resultType on each result, a fresh request ID on each retry, a requestState that fails verification if tampered with, an app-only tool that never reaches the model’s tool list, and text content that’s useful on its own. That one test catches most real-world interoperability bugs. Here’s a small version with the official Python SDK, mcp 2.3.0: get sales asks for a missing date range with Resolve , as in part 13, and the dashboard’s HTML resource and the app-only tool come from mcp.server.apps , as in part 25. python from typing import Annotated from pydantic import BaseModel from mcp.server import MCPServer from mcp.server.apps import Apps from mcp.server.mcpserver import Elicit, Resolve from mcp.types import CallToolResult, TextContent WAREHOUSE = {"Q3 2026": {"north": 1200, "south": 950}} stands in for the backend UI = "ui://sales/dashboard.html" apps = Apps apps.add html resource UI, "< doctype html