diff --git a/docs/clients/roots.mdx b/docs/clients/roots.mdx index 9de83cf61..08f5c9786 100644 --- a/docs/clients/roots.mdx +++ b/docs/clients/roots.mdx @@ -24,7 +24,7 @@ from fastmcp import Client client = Client( "my_mcp_server.py", - roots=["/path/to/root1", "/path/to/root2"] + roots=["file:///path/to/root1", "file:///path/to/root2"] ) ``` @@ -38,7 +38,7 @@ from fastmcp.client.roots import RequestContext async def roots_callback(context: RequestContext) -> list[str]: print(f"Server requested roots (Request ID: {context.request_id})") - return ["/path/to/root1", "/path/to/root2"] + return ["file:///path/to/root1", "file:///path/to/root2"] client = Client( "my_mcp_server.py", diff --git a/tests/conformance/expected-failures.yml b/tests/conformance/expected-failures.yml index 28ece5894..9e3ed9dde 100644 --- a/tests/conformance/expected-failures.yml +++ b/tests/conformance/expected-failures.yml @@ -21,9 +21,3 @@ server: # need the tool to declare which one it wants, which is an unmade API # decision rather than a bug. - tasks-mrtr-composition - - # Server-initiated sampling was removed from the server API (SEP-2577), so the - # fixture has no `test_sampling` tool for this handshake-era scenario to drive. - # Modern sampling rides the guard pattern and is covered by - # input-required-result-basic-sampling. - - tools-call-sampling diff --git a/tests/conformance/server.py b/tests/conformance/server.py index 12d58f802..cc8a020ae 100644 --- a/tests/conformance/server.py +++ b/tests/conformance/server.py @@ -173,6 +173,31 @@ async def test_tool_with_progress(ctx: Context) -> str: return "Progress test complete." +@server.tool(name="test_sampling") +async def test_sampling(prompt: str, ctx: Context) -> str: + """Requests LLM sampling via the client. + + `Context` has no `sample()` — server-initiated sampling is not part of + FastMCP's server API. The handshake-era wire path is still supported and + still shipped (the proxy relay uses it), so this fixture reaches the SDK + session directly to keep the scenario covered. + """ + result = await ctx.session.create_message( # ty: ignore[deprecated] + messages=[ + mcp_types.SamplingMessage( + role="user", + content=mcp_types.TextContent(type="text", text=prompt), + ) + ], + max_tokens=512, + related_request_id=ctx.origin_request_id, + ) + text = ( + result.content.text if isinstance(result.content, mcp_types.TextContent) else "" + ) + return f"Sampling result: {text}" + + class _UserInfo(BaseModel): username: str email: str