Skip to content

Commit 10dc173

Browse files
authored
Exercise the SEP-2575 stateless probes and SEP-2243 resource/prompt headers in the conformance fixtures (#3442)
1 parent 979208c commit 10dc173

3 files changed

Lines changed: 49 additions & 6 deletions

File tree

.github/actions/conformance/client.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
json-schema-ref-no-deref - Connect, list tools (no $ref deref)
2121
json-schema-2020-12-preservation - List tools, echo the focal inputSchema back verbatim
2222
request-metadata - Connect with all callbacks; client stamps _meta
23-
http-standard-headers - Connect, call a tool (Mcp-* headers checked)
23+
http-standard-headers - Tool, resource and prompt round-trips (Mcp-* headers checked)
2424
http-invalid-tool-headers - List tools, call every surfaced tool (x-mcp-header filter)
2525
http-custom-headers - Replay the harness's toolCalls (x-mcp-header -> Mcp-Param-*)
2626
elicitation-sep1034-client-defaults - Elicitation with default accept callback
@@ -311,11 +311,24 @@ async def run_request_metadata(server_url: str) -> None:
311311

312312
@register("http-standard-headers")
313313
async def run_http_standard_headers(server_url: str) -> None:
314-
"""Connect on the modern path so Mcp-Method / Mcp-Name / MCP-Protocol-Version are sent (SEP-2243)."""
314+
"""Touch tools, resources and prompts on the modern path so each standard header is checked (SEP-2243).
315+
316+
The scenario inspects Mcp-Method on each request and Mcp-Name on tools/call,
317+
resources/read and prompts/get, and reports methods the client never sent as
318+
SKIPPED rather than failed, so exercise one of each. initialize and
319+
notifications/initialized stay SKIPPED: the modern path discovers via
320+
server/discover and never sends them.
321+
"""
315322
async with Client(server_url, mode=client_mode()) as client:
316-
await client.list_tools()
317-
result = await client.call_tool("add_numbers", {"a": 5, "b": 3})
318-
logger.debug(f"add_numbers result: {result}")
323+
tools = await client.list_tools()
324+
if tools.tools:
325+
await client.call_tool(tools.tools[0].name, _stub_required_args(tools.tools[0].input_schema))
326+
resources = await client.list_resources()
327+
if resources.resources:
328+
await client.read_resource(resources.resources[0].uri)
329+
prompts = await client.list_prompts()
330+
if prompts.prompts:
331+
await client.get_prompt(prompts.prompts[0].name)
319332

320333

321334
def _stub_required_args(input_schema: dict[str, Any]) -> dict[str, Any]:

examples/servers/everything-server/mcp_everything_server/server.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import click
1414
from mcp.server import ServerRequestContext
15-
from mcp.server.mcpserver import Context, MCPServer, RequestStateSecurity
15+
from mcp.server.mcpserver import Context, Elicit, ElicitationResult, MCPServer, RequestStateSecurity, Resolve
1616
from mcp.server.mcpserver.exceptions import ToolError
1717
from mcp.server.mcpserver.prompts.base import Prompt, UserMessage
1818
from mcp.server.streamable_http import EventCallback, EventMessage, EventStore
@@ -350,6 +350,9 @@ def test_x_mcp_header(
350350
return f"region={region}"
351351

352352

353+
# SEP-2575 server-stateless diagnostics (the conformance scenario probes these tools by name)
354+
355+
353356
@mcp.tool()
354357
async def test_missing_capability(ctx: Context) -> str:
355358
"""Tests that a handler-raised MISSING_REQUIRED_CLIENT_CAPABILITY surfaces as a top-level JSON-RPC error.
@@ -370,6 +373,33 @@ async def test_missing_capability(ctx: Context) -> str:
370373
return "Client declared sampling capability; proceeding."
371374

372375

376+
def _ask_stream_probe() -> Elicit[UserResponse]:
377+
return Elicit("The stateless streaming probe asks for a word", UserResponse)
378+
379+
380+
@mcp.tool()
381+
async def test_streaming_elicitation(
382+
answer: Annotated[ElicitationResult[UserResponse], Resolve(_ask_stream_probe)],
383+
) -> str:
384+
"""A tool that needs elicitation, asked through a resolver (SEP-2575 / SEP-2322).
385+
386+
On 2026-07-28 the question is returned as an InputRequiredResult rather than sent
387+
on the response stream; on earlier versions it is a mid-call elicitation request.
388+
"""
389+
return f"elicitation {answer.action}"
390+
391+
392+
@mcp.tool()
393+
async def test_logging_tool(ctx: Context) -> str:
394+
"""Logs once on the request-scoped channel (SEP-2575).
395+
396+
On 2026-07-28 the message is delivered only when the request's `_meta` sets
397+
`io.modelcontextprotocol/logLevel`.
398+
"""
399+
await ctx.info("test_logging_tool ran") # pyright: ignore[reportDeprecated]
400+
return "logged through the request-scoped, logLevel-gated channel"
401+
402+
373403
# SEP-2322 InputRequiredResult fixtures (multi-round-trip / ephemeral workflow)
374404

375405
NAME_SCHEMA = {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]}

0 commit comments

Comments
 (0)