resolve
Resolver dependency injection for MCPServer tools.
A tool parameter annotated Annotated[T, Resolve(fn)] is filled by running the
resolver fn before the tool body, instead of from the LLM-supplied arguments.
Resolvers form a DAG: a resolver may declare its own Resolve(...) dependencies,
take tool arguments by name, and take the Context. A resolver may return
Elicit[T] to ask the client; the framework runs the elicitation and injects the
answer.
The framework picks the elicitation transport from the negotiated protocol. At
= 2026-07-28 it returns an
InputRequiredResultcarrying the batched questions and resumes when the client retries withinput_responses/request_state(independent resolvers are asked in one round; a resolver depending on another's answer is asked in a later round). At <= 2025-11-25 it issues a synchronouselicitation/createrequest mid-call. Only elicited outcomes are carried inrequest_stateacross rounds (so the user is asked each question once). Resolver bodies may re-run on every round; a recorded outcome is consulted only when the body asks its question again, so a resolver's own computation always wins over anything the client echoes back inrequest_state.
Whether the consumer receives the unwrapped model or the full
ElicitationResult union is decided by the consumer's annotation:
Annotated[T, Resolve(fn)]-> unwrappedT; decline/cancel aborts the call.Annotated[ElicitationResult[T], Resolve(fn)](or a specific member) -> the full outcome; the consumer branches on accept/decline/cancel.
AcceptedElicitation
Bases: BaseModel, Generic[ElicitSchemaModelT]
Result when user accepts the elicitation.
Source code in src/mcp/server/elicitation.py
21 22 23 24 25 | |
CancelledElicitation
Bases: BaseModel
Result when user cancels the elicitation.
Source code in src/mcp/server/elicitation.py
34 35 36 37 | |
DeclinedElicitation
Bases: BaseModel
Result when user declines the elicitation.
Source code in src/mcp/server/elicitation.py
28 29 30 31 | |
Resolve
Marker for Annotated[T, Resolve(fn)]: fill the parameter by running fn.
Source code in src/mcp/server/mcpserver/resolve.py
87 88 89 90 91 | |
Elicit
Bases: Generic[T]
A resolver's request to ask the client.
Returned from a resolver to signal that the value must be elicited. The
framework runs ctx.elicit(message, schema) and injects the outcome.
Source code in src/mcp/server/mcpserver/resolve.py
94 95 96 97 98 99 100 101 102 103 | |
find_resolved_parameters
Find parameters of fn annotated Annotated[_, Resolve(...)].
Returns a mapping of parameter name to (Resolve, wants_union), where
wants_union is True when the annotated type is an ElicitationResult member
(the consumer wants the full outcome rather than the unwrapped model).
Source code in src/mcp/server/mcpserver/resolve.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | |
returns_input_required
True when fn's return annotation carries an InputRequiredResult arm.
Used at tool registration to reject combining Resolve(...) parameters with a
hand-rolled InputRequiredResult flow: a call has a single
input_responses/request_state channel, so the two flows would overwrite
each other's state and the call could never converge.
Source code in src/mcp/server/mcpserver/resolve.py
185 186 187 188 189 190 191 192 193 | |
build_resolver_plans
build_resolver_plans(
resolved_params: Mapping[str, tuple[Resolve, bool]],
tool_arg_names: set[str],
) -> dict[Hashable, _ResolverPlan]
Statically analyze the resolver DAG rooted at a tool's resolved parameters.
Raises:
| Type | Description |
|---|---|
InvalidSignature
|
If a resolver has a cyclic dependency, or a resolver
parameter cannot be classified (not a |
Source code in src/mcp/server/mcpserver/resolve.py
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | |
resolve_arguments
async
resolve_arguments(
resolved_params: Mapping[str, tuple[Resolve, bool]],
plans: Mapping[Hashable, _ResolverPlan],
tool_args: Mapping[str, Any],
context: Context[Any, Any],
) -> dict[str, Any] | InputRequiredResult
Resolve every Resolve-marked tool parameter into a concrete value.
Returns the mapping of tool parameter name to injected value when every
resolver is satisfied. When a resolver still needs client input (and the
negotiated protocol is >= 2026-07-28), returns an InputRequiredResult
carrying the batched questions instead; the tool body is not run.
Each question is asked once - its answer is carried in request_state across
rounds and satisfies the question when the resolver asks it again. Resolver
bodies themselves may re-run on each round; a recorded answer is consulted
only when the body asks, never in place of running it.
Raises:
| Type | Description |
|---|---|
ToolError
|
If an elicited value is declined or cancelled and the consumer asked for the unwrapped model (rather than the result union). |
Source code in src/mcp/server/mcpserver/resolve.py
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | |