Move OpenAI sampling handler out of experimental

- Move from fastmcp.experimental.sampling.handlers.openai to fastmcp.server.sampling.openai
- Update docs and tests to use new import path
- Remove experimental handlers directory
This commit is contained in:
Jeremiah Lowin 2025-12-09 15:07:13 -05:00
commit d34f065417
6 changed files with 23 additions and 33 deletions

View file

@ -463,7 +463,7 @@ FastMCP provides an OpenAI-compatible sampling handler that supports both basic
import os
from openai import OpenAI
from fastmcp import FastMCP
from fastmcp.experimental.sampling.handlers.openai import OpenAISamplingHandler
from fastmcp.server.sampling.openai import OpenAISamplingHandler
server = FastMCP(
name="Sampling Server",
@ -487,7 +487,7 @@ import os
from openai import OpenAI
from fastmcp import FastMCP, Context
from fastmcp.experimental.sampling.handlers.openai import OpenAISamplingHandler
from fastmcp.server.sampling.openai import OpenAISamplingHandler
async def async_main():
@ -545,7 +545,7 @@ The fallback handler fully supports sampling with tools:
```python
from fastmcp import FastMCP, Context
from fastmcp.experimental.sampling.handlers.openai import OpenAISamplingHandler
from fastmcp.server.sampling.openai import OpenAISamplingHandler
from openai import OpenAI
import os

View file

@ -1,21 +0,0 @@
from abc import ABC, abstractmethod
from collections.abc import Awaitable
from mcp import ClientSession, CreateMessageResult
from mcp.server.session import ServerSession
from mcp.shared.context import LifespanContextT, RequestContext
from mcp.types import CreateMessageRequestParams as SamplingParams
from mcp.types import (
SamplingMessage,
)
class BaseLLMSamplingHandler(ABC):
@abstractmethod
def __call__(
self,
messages: list[SamplingMessage],
params: SamplingParams,
context: RequestContext[ServerSession, LifespanContextT]
| RequestContext[ClientSession, LifespanContextT],
) -> str | CreateMessageResult | Awaitable[str | CreateMessageResult]: ...

View file

@ -1,5 +1,7 @@
"""OpenAI sampling handler for FastMCP servers."""
import json
from collections.abc import Iterator, Sequence
from collections.abc import Awaitable, Callable, Iterator, Sequence
from typing import Any, get_args
from mcp import ClientSession, ServerSession
@ -35,20 +37,30 @@ try:
from openai.types.shared_params import FunctionDefinition
except ImportError as e:
raise ImportError(
"The `openai` package is not installed. Please install `fastmcp[openai]` or add `openai` to your dependencies manually."
"The `openai` package is not installed. "
"Please install `fastmcp[openai]` or add `openai` to your dependencies manually."
) from e
from typing_extensions import override
from fastmcp.experimental.sampling.handlers.base import BaseLLMSamplingHandler
SamplingHandlerResult = str | CreateMessageResult | CreateMessageResultWithTools
ServerSamplingHandler = Callable[
[
list[SamplingMessage],
SamplingParams,
RequestContext[ServerSession, LifespanContextT],
],
SamplingHandlerResult | Awaitable[SamplingHandlerResult],
]
class OpenAISamplingHandler(BaseLLMSamplingHandler):
class OpenAISamplingHandler:
"""Sampling handler that uses the OpenAI API."""
def __init__(self, default_model: ChatModel, client: OpenAI | None = None):
self.client: OpenAI = client or OpenAI()
self.default_model: ChatModel = default_model
@override
async def __call__(
self,
messages: list[SamplingMessage],

View file

@ -18,7 +18,7 @@ from openai.types.chat import (
)
from openai.types.chat.chat_completion import Choice
from fastmcp.experimental.sampling.handlers.openai import OpenAISamplingHandler
from fastmcp.server.sampling.openai import OpenAISamplingHandler
def test_convert_sampling_messages_to_openai_messages():

3
uv.lock generated
View file

@ -765,8 +765,7 @@ provides-extras = ["anthropic", "openai"]
dev = [
{ name = "dirty-equals", specifier = ">=0.9.0" },
{ name = "fastapi", specifier = ">=0.115.12" },
{ name = "fastmcp", extras = ["anthropic"] },
{ name = "fastmcp", extras = ["openai"] },
{ name = "fastmcp", extras = ["anthropic", "openai"] },
{ name = "inline-snapshot", extras = ["dirty-equals"], specifier = ">=0.27.2" },
{ name = "ipython", specifier = ">=8.12.3" },
{ name = "pdbpp", specifier = ">=0.11.7" },