fastmcp 2.13.3__py3-none-any.whl → 2.14.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastmcp/__init__.py +0 -21
- fastmcp/cli/__init__.py +0 -3
- fastmcp/cli/__main__.py +5 -0
- fastmcp/cli/cli.py +8 -22
- fastmcp/cli/install/shared.py +0 -15
- fastmcp/cli/tasks.py +110 -0
- fastmcp/client/auth/oauth.py +9 -9
- fastmcp/client/client.py +739 -136
- fastmcp/client/elicitation.py +11 -5
- fastmcp/client/messages.py +7 -5
- fastmcp/client/roots.py +2 -1
- fastmcp/client/sampling/__init__.py +69 -0
- fastmcp/client/sampling/handlers/__init__.py +0 -0
- fastmcp/client/sampling/handlers/anthropic.py +387 -0
- fastmcp/client/sampling/handlers/openai.py +399 -0
- fastmcp/client/tasks.py +551 -0
- fastmcp/client/transports.py +72 -21
- fastmcp/contrib/component_manager/component_service.py +4 -20
- fastmcp/dependencies.py +25 -0
- fastmcp/experimental/sampling/handlers/__init__.py +5 -0
- fastmcp/experimental/sampling/handlers/openai.py +4 -169
- fastmcp/experimental/server/openapi/__init__.py +15 -13
- fastmcp/experimental/utilities/openapi/__init__.py +12 -38
- fastmcp/prompts/prompt.py +38 -38
- fastmcp/resources/resource.py +33 -16
- fastmcp/resources/template.py +69 -59
- fastmcp/server/auth/__init__.py +0 -9
- fastmcp/server/auth/auth.py +127 -3
- fastmcp/server/auth/oauth_proxy.py +47 -97
- fastmcp/server/auth/oidc_proxy.py +7 -0
- fastmcp/server/auth/providers/in_memory.py +2 -2
- fastmcp/server/auth/providers/oci.py +2 -2
- fastmcp/server/context.py +509 -180
- fastmcp/server/dependencies.py +464 -6
- fastmcp/server/elicitation.py +285 -47
- fastmcp/server/event_store.py +177 -0
- fastmcp/server/http.py +15 -3
- fastmcp/server/low_level.py +56 -12
- fastmcp/server/middleware/middleware.py +2 -2
- fastmcp/server/openapi/__init__.py +35 -0
- fastmcp/{experimental/server → server}/openapi/components.py +4 -3
- fastmcp/{experimental/server → server}/openapi/routing.py +1 -1
- fastmcp/{experimental/server → server}/openapi/server.py +6 -5
- fastmcp/server/proxy.py +53 -40
- fastmcp/server/sampling/__init__.py +10 -0
- fastmcp/server/sampling/run.py +301 -0
- fastmcp/server/sampling/sampling_tool.py +108 -0
- fastmcp/server/server.py +793 -552
- fastmcp/server/tasks/__init__.py +21 -0
- fastmcp/server/tasks/capabilities.py +22 -0
- fastmcp/server/tasks/config.py +89 -0
- fastmcp/server/tasks/converters.py +206 -0
- fastmcp/server/tasks/handlers.py +356 -0
- fastmcp/server/tasks/keys.py +93 -0
- fastmcp/server/tasks/protocol.py +355 -0
- fastmcp/server/tasks/subscriptions.py +205 -0
- fastmcp/settings.py +101 -103
- fastmcp/tools/tool.py +83 -49
- fastmcp/tools/tool_transform.py +1 -12
- fastmcp/utilities/components.py +3 -3
- fastmcp/utilities/json_schema_type.py +4 -4
- fastmcp/utilities/mcp_config.py +1 -2
- fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +1 -1
- fastmcp/{experimental/utilities → utilities}/openapi/README.md +7 -35
- fastmcp/utilities/openapi/__init__.py +63 -0
- fastmcp/{experimental/utilities → utilities}/openapi/formatters.py +5 -5
- fastmcp/{experimental/utilities → utilities}/openapi/json_schema_converter.py +1 -1
- fastmcp/utilities/tests.py +11 -5
- fastmcp/utilities/types.py +8 -0
- {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/METADATA +7 -4
- {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/RECORD +79 -63
- fastmcp/client/sampling.py +0 -56
- fastmcp/experimental/sampling/handlers/base.py +0 -21
- fastmcp/server/auth/providers/bearer.py +0 -25
- fastmcp/server/openapi.py +0 -1087
- fastmcp/server/sampling/handler.py +0 -19
- fastmcp/utilities/openapi.py +0 -1568
- /fastmcp/{experimental/server → server}/openapi/README.md +0 -0
- /fastmcp/{experimental/utilities → utilities}/openapi/director.py +0 -0
- /fastmcp/{experimental/utilities → utilities}/openapi/models.py +0 -0
- /fastmcp/{experimental/utilities → utilities}/openapi/parser.py +0 -0
- /fastmcp/{experimental/utilities → utilities}/openapi/schemas.py +0 -0
- {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/WHEEL +0 -0
- {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/entry_points.txt +0 -0
- {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/licenses/LICENSE +0 -0
fastmcp/client/transports.py
CHANGED
|
@@ -6,7 +6,7 @@ import os
|
|
|
6
6
|
import shutil
|
|
7
7
|
import sys
|
|
8
8
|
import warnings
|
|
9
|
-
from collections.abc import AsyncIterator
|
|
9
|
+
from collections.abc import AsyncIterator, Callable
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any, Literal, TextIO, TypeVar, cast, overload
|
|
12
12
|
|
|
@@ -23,7 +23,7 @@ from mcp.client.session import (
|
|
|
23
23
|
)
|
|
24
24
|
from mcp.client.sse import sse_client
|
|
25
25
|
from mcp.client.stdio import stdio_client
|
|
26
|
-
from mcp.client.streamable_http import
|
|
26
|
+
from mcp.client.streamable_http import streamable_http_client
|
|
27
27
|
from mcp.server.fastmcp import FastMCP as FastMCP1Server
|
|
28
28
|
from mcp.shared._httpx_utils import McpHttpClientFactory
|
|
29
29
|
from mcp.shared.memory import create_client_server_memory_streams
|
|
@@ -36,6 +36,7 @@ from fastmcp.client.auth.oauth import OAuth
|
|
|
36
36
|
from fastmcp.mcp_config import MCPConfig, infer_transport_type_from_url
|
|
37
37
|
from fastmcp.server.dependencies import get_http_headers
|
|
38
38
|
from fastmcp.server.server import FastMCP
|
|
39
|
+
from fastmcp.server.tasks.capabilities import get_task_capabilities
|
|
39
40
|
from fastmcp.utilities.logging import get_logger
|
|
40
41
|
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment
|
|
41
42
|
|
|
@@ -65,6 +66,7 @@ class SessionKwargs(TypedDict, total=False):
|
|
|
65
66
|
|
|
66
67
|
read_timeout_seconds: datetime.timedelta | None
|
|
67
68
|
sampling_callback: SamplingFnT | None
|
|
69
|
+
sampling_capabilities: mcp.types.SamplingCapability | None
|
|
68
70
|
list_roots_callback: ListRootsFnT | None
|
|
69
71
|
logging_callback: LoggingFnT | None
|
|
70
72
|
elicitation_callback: ElicitationFnT | None
|
|
@@ -250,10 +252,22 @@ class StreamableHttpTransport(ClientTransport):
|
|
|
250
252
|
self.httpx_client_factory = httpx_client_factory
|
|
251
253
|
self._set_auth(auth)
|
|
252
254
|
|
|
255
|
+
if sse_read_timeout is not None:
|
|
256
|
+
if fastmcp.settings.deprecation_warnings:
|
|
257
|
+
warnings.warn(
|
|
258
|
+
"The `sse_read_timeout` parameter is deprecated and no longer used. "
|
|
259
|
+
"The new streamable_http_client API does not support this parameter. "
|
|
260
|
+
"Use `read_timeout_seconds` in session_kwargs or configure timeout on "
|
|
261
|
+
"the httpx client via `httpx_client_factory` instead.",
|
|
262
|
+
DeprecationWarning,
|
|
263
|
+
stacklevel=2,
|
|
264
|
+
)
|
|
253
265
|
if isinstance(sse_read_timeout, int | float):
|
|
254
266
|
sse_read_timeout = datetime.timedelta(seconds=float(sse_read_timeout))
|
|
255
267
|
self.sse_read_timeout = sse_read_timeout
|
|
256
268
|
|
|
269
|
+
self._get_session_id_cb: Callable[[], str | None] | None = None
|
|
270
|
+
|
|
257
271
|
def _set_auth(self, auth: httpx.Auth | Literal["oauth"] | str | None):
|
|
258
272
|
if auth == "oauth":
|
|
259
273
|
auth = OAuth(self.url, httpx_client_factory=self.httpx_client_factory)
|
|
@@ -265,34 +279,55 @@ class StreamableHttpTransport(ClientTransport):
|
|
|
265
279
|
async def connect_session(
|
|
266
280
|
self, **session_kwargs: Unpack[SessionKwargs]
|
|
267
281
|
) -> AsyncIterator[ClientSession]:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
# load headers from an active HTTP request, if available. This will only be true
|
|
282
|
+
# Load headers from an active HTTP request, if available. This will only be true
|
|
271
283
|
# if the client is used in a FastMCP Proxy, in which case the MCP client headers
|
|
272
284
|
# need to be forwarded to the remote server.
|
|
273
|
-
|
|
285
|
+
headers = get_http_headers() | self.headers
|
|
274
286
|
|
|
275
|
-
#
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
287
|
+
# Build httpx client configuration
|
|
288
|
+
httpx_client_kwargs: dict[str, Any] = {
|
|
289
|
+
"headers": headers,
|
|
290
|
+
"auth": self.auth,
|
|
291
|
+
"follow_redirects": True,
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
# Configure timeout if provided (convert timedelta to seconds for httpx)
|
|
279
295
|
if session_kwargs.get("read_timeout_seconds") is not None:
|
|
280
|
-
|
|
296
|
+
read_timeout_seconds = cast(
|
|
297
|
+
datetime.timedelta, session_kwargs.get("read_timeout_seconds")
|
|
298
|
+
)
|
|
299
|
+
httpx_client_kwargs["timeout"] = read_timeout_seconds.total_seconds()
|
|
281
300
|
|
|
301
|
+
# Create httpx client from factory or use default
|
|
282
302
|
if self.httpx_client_factory is not None:
|
|
283
|
-
|
|
303
|
+
http_client = self.httpx_client_factory(**httpx_client_kwargs)
|
|
304
|
+
else:
|
|
305
|
+
http_client = httpx.AsyncClient(**httpx_client_kwargs)
|
|
284
306
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
)
|
|
290
|
-
read_stream, write_stream,
|
|
307
|
+
# Ensure httpx client is closed after use
|
|
308
|
+
async with (
|
|
309
|
+
http_client,
|
|
310
|
+
streamable_http_client(self.url, http_client=http_client) as transport,
|
|
311
|
+
):
|
|
312
|
+
read_stream, write_stream, get_session_id = transport
|
|
313
|
+
self._get_session_id_cb = get_session_id
|
|
291
314
|
async with ClientSession(
|
|
292
315
|
read_stream, write_stream, **session_kwargs
|
|
293
316
|
) as session:
|
|
294
317
|
yield session
|
|
295
318
|
|
|
319
|
+
def get_session_id(self) -> str | None:
|
|
320
|
+
if self._get_session_id_cb:
|
|
321
|
+
try:
|
|
322
|
+
return self._get_session_id_cb()
|
|
323
|
+
except Exception:
|
|
324
|
+
return None
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
async def close(self):
|
|
328
|
+
# Reset the session id callback
|
|
329
|
+
self._get_session_id_cb = None
|
|
330
|
+
|
|
296
331
|
def __repr__(self) -> str:
|
|
297
332
|
return f"<StreamableHttpTransport(url='{self.url}')>"
|
|
298
333
|
|
|
@@ -375,7 +410,8 @@ class StdioTransport(ClientTransport):
|
|
|
375
410
|
env=self.env,
|
|
376
411
|
cwd=self.cwd,
|
|
377
412
|
log_file=self.log_file,
|
|
378
|
-
|
|
413
|
+
# TODO(ty): remove when ty supports Unpack[TypedDict] inference
|
|
414
|
+
session_kwargs=session_kwargs, # type: ignore[arg-type]
|
|
379
415
|
ready_event=self._ready_event,
|
|
380
416
|
stop_event=self._stop_event,
|
|
381
417
|
session_future=session_future,
|
|
@@ -849,16 +885,25 @@ class FastMCPTransport(ClientTransport):
|
|
|
849
885
|
client_read, client_write = client_streams
|
|
850
886
|
server_read, server_write = server_streams
|
|
851
887
|
|
|
852
|
-
#
|
|
888
|
+
# Capture exceptions to re-raise after task group cleanup.
|
|
889
|
+
# anyio task groups can suppress exceptions when cancel_scope.cancel()
|
|
890
|
+
# is called during cleanup, so we capture and re-raise manually.
|
|
891
|
+
exception_to_raise: BaseException | None = None
|
|
892
|
+
|
|
853
893
|
async with (
|
|
854
894
|
anyio.create_task_group() as tg,
|
|
855
895
|
_enter_server_lifespan(server=self.server),
|
|
856
896
|
):
|
|
897
|
+
# Build experimental capabilities
|
|
898
|
+
experimental_capabilities = get_task_capabilities()
|
|
899
|
+
|
|
857
900
|
tg.start_soon(
|
|
858
901
|
lambda: self.server._mcp_server.run(
|
|
859
902
|
server_read,
|
|
860
903
|
server_write,
|
|
861
|
-
self.server._mcp_server.create_initialization_options(
|
|
904
|
+
self.server._mcp_server.create_initialization_options(
|
|
905
|
+
experimental_capabilities=experimental_capabilities
|
|
906
|
+
),
|
|
862
907
|
raise_exceptions=self.raise_exceptions,
|
|
863
908
|
)
|
|
864
909
|
)
|
|
@@ -870,9 +915,15 @@ class FastMCPTransport(ClientTransport):
|
|
|
870
915
|
**session_kwargs,
|
|
871
916
|
) as client_session:
|
|
872
917
|
yield client_session
|
|
918
|
+
except BaseException as e:
|
|
919
|
+
exception_to_raise = e
|
|
873
920
|
finally:
|
|
874
921
|
tg.cancel_scope.cancel()
|
|
875
922
|
|
|
923
|
+
# Re-raise after task group has exited cleanly
|
|
924
|
+
if exception_to_raise is not None:
|
|
925
|
+
raise exception_to_raise
|
|
926
|
+
|
|
876
927
|
def __repr__(self) -> str:
|
|
877
928
|
return f"<FastMCPTransport(server='{self.server.name}')>"
|
|
878
929
|
|
|
@@ -105,16 +105,8 @@ class ComponentService:
|
|
|
105
105
|
# 2. Check mounted servers using the filtered protocol path.
|
|
106
106
|
for mounted in reversed(self._server._mounted_servers):
|
|
107
107
|
if mounted.prefix:
|
|
108
|
-
if has_resource_prefix(
|
|
109
|
-
key,
|
|
110
|
-
mounted.prefix,
|
|
111
|
-
mounted.resource_prefix_format,
|
|
112
|
-
):
|
|
113
|
-
key = remove_resource_prefix(
|
|
114
|
-
key,
|
|
115
|
-
mounted.prefix,
|
|
116
|
-
mounted.resource_prefix_format,
|
|
117
|
-
)
|
|
108
|
+
if has_resource_prefix(key, mounted.prefix):
|
|
109
|
+
key = remove_resource_prefix(key, mounted.prefix)
|
|
118
110
|
mounted_service = ComponentService(mounted.server)
|
|
119
111
|
mounted_resource: (
|
|
120
112
|
Resource | ResourceTemplate
|
|
@@ -148,16 +140,8 @@ class ComponentService:
|
|
|
148
140
|
# 2. Check mounted servers using the filtered protocol path.
|
|
149
141
|
for mounted in reversed(self._server._mounted_servers):
|
|
150
142
|
if mounted.prefix:
|
|
151
|
-
if has_resource_prefix(
|
|
152
|
-
key,
|
|
153
|
-
mounted.prefix,
|
|
154
|
-
mounted.resource_prefix_format,
|
|
155
|
-
):
|
|
156
|
-
key = remove_resource_prefix(
|
|
157
|
-
key,
|
|
158
|
-
mounted.prefix,
|
|
159
|
-
mounted.resource_prefix_format,
|
|
160
|
-
)
|
|
143
|
+
if has_resource_prefix(key, mounted.prefix):
|
|
144
|
+
key = remove_resource_prefix(key, mounted.prefix)
|
|
161
145
|
mounted_service = ComponentService(mounted.server)
|
|
162
146
|
mounted_resource: (
|
|
163
147
|
Resource | ResourceTemplate
|
fastmcp/dependencies.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Dependency injection exports for FastMCP.
|
|
2
|
+
|
|
3
|
+
This module re-exports dependency injection symbols from Docket and FastMCP
|
|
4
|
+
to provide a clean, centralized import location for all dependency-related
|
|
5
|
+
functionality.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from docket import Depends
|
|
9
|
+
|
|
10
|
+
from fastmcp.server.dependencies import (
|
|
11
|
+
CurrentContext,
|
|
12
|
+
CurrentDocket,
|
|
13
|
+
CurrentFastMCP,
|
|
14
|
+
CurrentWorker,
|
|
15
|
+
Progress,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"CurrentContext",
|
|
20
|
+
"CurrentDocket",
|
|
21
|
+
"CurrentFastMCP",
|
|
22
|
+
"CurrentWorker",
|
|
23
|
+
"Depends",
|
|
24
|
+
"Progress",
|
|
25
|
+
]
|
|
@@ -1,170 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# Re-export for backwards compatibility
|
|
2
|
+
# The canonical location is now fastmcp.client.sampling.handlers.openai
|
|
3
|
+
from fastmcp.client.sampling.handlers.openai import OpenAISamplingHandler
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
from mcp.shared.context import LifespanContextT, RequestContext
|
|
6
|
-
from mcp.types import CreateMessageRequestParams as SamplingParams
|
|
7
|
-
from mcp.types import (
|
|
8
|
-
CreateMessageResult,
|
|
9
|
-
ModelPreferences,
|
|
10
|
-
SamplingMessage,
|
|
11
|
-
TextContent,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
try:
|
|
15
|
-
from openai import NOT_GIVEN, OpenAI
|
|
16
|
-
from openai.types.chat import (
|
|
17
|
-
ChatCompletion,
|
|
18
|
-
ChatCompletionAssistantMessageParam,
|
|
19
|
-
ChatCompletionMessageParam,
|
|
20
|
-
ChatCompletionSystemMessageParam,
|
|
21
|
-
ChatCompletionUserMessageParam,
|
|
22
|
-
)
|
|
23
|
-
from openai.types.shared.chat_model import ChatModel
|
|
24
|
-
except ImportError as e:
|
|
25
|
-
raise ImportError(
|
|
26
|
-
"The `openai` package is not installed. Please install `fastmcp[openai]` or add `openai` to your dependencies manually."
|
|
27
|
-
) from e
|
|
28
|
-
|
|
29
|
-
from typing_extensions import override
|
|
30
|
-
|
|
31
|
-
from fastmcp.experimental.sampling.handlers.base import BaseLLMSamplingHandler
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class OpenAISamplingHandler(BaseLLMSamplingHandler):
|
|
35
|
-
def __init__(self, default_model: ChatModel, client: OpenAI | None = None):
|
|
36
|
-
self.client: OpenAI = client or OpenAI()
|
|
37
|
-
self.default_model: ChatModel = default_model
|
|
38
|
-
|
|
39
|
-
@override
|
|
40
|
-
async def __call__(
|
|
41
|
-
self,
|
|
42
|
-
messages: list[SamplingMessage],
|
|
43
|
-
params: SamplingParams,
|
|
44
|
-
context: RequestContext[ServerSession, LifespanContextT]
|
|
45
|
-
| RequestContext[ClientSession, LifespanContextT],
|
|
46
|
-
) -> CreateMessageResult:
|
|
47
|
-
openai_messages: list[ChatCompletionMessageParam] = (
|
|
48
|
-
self._convert_to_openai_messages(
|
|
49
|
-
system_prompt=params.systemPrompt,
|
|
50
|
-
messages=messages,
|
|
51
|
-
)
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
model: ChatModel = self._select_model_from_preferences(params.modelPreferences)
|
|
55
|
-
|
|
56
|
-
response = self.client.chat.completions.create(
|
|
57
|
-
model=model,
|
|
58
|
-
messages=openai_messages,
|
|
59
|
-
temperature=params.temperature or NOT_GIVEN,
|
|
60
|
-
max_tokens=params.maxTokens,
|
|
61
|
-
stop=params.stopSequences or NOT_GIVEN,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
return self._chat_completion_to_create_message_result(response)
|
|
65
|
-
|
|
66
|
-
@staticmethod
|
|
67
|
-
def _iter_models_from_preferences(
|
|
68
|
-
model_preferences: ModelPreferences | str | list[str] | None,
|
|
69
|
-
) -> Iterator[str]:
|
|
70
|
-
if model_preferences is None:
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
if isinstance(model_preferences, str) and model_preferences in get_args(
|
|
74
|
-
ChatModel
|
|
75
|
-
):
|
|
76
|
-
yield model_preferences
|
|
77
|
-
|
|
78
|
-
if isinstance(model_preferences, list):
|
|
79
|
-
yield from model_preferences
|
|
80
|
-
|
|
81
|
-
if isinstance(model_preferences, ModelPreferences):
|
|
82
|
-
if not (hints := model_preferences.hints):
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
for hint in hints:
|
|
86
|
-
if not (name := hint.name):
|
|
87
|
-
continue
|
|
88
|
-
|
|
89
|
-
yield name
|
|
90
|
-
|
|
91
|
-
@staticmethod
|
|
92
|
-
def _convert_to_openai_messages(
|
|
93
|
-
system_prompt: str | None, messages: Sequence[SamplingMessage]
|
|
94
|
-
) -> list[ChatCompletionMessageParam]:
|
|
95
|
-
openai_messages: list[ChatCompletionMessageParam] = []
|
|
96
|
-
|
|
97
|
-
if system_prompt:
|
|
98
|
-
openai_messages.append(
|
|
99
|
-
ChatCompletionSystemMessageParam(
|
|
100
|
-
role="system",
|
|
101
|
-
content=system_prompt,
|
|
102
|
-
)
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
if isinstance(messages, str):
|
|
106
|
-
openai_messages.append(
|
|
107
|
-
ChatCompletionUserMessageParam(
|
|
108
|
-
role="user",
|
|
109
|
-
content=messages,
|
|
110
|
-
)
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
if isinstance(messages, list):
|
|
114
|
-
for message in messages:
|
|
115
|
-
if isinstance(message, str):
|
|
116
|
-
openai_messages.append(
|
|
117
|
-
ChatCompletionUserMessageParam(
|
|
118
|
-
role="user",
|
|
119
|
-
content=message,
|
|
120
|
-
)
|
|
121
|
-
)
|
|
122
|
-
continue
|
|
123
|
-
|
|
124
|
-
if not isinstance(message.content, TextContent):
|
|
125
|
-
raise ValueError("Only text content is supported")
|
|
126
|
-
|
|
127
|
-
if message.role == "user":
|
|
128
|
-
openai_messages.append(
|
|
129
|
-
ChatCompletionUserMessageParam(
|
|
130
|
-
role="user",
|
|
131
|
-
content=message.content.text,
|
|
132
|
-
)
|
|
133
|
-
)
|
|
134
|
-
else:
|
|
135
|
-
openai_messages.append(
|
|
136
|
-
ChatCompletionAssistantMessageParam(
|
|
137
|
-
role="assistant",
|
|
138
|
-
content=message.content.text,
|
|
139
|
-
)
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
return openai_messages
|
|
143
|
-
|
|
144
|
-
@staticmethod
|
|
145
|
-
def _chat_completion_to_create_message_result(
|
|
146
|
-
chat_completion: ChatCompletion,
|
|
147
|
-
) -> CreateMessageResult:
|
|
148
|
-
if len(chat_completion.choices) == 0:
|
|
149
|
-
raise ValueError("No response for completion")
|
|
150
|
-
|
|
151
|
-
first_choice = chat_completion.choices[0]
|
|
152
|
-
|
|
153
|
-
if content := first_choice.message.content:
|
|
154
|
-
return CreateMessageResult(
|
|
155
|
-
content=TextContent(type="text", text=content),
|
|
156
|
-
role="assistant",
|
|
157
|
-
model=chat_completion.model,
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
raise ValueError("No content in response from completion")
|
|
161
|
-
|
|
162
|
-
def _select_model_from_preferences(
|
|
163
|
-
self, model_preferences: ModelPreferences | str | list[str] | None
|
|
164
|
-
) -> ChatModel:
|
|
165
|
-
for model_option in self._iter_models_from_preferences(model_preferences):
|
|
166
|
-
if model_option in get_args(ChatModel):
|
|
167
|
-
chosen_model: ChatModel = model_option # pyright: ignore[reportAssignmentType]
|
|
168
|
-
return chosen_model
|
|
169
|
-
|
|
170
|
-
return self.default_model
|
|
5
|
+
__all__ = ["OpenAISamplingHandler"]
|
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Deprecated: Import from fastmcp.server.openapi instead."""
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
from .server import FastMCPOpenAPI
|
|
3
|
+
import warnings
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
from fastmcp.server.openapi import (
|
|
6
|
+
ComponentFn,
|
|
7
|
+
DEFAULT_ROUTE_MAPPINGS,
|
|
8
|
+
FastMCPOpenAPI,
|
|
8
9
|
MCPType,
|
|
10
|
+
OpenAPIResource,
|
|
11
|
+
OpenAPIResourceTemplate,
|
|
12
|
+
OpenAPITool,
|
|
9
13
|
RouteMap,
|
|
10
14
|
RouteMapFn,
|
|
11
|
-
ComponentFn,
|
|
12
|
-
DEFAULT_ROUTE_MAPPINGS,
|
|
13
15
|
_determine_route_type,
|
|
14
16
|
)
|
|
15
17
|
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
# Deprecated in 2.14 when OpenAPI support was promoted out of experimental
|
|
19
|
+
warnings.warn(
|
|
20
|
+
"Importing from fastmcp.experimental.server.openapi is deprecated. "
|
|
21
|
+
"Import from fastmcp.server.openapi instead.",
|
|
22
|
+
DeprecationWarning,
|
|
23
|
+
stacklevel=2,
|
|
21
24
|
)
|
|
22
25
|
|
|
23
|
-
# Export public symbols - maintaining backward compatibility
|
|
24
26
|
__all__ = [
|
|
25
27
|
"DEFAULT_ROUTE_MAPPINGS",
|
|
26
28
|
"ComponentFn",
|
|
@@ -1,63 +1,37 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Deprecated: Import from fastmcp.utilities.openapi instead."""
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
5
|
+
from fastmcp.utilities.openapi import (
|
|
5
6
|
HTTPRoute,
|
|
6
7
|
HttpMethod,
|
|
7
|
-
JsonSchema,
|
|
8
8
|
ParameterInfo,
|
|
9
9
|
ParameterLocation,
|
|
10
10
|
RequestBodyInfo,
|
|
11
11
|
ResponseInfo,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# Import from parser
|
|
15
|
-
from .parser import parse_openapi_to_http_routes
|
|
16
|
-
|
|
17
|
-
# Import from formatters
|
|
18
|
-
from .formatters import (
|
|
19
|
-
format_array_parameter,
|
|
20
|
-
format_deep_object_parameter,
|
|
21
|
-
format_description_with_responses,
|
|
22
|
-
format_json_for_description,
|
|
12
|
+
extract_output_schema_from_responses,
|
|
23
13
|
format_simple_description,
|
|
24
|
-
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
# Import from schemas
|
|
28
|
-
from .schemas import (
|
|
14
|
+
parse_openapi_to_http_routes,
|
|
29
15
|
_combine_schemas,
|
|
30
|
-
extract_output_schema_from_responses,
|
|
31
|
-
clean_schema_for_display,
|
|
32
|
-
_make_optional_parameter_nullable,
|
|
33
16
|
)
|
|
34
17
|
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
18
|
+
# Deprecated in 2.14 when OpenAPI support was promoted out of experimental
|
|
19
|
+
warnings.warn(
|
|
20
|
+
"Importing from fastmcp.experimental.utilities.openapi is deprecated. "
|
|
21
|
+
"Import from fastmcp.utilities.openapi instead.",
|
|
22
|
+
DeprecationWarning,
|
|
23
|
+
stacklevel=2,
|
|
39
24
|
)
|
|
40
25
|
|
|
41
|
-
# Export public symbols - maintaining backward compatibility
|
|
42
26
|
__all__ = [
|
|
43
27
|
"HTTPRoute",
|
|
44
28
|
"HttpMethod",
|
|
45
|
-
"JsonSchema",
|
|
46
29
|
"ParameterInfo",
|
|
47
30
|
"ParameterLocation",
|
|
48
31
|
"RequestBodyInfo",
|
|
49
32
|
"ResponseInfo",
|
|
50
33
|
"_combine_schemas",
|
|
51
|
-
"_make_optional_parameter_nullable",
|
|
52
|
-
"clean_schema_for_display",
|
|
53
|
-
"convert_openapi_schema_to_json_schema",
|
|
54
|
-
"convert_schema_definitions",
|
|
55
34
|
"extract_output_schema_from_responses",
|
|
56
|
-
"format_array_parameter",
|
|
57
|
-
"format_deep_object_parameter",
|
|
58
|
-
"format_description_with_responses",
|
|
59
|
-
"format_json_for_description",
|
|
60
35
|
"format_simple_description",
|
|
61
|
-
"generate_example_from_schema",
|
|
62
36
|
"parse_openapi_to_http_routes",
|
|
63
37
|
]
|