Merge pull request #4650 from PrefectHQ/claude/mcp-conformance-tests-7ec13f

Pass the MCP conformance suite's draft and pending scenarios
This commit is contained in:
Jeremiah Lowin 2026-07-26 17:38:13 -04:00 committed by GitHub
commit fecced2b5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1727 additions and 84 deletions

View file

@ -541,6 +541,59 @@ on handshake-era connections.
If you need to support both eras, branch on `ctx.protocol_version`: return an `InputRequiredResult` on modern connections and fall back to [`ctx.elicit()`](#requesting-input-on-handshake-connections) on handshake-era ones.
### Prompts and resources
`InputRequiredResult` is a **result type**, not a tools feature: any request can resolve to one. Prompts, resources, and resource templates ask for input exactly the way tools do — return an `InputRequiredResult`, read `ctx.input_responses` on the next round, and the client re-issues the same `prompts/get` or `resources/read` with the answer attached.
This prompt gathers the context it needs before rendering:
```python
from fastmcp import FastMCP, Context
from mcp_types import InputRequiredResult, ElicitRequest, ElicitRequestFormParams
mcp = FastMCP("Reporting Server")
ask_for_quarter = InputRequiredResult(
result_type="input_required",
input_requests={
"quarter": ElicitRequest(
method="elicitation/create",
params=ElicitRequestFormParams(
message="Which quarter should the summary cover?",
requested_schema={
"type": "object",
"properties": {"quarter": {"type": "string"}},
"required": ["quarter"],
},
),
)
},
)
@mcp.prompt
async def summarize(ctx: Context) -> str | InputRequiredResult:
responses = ctx.input_responses
if responses is None:
return ask_for_quarter
quarter = responses["quarter"].content["quarter"]
return f"Summarize the {quarter} results."
```
Resources and resource templates work the same way, with the URI standing in for the tool name:
```python
@mcp.resource("report://summary")
async def report(ctx: Context) -> str | InputRequiredResult:
responses = ctx.input_responses
if responses is None:
return ask_for_quarter
quarter = responses["quarter"].content["quarter"]
return f"Revenue report for {quarter}"
```
The same protocol requirement applies: returning an `InputRequiredResult` from a prompt or resource needs a 2026-07-28 connection, and FastMCP names the era mismatch if one arrives on an older one. Client-side, `read_resource` and `get_prompt` drive the loop the way `call_tool` does, so a configured elicitation handler answers all three without extra wiring.
### Sampling and roots
Elicitation is the most common request to carry this way, and **roots** requests work identically — the `input_requests` map holds them the same way, and each answer comes back in `ctx.input_responses` under its key (an `ElicitResult` or `ListRootsResult`). See [Client Roots](/clients/roots) for what a roots request contains. `fastmcp.Client` answers both from the handlers you already configured, so a guard tool that mixes them needs no extra client wiring.

View file

@ -438,6 +438,10 @@ Notifications are only sent when these operations occur within an active MCP req
Clients can handle these notifications using a [message handler](/clients/notifications) to automatically refresh their prompt lists or update their interfaces.
## Requesting Input
A prompt can ask the client for information before it renders. On an MCP 2026-07-28 connection, return an `InputRequiredResult` describing what you need; the client answers and re-issues the `prompts/get`, and your function runs again with the answer on `ctx.input_responses`. See [Elicitation](/servers/elicitation#prompts-and-resources) for the full pattern.
## Server Behavior
### Duplicate Prompts

View file

@ -783,6 +783,10 @@ def get_data_by_id(id: str) -> dict:
When `mask_error_details=True`, only error messages from `ResourceError` will include details, other exceptions will be converted to a generic message.
## Requesting Input
A resource or resource template can ask the client for information before it produces content. On an MCP 2026-07-28 connection, return an `InputRequiredResult` describing what you need; the client answers and re-issues the `resources/read`, and your function runs again with the answer on `ctx.input_responses`. See [Elicitation](/servers/elicitation#prompts-and-resources) for the full pattern.
## Server Behavior
### Duplicate Resources