Skip to content

Commit d58f15d

Browse files
committed
Make the feature-walk tests the canonical resolver pins
Applies the review round: the six older tests each superseded by a feature-walk test are deleted (weaker assertions, legacy-only arms, or internals-level schema inspection), the SDK-authored decline message is pinned via inline-snapshot, never-invoked handler bodies raise NotImplementedError, results assert is_error, the elicit test asserts the negotiated revision per arm so the era matrix cannot silently collapse, and the decline tests reuse the module's _decline helper.
1 parent 0016c5f commit d58f15d

1 file changed

Lines changed: 22 additions & 136 deletions

File tree

tests/server/mcpserver/test_resolve.py

Lines changed: 22 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -198,42 +198,6 @@ def _wire_key(fn: Callable[..., Any]) -> str:
198198
return f"{fn.__module__}:{fn.__qualname__}"
199199

200200

201-
@pytest.mark.anyio
202-
async def test_resolver_returns_value_directly_without_eliciting():
203-
mcp = MCPServer(name="Direct", request_state_security=RequestStateSecurity.ephemeral())
204-
205-
async def login(ctx: Context) -> Login | Elicit[Login]:
206-
username = (ctx.headers or {}).get("x-github-user")
207-
if username: # pragma: no cover - no headers on in-memory transport
208-
return Login(username=username)
209-
return Login(username="from-resolver")
210-
211-
@mcp.tool()
212-
async def whoami(login: Annotated[Login, Resolve(login)]) -> str:
213-
return login.username
214-
215-
async def never(context: ClientRequestContext, params: ElicitRequestParams) -> ElicitResult: # pragma: no cover
216-
raise AssertionError("should not elicit")
217-
218-
async with Client(mcp, mode="legacy", elicitation_callback=never) as client:
219-
assert await _text(client, "whoami", {}) == "from-resolver"
220-
221-
222-
@pytest.mark.anyio
223-
async def test_resolver_elicits_and_injects_unwrapped_model_on_accept():
224-
mcp = MCPServer(name="Accept", request_state_security=RequestStateSecurity.ephemeral())
225-
226-
async def login(ctx: Context) -> Login | Elicit[Login]:
227-
return Elicit("GitHub username?", Login)
228-
229-
@mcp.tool()
230-
async def whoami(login: Annotated[Login, Resolve(login)]) -> str:
231-
return login.username
232-
233-
async with Client(mcp, mode="legacy", elicitation_callback=_accept({"username": "octocat"})) as client:
234-
assert await _text(client, "whoami", {}) == "octocat"
235-
236-
237201
@pytest.mark.anyio
238202
async def test_consumer_receives_result_union_and_branches():
239203
mcp = MCPServer(name="Union", request_state_security=RequestStateSecurity.ephemeral())
@@ -253,43 +217,6 @@ async def whoami(login: Annotated[ElicitationResult[Login], Resolve(login)]) ->
253217
assert await _text(client, "whoami", {}) == "hi octocat"
254218

255219

256-
@pytest.mark.anyio
257-
async def test_decline_reaches_union_consumer_without_aborting():
258-
mcp = MCPServer(name="UnionDecline", request_state_security=RequestStateSecurity.ephemeral())
259-
260-
async def login(ctx: Context) -> Login | Elicit[Login]:
261-
return Elicit("GitHub username?", Login)
262-
263-
@mcp.tool()
264-
async def whoami(
265-
login: Annotated[AcceptedElicitation[Login] | DeclinedElicitation | CancelledElicitation, Resolve(login)],
266-
) -> str:
267-
if isinstance(login, DeclinedElicitation):
268-
return "declined gracefully"
269-
raise NotImplementedError
270-
271-
async with Client(mcp, mode="legacy", elicitation_callback=_decline) as client:
272-
assert await _text(client, "whoami", {}) == "declined gracefully"
273-
274-
275-
@pytest.mark.anyio
276-
async def test_decline_aborts_when_consumer_wants_unwrapped():
277-
mcp = MCPServer(name="UnwrappedDecline", request_state_security=RequestStateSecurity.ephemeral())
278-
279-
async def login(ctx: Context) -> Login | Elicit[Login]:
280-
return Elicit("GitHub username?", Login)
281-
282-
@mcp.tool()
283-
async def whoami(login: Annotated[Login, Resolve(login)]) -> str:
284-
raise NotImplementedError # pragma: no cover - never reached
285-
286-
async with Client(mcp, mode="legacy", elicitation_callback=_decline) as client:
287-
result = await client.call_tool("whoami", {})
288-
assert result.is_error
289-
assert isinstance(result.content[0], TextContent)
290-
assert "decline" in result.content[0].text
291-
292-
293220
@pytest.mark.anyio
294221
async def test_nested_resolver_sees_dependency_and_tool_args():
295222
mcp = MCPServer(name="Nested", request_state_security=RequestStateSecurity.ephemeral())
@@ -369,22 +296,6 @@ async def never(context: ClientRequestContext, params: ElicitRequestParams) -> E
369296
assert await _text(client, "whoami", {}) == "sync-user"
370297

371298

372-
def test_resolved_params_absent_from_input_schema():
373-
async def login(ctx: Context) -> Login:
374-
return Login(username="x") # pragma: no cover - only the schema is inspected
375-
376-
async def tool(
377-
repo: Annotated[str, Field(description="repo name")],
378-
login: Annotated[Login, Resolve(login)],
379-
) -> str:
380-
return repo # pragma: no cover - only the schema is inspected
381-
382-
built = Tool.from_function(tool)
383-
properties = built.parameters["properties"]
384-
assert "repo" in properties
385-
assert "login" not in properties
386-
387-
388299
def test_cycle_detection_raises_at_registration():
389300
async def a(dep: Login) -> Login:
390301
return dep # pragma: no cover
@@ -1140,28 +1051,6 @@ async def empty_accept(context: ClientRequestContext, params: ElicitRequestParam
11401051
assert "no content" in result.content[0].text
11411052

11421053

1143-
@pytest.mark.anyio
1144-
async def test_eliciting_tool_without_client_capability_is_a_protocol_error():
1145-
# The server must not send an `input_requests` entry the client has not declared
1146-
# capability for: with no `elicitation` declared (no callback), the call fails as
1147-
# a -32021 protocol error, not a CallToolResult execution failure.
1148-
mcp = MCPServer(name="NoElicitationCapability", request_state_security=RequestStateSecurity.ephemeral())
1149-
1150-
async def ask(ctx: Context) -> Elicit[Login]:
1151-
return Elicit("user?", Login)
1152-
1153-
@mcp.tool()
1154-
async def tool(login: Annotated[Login, Resolve(ask)]) -> str:
1155-
return login.username # pragma: no cover
1156-
1157-
async with Client(mcp) as client:
1158-
with pytest.raises(MCPError) as exc_info:
1159-
await client.session.call_tool("tool", {}, allow_input_required=True)
1160-
assert exc_info.value.code == MISSING_REQUIRED_CLIENT_CAPABILITY
1161-
assert exc_info.value.error.data is not None
1162-
assert "elicitation" in exc_info.value.error.data["requiredCapabilities"]
1163-
1164-
11651054
@pytest.mark.anyio
11661055
async def test_independent_nested_deps_batch_into_one_round():
11671056
mcp = MCPServer(name="NestedBatch", request_state_security=RequestStateSecurity.ephemeral())
@@ -2802,6 +2691,7 @@ async def quote(title: str, price: Annotated[int, Resolve(price_of)]) -> str:
28022691
async with Client(mcp) as client:
28032692
result = await client.call_tool("quote", {"title": "Dune"})
28042693

2694+
assert not result.is_error
28052695
assert result.content == [TextContent(type="text", text="Dune: 42")]
28062696

28072697

@@ -2824,6 +2714,7 @@ async def quote(title: str, total: Annotated[int, Resolve(with_tax)]) -> str:
28242714
async with Client(mcp) as client:
28252715
result = await client.call_tool("quote", {"title": "Dune"})
28262716

2717+
assert not result.is_error
28272718
assert result.content == [TextContent(type="text", text="Dune costs 20")]
28282719

28292720

@@ -2843,6 +2734,7 @@ async def quote(title: str, price: Annotated[int, Resolve(price_of)]) -> str:
28432734
async with Client(mcp) as client:
28442735
result = await client.call_tool("quote", {"title": "Dune", "price": 999})
28452736

2737+
assert not result.is_error
28462738
assert result.content == [TextContent(type="text", text="Dune: 42")]
28472739

28482740

@@ -2853,11 +2745,11 @@ async def test_resolved_parameters_are_absent_from_the_advertised_tool_schema():
28532745
mcp = MCPServer(name="Walk", request_state_security=RequestStateSecurity.ephemeral())
28542746

28552747
def price_of(title: str) -> int:
2856-
return 42 # pragma: no cover - only the schema is inspected
2748+
raise NotImplementedError # pragma: no cover - only the schema is inspected
28572749

28582750
@mcp.tool()
28592751
async def quote(title: str, price: Annotated[int, Resolve(price_of)]) -> str:
2860-
return f"{title}: {price}" # pragma: no cover - only the schema is inspected
2752+
raise NotImplementedError # pragma: no cover - only the schema is inspected
28612753

28622754
async with Client(mcp) as client:
28632755
(advertised,) = (await client.list_tools()).tools
@@ -2879,11 +2771,6 @@ async def test_an_elicit_marker_asks_the_client_and_injects_the_accepted_answer(
28792771
callback and the tool receives the validated model, identically over the 2025
28802772
back-channel and the 2026 multi-round-trip flow. SDK-defined injection contract."""
28812773
mcp = MCPServer(name="Walk", request_state_security=RequestStateSecurity.ephemeral())
2882-
asked: list[str] = []
2883-
2884-
async def on_elicit(context: ClientRequestContext, params: ElicitRequestParams) -> ElicitResult:
2885-
asked.append(params.message)
2886-
return ElicitResult(action="accept", content={"username": "octocat"})
28872774

28882775
def ask(ctx: Context) -> Elicit[Login]:
28892776
return Elicit("GitHub username?", Login)
@@ -2892,9 +2779,18 @@ def ask(ctx: Context) -> Elicit[Login]:
28922779
async def whoami(login: Annotated[Login, Resolve(ask)]) -> str:
28932780
return login.username
28942781

2782+
asked: list[str] = []
2783+
2784+
async def on_elicit(context: ClientRequestContext, params: ElicitRequestParams) -> ElicitResult:
2785+
asked.append(params.message)
2786+
return ElicitResult(action="accept", content={"username": "octocat"})
2787+
28952788
async with Client(mcp, mode=mode, elicitation_callback=on_elicit) as client:
2789+
# The parametrize is only a real era matrix while the arms negotiate different revisions.
2790+
assert client.protocol_version == ("2025-11-25" if mode == "legacy" else "2026-07-28")
28962791
result = await client.call_tool("whoami", {})
28972792

2793+
assert not result.is_error
28982794
assert result.content == [TextContent(type="text", text="octocat")]
28992795
assert asked == ["GitHub username?"]
29002796

@@ -2907,28 +2803,21 @@ async def test_a_declined_elicitation_fails_the_call_for_a_plain_model_consumer(
29072803
the SDK's contract for plain-model consumers."""
29082804
mcp = MCPServer(name="Walk", request_state_security=RequestStateSecurity.ephemeral())
29092805

2910-
async def on_elicit(context: ClientRequestContext, params: ElicitRequestParams) -> ElicitResult:
2911-
return ElicitResult(action="decline")
2912-
29132806
def ask(ctx: Context) -> Elicit[Login]:
29142807
return Elicit("GitHub username?", Login)
29152808

29162809
@mcp.tool()
29172810
async def whoami(login: Annotated[Login, Resolve(ask)]) -> str:
2918-
return login.username # pragma: no cover - the decline aborts before the body
2811+
raise NotImplementedError # pragma: no cover - the decline aborts before the body
29192812

2920-
async with Client(mcp, mode=mode, elicitation_callback=on_elicit) as client:
2813+
async with Client(mcp, mode=mode, elicitation_callback=_decline) as client:
29212814
result = await client.call_tool("whoami", {})
29222815

29232816
assert result.is_error
2924-
assert result.content == [
2925-
TextContent(
2926-
type="text",
2927-
text=(
2928-
"Error executing tool whoami: Resolver for parameter 'login' could not resolve: elicitation was decline"
2929-
),
2930-
)
2931-
]
2817+
assert isinstance(result.content[0], TextContent)
2818+
assert result.content[0].text == snapshot(
2819+
"Error executing tool whoami: Resolver for parameter 'login' could not resolve: elicitation was decline"
2820+
)
29322821

29332822

29342823
@pytest.mark.anyio
@@ -2940,9 +2829,6 @@ async def test_a_declined_elicitation_reaches_a_consumer_that_asked_for_the_outc
29402829
of aborting the call. SDK-defined consumer-annotation contract."""
29412830
mcp = MCPServer(name="Walk", request_state_security=RequestStateSecurity.ephemeral())
29422831

2943-
async def on_elicit(context: ClientRequestContext, params: ElicitRequestParams) -> ElicitResult:
2944-
return ElicitResult(action="decline")
2945-
29462832
def ask(ctx: Context) -> Elicit[Login]:
29472833
return Elicit("GitHub username?", Login)
29482834

@@ -2952,7 +2838,7 @@ async def whoami(login: Annotated[ElicitationResult[Login], Resolve(ask)]) -> st
29522838
return login.data.username # pragma: no cover - declined in this test
29532839
return "anonymous"
29542840

2955-
async with Client(mcp, mode=mode, elicitation_callback=on_elicit) as client:
2841+
async with Client(mcp, mode=mode, elicitation_callback=_decline) as client:
29562842
result = await client.call_tool("whoami", {})
29572843

29582844
assert not result.is_error
@@ -2972,7 +2858,7 @@ def ask(ctx: Context) -> Elicit[Login]:
29722858

29732859
@mcp.tool()
29742860
async def whoami(login: Annotated[Login, Resolve(ask)]) -> str:
2975-
return login.username # pragma: no cover - the gate refuses before the body
2861+
raise NotImplementedError # pragma: no cover - the gate refuses before the body
29762862

29772863
async with Client(mcp, mode=mode) as client:
29782864
with pytest.raises(MCPError) as exc_info:

0 commit comments

Comments
 (0)