You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- In-call cache keyed by _resolver_key (instance-distinct) again; _state_key adds
id(__self__) for the wire key, so two instances of one bound method no longer
collide and silently share an outcome.
- resolve_arguments reads ctx.protocol_version (new Context property, None outside
a request) instead of dereferencing request_context, so direct
MCPServer.call_tool() works for tools whose resolvers never elicit.
- request_state persists only elicited outcomes (always validated models); a
resolver that resolves without eliciting is pure and re-runs each round. Fixes
the json.dumps crash on non-serializable returns (datetime/set/...) and the
dict-degradation of restored values.
- _elicit_return_schema handles a bare Elicit[T] return (not only unions).
- _INPUT_REQUIRED_VERSION pinned to '2026-07-28' instead of LATEST_MODERN_VERSION.
- accept with no content raises ToolError instead of silently reporting cancel.
- Independent nested resolver deps batch into one round (catch _Pending per dep).
- Test cleanup: drop dead helpers, hoist CreateMessageResult import.
Add regression tests for each; document the narrowed elicited-only persistence.
Copy file name to clipboardExpand all lines: docs/migration.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1515,7 +1515,7 @@ async def delete_folder(
1515
1515
1516
1516
The `confirm_delete` resolver reads the tool's own `path` argument by name, lists the folder, and only elicits when the folder is non-empty - an empty folder resolves to `Confirm(ok=True)` with no round-trip to the client. Because `delete_folder` annotates the result union, it handles every outcome: the user accepting and confirming, accepting but declining to delete (`ok=False`), declining the elicitation, or cancelling it.
1517
1517
1518
-
The framework drives elicitation over whichever transport the negotiated protocol provides, so the resolver and tool code above is unchanged either way. At `2026-07-28` and later it returns an `InputRequiredResult` carrying the questions and resumes when the client retries `call_tool(..., input_responses=..., request_state=...)` (independent resolvers are batched into one round; a resolver that depends on another's answer is asked in a later round). At `2025-11-25` and earlier it issues a synchronous `elicitation/create` request mid-call. Resolved outcomes are carried in `request_state` across rounds so each resolver resolves once per call.
1518
+
The framework drives elicitation over whichever transport the negotiated protocol provides, so the resolver and tool code above is unchanged either way. At `2026-07-28` and later it returns an `InputRequiredResult` carrying the questions and resumes when the client retries `call_tool(..., input_responses=..., request_state=...)` (independent resolvers are batched into one round; a resolver that depends on another's answer is asked in a later round). At `2025-11-25` and earlier it issues a synchronous `elicitation/create` request mid-call. Elicited answers are carried in `request_state` across rounds, so each question is asked once; a resolver that resolves without eliciting is pure and may re-run each round.
1519
1519
1520
1520
Resolved parameters are omitted from the tool's input schema, so the client never supplies them. Resolver parameters that cannot be classified, and cyclic resolver dependencies, raise at registration time.
0 commit comments