From 90f2e190d00beedefbc2b7866fe3fa0db1c363a8 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sun, 26 Jul 2026 14:45:55 -0400 Subject: [PATCH] Silence ty deprecation diagnostics and drop stale sampling doc mentions --- docs/servers/telemetry.mdx | 6 +++--- docs/servers/tools.mdx | 11 ++--------- tests/client/test_roots.py | 8 +++----- tests/client/test_sampling.py | 6 ++++-- tests/server/providers/proxy/test_proxy_client.py | 4 ++-- tests/server/test_protocol_eras.py | 2 +- 6 files changed, 15 insertions(+), 22 deletions(-) diff --git a/docs/servers/telemetry.mdx b/docs/servers/telemetry.mdx index 7e7356f5e..e902fe5a6 100644 --- a/docs/servers/telemetry.mdx +++ b/docs/servers/telemetry.mdx @@ -238,7 +238,7 @@ Custom spans are most useful around work that is expensive or hard to debug: - External calls such as databases, vector stores, HTTP APIs, or queue operations - Multi-step tool logic where one stage dominates latency - Prompt or resource generation that fans out to other systems -- Sampling calls made from inside a tool via `ctx.sample(...)` +- LLM calls a tool makes to a model provider Avoid wrapping every small helper function or simple in-memory transformation. That usually adds noise without making traces easier to interpret. @@ -286,9 +286,9 @@ async def docs_resource(slug: str) -> str: return await load_doc(slug) ``` -### Sampling calls inside tools +### LLM calls inside tools -If your tool uses `ctx.sample(...)`, keep the LLM work nested under the tool span so traces show both application logic and model latency together. +A tool that [calls an LLM directly](/servers/sampling) should keep the model work nested under the tool span, so traces show application logic and model latency together. For providers with their own OTEL integrations, prefer enabling that instrumentation rather than manually creating a span around every model call. For example, if you use Google GenAI, `logfire.instrument_google_genai()` will emit child spans with token and request metadata under the active FastMCP tool span. diff --git a/docs/servers/tools.mdx b/docs/servers/tools.mdx index 2e5fe4d85..197ca2340 100644 --- a/docs/servers/tools.mdx +++ b/docs/servers/tools.mdx @@ -1063,15 +1063,9 @@ async def process_data(data_uri: str, ctx: Context) -> dict: # Report progress await ctx.report_progress(progress=50, total=100) - - # Example request to the client's LLM for help - summary = await ctx.sample(f"Summarize this in 10 words: {data[:200]}") - + await ctx.report_progress(progress=100, total=100) - return { - "length": len(data), - "summary": summary.text - } + return {"length": len(data)} ``` The Context object provides access to: @@ -1079,7 +1073,6 @@ The Context object provides access to: - **Logging**: `ctx.debug()`, `ctx.info()`, `ctx.warning()`, `ctx.error()` - **Progress Reporting**: `ctx.report_progress(progress, total)` - **Resource Access**: `ctx.read_resource(uri)` -- **LLM Sampling**: `ctx.sample(...)` - **Request Information**: `ctx.request_id`, `ctx.client_id` For full documentation on the Context object and all its capabilities, see the [Context documentation](/servers/context). diff --git a/tests/client/test_roots.py b/tests/client/test_roots.py index 609bbdfd5..9d87202c0 100644 --- a/tests/client/test_roots.py +++ b/tests/client/test_roots.py @@ -16,7 +16,7 @@ def fastmcp_server(): @mcp.tool async def list_roots(context: Context) -> list[str]: - result = await context.session.list_roots() + result = await context.session.list_roots() # ty: ignore[deprecated] return [str(r.uri) for r in result.roots] return mcp @@ -58,11 +58,9 @@ class TestClientRoots: async def roots_handler(ctx) -> list[Root]: calls.append(ctx) - return [Root(uri="file://from/handler")] # ty: ignore[invalid-argument-type] + return [Root(uri="file://from/handler")] - async with Client( - fastmcp_server, mode="legacy", roots=roots_handler - ) as client: + async with Client(fastmcp_server, mode="legacy", roots=roots_handler) as client: result = await client.call_tool("list_roots", {}) assert len(calls) == 1 diff --git a/tests/client/test_sampling.py b/tests/client/test_sampling.py index e82e71093..f442419a9 100644 --- a/tests/client/test_sampling.py +++ b/tests/client/test_sampling.py @@ -23,7 +23,7 @@ async def _sample( answering a legacy server, so the stand-in server reaches the SDK session directly. """ - result = await context.session.create_message( + result = await context.session.create_message( # ty: ignore[deprecated] messages=messages, system_prompt=system_prompt, max_tokens=512, @@ -72,7 +72,9 @@ def fastmcp_server(): ), SamplingMessage( role="assistant", - content=TextContent(type="text", text="How can I assist you today?"), + content=TextContent( + type="text", text="How can I assist you today?" + ), ), ], ) diff --git a/tests/server/providers/proxy/test_proxy_client.py b/tests/server/providers/proxy/test_proxy_client.py index 7638ef1b9..caa4b9075 100644 --- a/tests/server/providers/proxy/test_proxy_client.py +++ b/tests/server/providers/proxy/test_proxy_client.py @@ -66,13 +66,13 @@ async def _backend_list_roots(context: Context) -> list[Root]: FastMCP's server API. These helpers reach the SDK session directly to stand in for a legacy upstream, which is the only thing the proxy relay forwards. """ - result = await context.session.list_roots() + result = await context.session.list_roots() # ty: ignore[deprecated] return result.roots async def _backend_sample(context: Context) -> str: """Issue a handshake-era `sampling/createMessage` from a backend server.""" - result = await context.session.create_message( + result = await context.session.create_message( # ty: ignore[deprecated] messages=[ SamplingMessage( role="user", content=TextContent(type="text", text="Hello, world!") diff --git a/tests/server/test_protocol_eras.py b/tests/server/test_protocol_eras.py index 90cae9bb4..aabb54d68 100644 --- a/tests/server/test_protocol_eras.py +++ b/tests/server/test_protocol_eras.py @@ -307,7 +307,7 @@ def test_removed_server_initiated_methods_are_absent(name): def test_server_sampling_handler_kwargs_are_rejected(kwarg): """The server-side sampling handler existed only to answer `ctx.sample()`.""" with pytest.raises(TypeError, match="SEP-2577"): - FastMCP("gone", **{kwarg: None}) + FastMCP("gone", **{kwarg: None}) # ty: ignore[invalid-argument-type] @pytest.mark.parametrize("mode", MODERN_MODES)