Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
84f1736
MCP → SDK (vocab change only)
jlowin Dec 4, 2025
5fb9103
WIP: Sampling API with SamplingResult[T] and result_type
jlowin Dec 4, 2025
0d8679c
SEP-1577: Sampling with tools
jlowin Dec 4, 2025
ead4730
Fix tool result content handling in OpenAI handler
jlowin Dec 4, 2025
5c0f055
Remove @sampling_tool decorator - pass functions directly to sample()
jlowin Dec 5, 2025
b544cdd
Merge main into sampling-tools-sep-1577
jlowin Dec 5, 2025
1cf947b
Merge main into sampling-tools-sep-1577
github-actions[bot] Dec 10, 2025
4b5bfe6
Remove auto-conversion of MCP tools to sampling tools
jlowin Dec 12, 2025
1d7c1da
Merge branch 'main' into sampling-tools-sep-1577
jlowin Dec 14, 2025
7796179
Merge branch 'main' into sampling-tools-sep-1577
jlowin Dec 14, 2025
2cdc9b6
Refactor sampling API: replace sample_iter() with sample_step()
jlowin Dec 14, 2025
5e6c790
Address CodeRabbit nitpicks
jlowin Dec 14, 2025
1ef5319
Address CodeRabbit review feedback for sampling tools
jlowin Dec 14, 2025
b079fe5
Address additional CodeRabbit review feedback
jlowin Dec 14, 2025
07df7c6
Review fixes for sampling tools PR
jlowin Dec 14, 2025
1bba6e0
Fix OpenAI handler tests to use AsyncOpenAI
jlowin Dec 14, 2025
6bc676e
Merge branch 'main' into sampling-tools-sep-1577
jlowin Dec 14, 2025
5629f24
Address remaining CodeRabbit review comments
jlowin Dec 14, 2025
0d9272e
Add return type annotation to OpenAISamplingHandler.__init__
jlowin Dec 14, 2025
2c63948
Use explicit 'is not None' check for sampling_capabilities defaulting
jlowin Dec 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion docs/clients/sampling.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ The sampling handler receives three parameters:
<ResponseField name="metadata" type="dict[str, Any] | None">
Optional metadata to pass through to the LLM provider.
</ResponseField>

<ResponseField name="tools" type="list[Tool] | None">
Optional list of tools the LLM can use during sampling. See [Using the OpenAI Handler](#using-the-openai-handler).
</ResponseField>

<ResponseField name="toolChoice" type="ToolChoice | None">
Optional control over tool usage behavior (`auto`, `required`, or `none`).
</ResponseField>
</Expandable>

</ResponseField>
Expand Down Expand Up @@ -153,4 +161,56 @@ client = Client(

<Note>
If the client doesn't provide a sampling handler, servers can optionally configure a fallback handler. See [Server Sampling](/servers/sampling#sampling-fallback-handler) for details.
</Note>
</Note>

## Sampling Capabilities

When you provide a `sampling_handler`, FastMCP automatically advertises full sampling capabilities to the server, including tool support. To disable tool support (for simpler handlers that don't support tools), pass `sampling_capabilities` explicitly:

```python
from mcp.types import SamplingCapability

client = Client(
"my_mcp_server.py",
sampling_handler=basic_handler,
sampling_capabilities=SamplingCapability(), # No tool support
)
```
Comment on lines +166 to +178

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify what “SamplingCapability()” disables (tools only vs sampling entirely).

The comment says “No tool support”, but SamplingCapability() reads like “no sampling features at all”. Consider showing SamplingCapability(tools=None) (or the exact “no-tools” shape) and stating what remains enabled.

🤖 Prompt for AI Agents
In docs/clients/sampling.mdx around lines 166 to 178, the example and text are
ambiguous about what SamplingCapability() disables; update the example to show
the explicit no-tools shape (e.g., SamplingCapability(tools=None) or the exact
parameter name used in the codebase) and change the surrounding copy to clearly
state that only tool support is being disabled while sampling itself (and other
capabilities) remains enabled; include the explicit shape and a short sentence
listing what still remains enabled.


## Using the OpenAI Handler

<VersionBadge version="2.14.0" />

For full-featured sampling with tool support, use the built-in OpenAI handler. It handles message conversion, tool calls, and response formatting automatically:

```python
from fastmcp import Client
from fastmcp.experimental.sampling.handlers.openai import OpenAISamplingHandler

client = Client(
"my_mcp_server.py",
sampling_handler=OpenAISamplingHandler(default_model="gpt-4o"),
)
```

The handler works with any OpenAI-compatible API by passing a custom client:

```python
from openai import AsyncOpenAI

client = Client(
"my_mcp_server.py",
sampling_handler=OpenAISamplingHandler(
default_model="llama-3.1-70b",
client=AsyncOpenAI(base_url="http://localhost:8000/v1"),
),
)
```

<Note>
Tool execution happens on the server side. The client's role is to pass tools to the LLM and return the LLM's response (which may include tool use requests). The server then executes the tools and may send follow-up sampling requests with tool results.
</Note>

<Tip>
To implement a custom sampling handler, see the [OpenAISamplingHandler source code](https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/experimental/sampling/handlers/openai.py) as a reference.
</Tip>
Loading
Loading