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.
Files changed (85) hide show
  1. fastmcp/__init__.py +0 -21
  2. fastmcp/cli/__init__.py +0 -3
  3. fastmcp/cli/__main__.py +5 -0
  4. fastmcp/cli/cli.py +8 -22
  5. fastmcp/cli/install/shared.py +0 -15
  6. fastmcp/cli/tasks.py +110 -0
  7. fastmcp/client/auth/oauth.py +9 -9
  8. fastmcp/client/client.py +739 -136
  9. fastmcp/client/elicitation.py +11 -5
  10. fastmcp/client/messages.py +7 -5
  11. fastmcp/client/roots.py +2 -1
  12. fastmcp/client/sampling/__init__.py +69 -0
  13. fastmcp/client/sampling/handlers/__init__.py +0 -0
  14. fastmcp/client/sampling/handlers/anthropic.py +387 -0
  15. fastmcp/client/sampling/handlers/openai.py +399 -0
  16. fastmcp/client/tasks.py +551 -0
  17. fastmcp/client/transports.py +72 -21
  18. fastmcp/contrib/component_manager/component_service.py +4 -20
  19. fastmcp/dependencies.py +25 -0
  20. fastmcp/experimental/sampling/handlers/__init__.py +5 -0
  21. fastmcp/experimental/sampling/handlers/openai.py +4 -169
  22. fastmcp/experimental/server/openapi/__init__.py +15 -13
  23. fastmcp/experimental/utilities/openapi/__init__.py +12 -38
  24. fastmcp/prompts/prompt.py +38 -38
  25. fastmcp/resources/resource.py +33 -16
  26. fastmcp/resources/template.py +69 -59
  27. fastmcp/server/auth/__init__.py +0 -9
  28. fastmcp/server/auth/auth.py +127 -3
  29. fastmcp/server/auth/oauth_proxy.py +47 -97
  30. fastmcp/server/auth/oidc_proxy.py +7 -0
  31. fastmcp/server/auth/providers/in_memory.py +2 -2
  32. fastmcp/server/auth/providers/oci.py +2 -2
  33. fastmcp/server/context.py +509 -180
  34. fastmcp/server/dependencies.py +464 -6
  35. fastmcp/server/elicitation.py +285 -47
  36. fastmcp/server/event_store.py +177 -0
  37. fastmcp/server/http.py +15 -3
  38. fastmcp/server/low_level.py +56 -12
  39. fastmcp/server/middleware/middleware.py +2 -2
  40. fastmcp/server/openapi/__init__.py +35 -0
  41. fastmcp/{experimental/server → server}/openapi/components.py +4 -3
  42. fastmcp/{experimental/server → server}/openapi/routing.py +1 -1
  43. fastmcp/{experimental/server → server}/openapi/server.py +6 -5
  44. fastmcp/server/proxy.py +53 -40
  45. fastmcp/server/sampling/__init__.py +10 -0
  46. fastmcp/server/sampling/run.py +301 -0
  47. fastmcp/server/sampling/sampling_tool.py +108 -0
  48. fastmcp/server/server.py +793 -552
  49. fastmcp/server/tasks/__init__.py +21 -0
  50. fastmcp/server/tasks/capabilities.py +22 -0
  51. fastmcp/server/tasks/config.py +89 -0
  52. fastmcp/server/tasks/converters.py +206 -0
  53. fastmcp/server/tasks/handlers.py +356 -0
  54. fastmcp/server/tasks/keys.py +93 -0
  55. fastmcp/server/tasks/protocol.py +355 -0
  56. fastmcp/server/tasks/subscriptions.py +205 -0
  57. fastmcp/settings.py +101 -103
  58. fastmcp/tools/tool.py +83 -49
  59. fastmcp/tools/tool_transform.py +1 -12
  60. fastmcp/utilities/components.py +3 -3
  61. fastmcp/utilities/json_schema_type.py +4 -4
  62. fastmcp/utilities/mcp_config.py +1 -2
  63. fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +1 -1
  64. fastmcp/{experimental/utilities → utilities}/openapi/README.md +7 -35
  65. fastmcp/utilities/openapi/__init__.py +63 -0
  66. fastmcp/{experimental/utilities → utilities}/openapi/formatters.py +5 -5
  67. fastmcp/{experimental/utilities → utilities}/openapi/json_schema_converter.py +1 -1
  68. fastmcp/utilities/tests.py +11 -5
  69. fastmcp/utilities/types.py +8 -0
  70. {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/METADATA +7 -4
  71. {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/RECORD +79 -63
  72. fastmcp/client/sampling.py +0 -56
  73. fastmcp/experimental/sampling/handlers/base.py +0 -21
  74. fastmcp/server/auth/providers/bearer.py +0 -25
  75. fastmcp/server/openapi.py +0 -1087
  76. fastmcp/server/sampling/handler.py +0 -19
  77. fastmcp/utilities/openapi.py +0 -1568
  78. /fastmcp/{experimental/server → server}/openapi/README.md +0 -0
  79. /fastmcp/{experimental/utilities → utilities}/openapi/director.py +0 -0
  80. /fastmcp/{experimental/utilities → utilities}/openapi/models.py +0 -0
  81. /fastmcp/{experimental/utilities → utilities}/openapi/parser.py +0 -0
  82. /fastmcp/{experimental/utilities → utilities}/openapi/schemas.py +0 -0
  83. {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/WHEEL +0 -0
  84. {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/entry_points.txt +0 -0
  85. {fastmcp-2.13.3.dist-info → fastmcp-2.14.1.dist-info}/licenses/LICENSE +0 -0
@@ -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 streamablehttp_client
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
- client_kwargs: dict[str, Any] = {}
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
- client_kwargs["headers"] = get_http_headers() | self.headers
285
+ headers = get_http_headers() | self.headers
274
286
 
275
- # sse_read_timeout has a default value set, so we can't pass None without overriding it
276
- # instead we simply leave the kwarg out if it's not provided
277
- if self.sse_read_timeout is not None:
278
- client_kwargs["sse_read_timeout"] = self.sse_read_timeout
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
- client_kwargs["timeout"] = session_kwargs.get("read_timeout_seconds")
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
- client_kwargs["httpx_client_factory"] = self.httpx_client_factory
303
+ http_client = self.httpx_client_factory(**httpx_client_kwargs)
304
+ else:
305
+ http_client = httpx.AsyncClient(**httpx_client_kwargs)
284
306
 
285
- async with streamablehttp_client(
286
- self.url,
287
- auth=self.auth,
288
- **client_kwargs,
289
- ) as transport:
290
- read_stream, write_stream, _ = transport
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
- session_kwargs=session_kwargs,
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
- # Create a cancel scope for the server task
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
@@ -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
+ ]
@@ -0,0 +1,5 @@
1
+ # Re-export for backwards compatibility
2
+ # The canonical location is now fastmcp.client.sampling.handlers
3
+ from fastmcp.client.sampling.handlers.openai import OpenAISamplingHandler
4
+
5
+ __all__ = ["OpenAISamplingHandler"]
@@ -1,170 +1,5 @@
1
- from collections.abc import Iterator, Sequence
2
- from typing import get_args
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
- from mcp import ClientSession, ServerSession
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
- """OpenAPI server implementation for FastMCP - refactored for better maintainability."""
1
+ """Deprecated: Import from fastmcp.server.openapi instead."""
2
2
 
3
- # Import from server
4
- from .server import FastMCPOpenAPI
3
+ import warnings
5
4
 
6
- # Import from routing
7
- from .routing import (
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
- # Import from components
17
- from .components import (
18
- OpenAPITool,
19
- OpenAPIResource,
20
- OpenAPIResourceTemplate,
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
- """OpenAPI utilities for FastMCP - refactored for better maintainability."""
1
+ """Deprecated: Import from fastmcp.utilities.openapi instead."""
2
2
 
3
- # Import from models
4
- from .models import (
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
- generate_example_from_schema,
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
- # Import from json_schema_converter
36
- from .json_schema_converter import (
37
- convert_openapi_schema_to_json_schema,
38
- convert_schema_definitions,
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
  ]