fastmcp 2.10.5__py3-none-any.whl → 2.11.0__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 (65) hide show
  1. fastmcp/__init__.py +7 -2
  2. fastmcp/cli/cli.py +128 -33
  3. fastmcp/cli/install/__init__.py +2 -2
  4. fastmcp/cli/install/claude_code.py +42 -1
  5. fastmcp/cli/install/claude_desktop.py +42 -1
  6. fastmcp/cli/install/cursor.py +42 -1
  7. fastmcp/cli/install/{mcp_config.py → mcp_json.py} +51 -7
  8. fastmcp/cli/run.py +127 -1
  9. fastmcp/client/__init__.py +2 -0
  10. fastmcp/client/auth/oauth.py +68 -99
  11. fastmcp/client/oauth_callback.py +18 -0
  12. fastmcp/client/transports.py +69 -15
  13. fastmcp/contrib/component_manager/example.py +2 -2
  14. fastmcp/experimental/server/openapi/README.md +266 -0
  15. fastmcp/experimental/server/openapi/__init__.py +38 -0
  16. fastmcp/experimental/server/openapi/components.py +348 -0
  17. fastmcp/experimental/server/openapi/routing.py +132 -0
  18. fastmcp/experimental/server/openapi/server.py +466 -0
  19. fastmcp/experimental/utilities/openapi/README.md +239 -0
  20. fastmcp/experimental/utilities/openapi/__init__.py +68 -0
  21. fastmcp/experimental/utilities/openapi/director.py +208 -0
  22. fastmcp/experimental/utilities/openapi/formatters.py +355 -0
  23. fastmcp/experimental/utilities/openapi/json_schema_converter.py +340 -0
  24. fastmcp/experimental/utilities/openapi/models.py +85 -0
  25. fastmcp/experimental/utilities/openapi/parser.py +618 -0
  26. fastmcp/experimental/utilities/openapi/schemas.py +538 -0
  27. fastmcp/mcp_config.py +125 -88
  28. fastmcp/prompts/prompt.py +11 -1
  29. fastmcp/prompts/prompt_manager.py +1 -1
  30. fastmcp/resources/resource.py +21 -1
  31. fastmcp/resources/resource_manager.py +2 -2
  32. fastmcp/resources/template.py +20 -1
  33. fastmcp/server/auth/__init__.py +17 -2
  34. fastmcp/server/auth/auth.py +144 -7
  35. fastmcp/server/auth/providers/bearer.py +25 -473
  36. fastmcp/server/auth/providers/in_memory.py +4 -2
  37. fastmcp/server/auth/providers/jwt.py +538 -0
  38. fastmcp/server/auth/providers/workos.py +170 -0
  39. fastmcp/server/auth/registry.py +52 -0
  40. fastmcp/server/context.py +110 -26
  41. fastmcp/server/dependencies.py +9 -2
  42. fastmcp/server/http.py +62 -30
  43. fastmcp/server/middleware/middleware.py +3 -23
  44. fastmcp/server/openapi.py +26 -13
  45. fastmcp/server/proxy.py +89 -8
  46. fastmcp/server/server.py +170 -62
  47. fastmcp/settings.py +83 -18
  48. fastmcp/tools/tool.py +41 -6
  49. fastmcp/tools/tool_manager.py +39 -3
  50. fastmcp/tools/tool_transform.py +122 -6
  51. fastmcp/utilities/components.py +35 -2
  52. fastmcp/utilities/json_schema.py +136 -98
  53. fastmcp/utilities/json_schema_type.py +1 -3
  54. fastmcp/utilities/mcp_config.py +28 -0
  55. fastmcp/utilities/openapi.py +306 -30
  56. fastmcp/utilities/tests.py +54 -6
  57. fastmcp/utilities/types.py +89 -11
  58. {fastmcp-2.10.5.dist-info → fastmcp-2.11.0.dist-info}/METADATA +4 -3
  59. fastmcp-2.11.0.dist-info/RECORD +108 -0
  60. fastmcp/server/auth/providers/bearer_env.py +0 -63
  61. fastmcp/utilities/cache.py +0 -26
  62. fastmcp-2.10.5.dist-info/RECORD +0 -93
  63. {fastmcp-2.10.5.dist-info → fastmcp-2.11.0.dist-info}/WHEEL +0 -0
  64. {fastmcp-2.10.5.dist-info → fastmcp-2.11.0.dist-info}/entry_points.txt +0 -0
  65. {fastmcp-2.10.5.dist-info → fastmcp-2.11.0.dist-info}/licenses/LICENSE +0 -0
fastmcp/server/server.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import datetime
6
5
  import inspect
7
6
  import re
8
7
  import warnings
@@ -25,7 +24,9 @@ from mcp.server.lowlevel.helper_types import ReadResourceContents
25
24
  from mcp.server.lowlevel.server import LifespanResultT, NotificationOptions
26
25
  from mcp.server.stdio import stdio_server
27
26
  from mcp.types import (
27
+ Annotations,
28
28
  AnyFunction,
29
+ CallToolRequestParams,
29
30
  ContentBlock,
30
31
  GetPromptResult,
31
32
  ToolAnnotations,
@@ -48,8 +49,8 @@ from fastmcp.prompts import Prompt, PromptManager
48
49
  from fastmcp.prompts.prompt import FunctionPrompt
49
50
  from fastmcp.resources import Resource, ResourceManager
50
51
  from fastmcp.resources.template import ResourceTemplate
51
- from fastmcp.server.auth.auth import OAuthProvider
52
- from fastmcp.server.auth.providers.bearer_env import EnvBearerAuthProvider
52
+ from fastmcp.server.auth.auth import AuthProvider
53
+ from fastmcp.server.auth.registry import get_registered_provider
53
54
  from fastmcp.server.http import (
54
55
  StarletteWithLifespan,
55
56
  create_sse_app,
@@ -60,7 +61,7 @@ from fastmcp.server.middleware import Middleware, MiddlewareContext
60
61
  from fastmcp.settings import Settings
61
62
  from fastmcp.tools import ToolManager
62
63
  from fastmcp.tools.tool import FunctionTool, Tool, ToolResult
63
- from fastmcp.utilities.cache import TimedCache
64
+ from fastmcp.tools.tool_transform import ToolTransformConfig
64
65
  from fastmcp.utilities.cli import log_server_banner
65
66
  from fastmcp.utilities.components import FastMCPComponent
66
67
  from fastmcp.utilities.logging import get_logger
@@ -69,10 +70,19 @@ from fastmcp.utilities.types import NotSet, NotSetT
69
70
  if TYPE_CHECKING:
70
71
  from fastmcp.client import Client
71
72
  from fastmcp.client.transports import ClientTransport, ClientTransportT
73
+ from fastmcp.experimental.server.openapi import FastMCPOpenAPI as FastMCPOpenAPINew
74
+ from fastmcp.experimental.server.openapi.routing import (
75
+ ComponentFn as OpenAPIComponentFnNew,
76
+ )
77
+ from fastmcp.experimental.server.openapi.routing import RouteMap as RouteMapNew
78
+ from fastmcp.experimental.server.openapi.routing import (
79
+ RouteMapFn as OpenAPIRouteMapFnNew,
80
+ )
72
81
  from fastmcp.server.openapi import ComponentFn as OpenAPIComponentFn
73
82
  from fastmcp.server.openapi import FastMCPOpenAPI, RouteMap
74
83
  from fastmcp.server.openapi import RouteMapFn as OpenAPIRouteMapFn
75
84
  from fastmcp.server.proxy import FastMCPProxy
85
+
76
86
  logger = get_logger(__name__)
77
87
 
78
88
  DuplicateBehavior = Literal["warn", "error", "replace", "ignore"]
@@ -121,7 +131,7 @@ class FastMCP(Generic[LifespanResultT]):
121
131
  instructions: str | None = None,
122
132
  *,
123
133
  version: str | None = None,
124
- auth: OAuthProvider | None = None,
134
+ auth: AuthProvider | None | NotSetT = NotSet,
125
135
  middleware: list[Middleware] | None = None,
126
136
  lifespan: (
127
137
  Callable[
@@ -138,9 +148,11 @@ class FastMCP(Generic[LifespanResultT]):
138
148
  resource_prefix_format: Literal["protocol", "path"] | None = None,
139
149
  mask_error_details: bool | None = None,
140
150
  tools: list[Tool | Callable[..., Any]] | None = None,
151
+ tool_transformations: dict[str, ToolTransformConfig] | None = None,
141
152
  dependencies: list[str] | None = None,
142
153
  include_tags: set[str] | None = None,
143
154
  exclude_tags: set[str] | None = None,
155
+ include_fastmcp_meta: bool | None = None,
144
156
  # ---
145
157
  # ---
146
158
  # --- The following arguments are DEPRECATED ---
@@ -160,13 +172,11 @@ class FastMCP(Generic[LifespanResultT]):
160
172
  resource_prefix_format or fastmcp.settings.resource_prefix_format
161
173
  )
162
174
 
163
- self._cache = TimedCache(
164
- expiration=datetime.timedelta(seconds=cache_expiration_seconds or 0)
165
- )
166
175
  self._additional_http_routes: list[BaseRoute] = []
167
176
  self._tool_manager = ToolManager(
168
177
  duplicate_behavior=on_duplicate_tools,
169
178
  mask_error_details=mask_error_details,
179
+ transformations=tool_transformations,
170
180
  )
171
181
  self._resource_manager = ResourceManager(
172
182
  duplicate_behavior=on_duplicate_resources,
@@ -190,9 +200,14 @@ class FastMCP(Generic[LifespanResultT]):
190
200
  lifespan=_lifespan_wrapper(self, lifespan),
191
201
  )
192
202
 
193
- if auth is None and fastmcp.settings.default_auth_provider == "bearer_env":
194
- auth = EnvBearerAuthProvider()
195
- self.auth = auth
203
+ # if auth is `NotSet`, try to create a provider from the environment
204
+ if auth is NotSet:
205
+ if fastmcp.settings.server_auth is not None:
206
+ provider_cls = get_registered_provider(fastmcp.settings.server_auth)
207
+ auth = provider_cls()
208
+ else:
209
+ auth = None
210
+ self.auth = cast(AuthProvider | None, auth)
196
211
 
197
212
  if tools:
198
213
  for tool in tools:
@@ -209,6 +224,12 @@ class FastMCP(Generic[LifespanResultT]):
209
224
  self._setup_handlers()
210
225
  self.dependencies = dependencies or fastmcp.settings.server_dependencies
211
226
 
227
+ self.include_fastmcp_meta = (
228
+ include_fastmcp_meta
229
+ if include_fastmcp_meta is not None
230
+ else fastmcp.settings.include_fastmcp_meta
231
+ )
232
+
212
233
  # handle deprecated settings
213
234
  self._handle_deprecated_settings(
214
235
  log_level=log_level,
@@ -407,7 +428,10 @@ class FastMCP(Generic[LifespanResultT]):
407
428
  methods: list[str],
408
429
  name: str | None = None,
409
430
  include_in_schema: bool = True,
410
- ):
431
+ ) -> Callable[
432
+ [Callable[[Request], Awaitable[Response]]],
433
+ Callable[[Request], Awaitable[Response]],
434
+ ]:
411
435
  """
412
436
  Decorator to register a custom HTTP route on the FastMCP server.
413
437
 
@@ -453,7 +477,13 @@ class FastMCP(Generic[LifespanResultT]):
453
477
 
454
478
  async with fastmcp.server.context.Context(fastmcp=self):
455
479
  tools = await self._list_tools()
456
- return [tool.to_mcp_tool(name=tool.key) for tool in tools]
480
+ return [
481
+ tool.to_mcp_tool(
482
+ name=tool.key,
483
+ include_fastmcp_meta=self.include_fastmcp_meta,
484
+ )
485
+ for tool in tools
486
+ ]
457
487
 
458
488
  async def _list_tools(self) -> list[Tool]:
459
489
  """
@@ -492,7 +522,11 @@ class FastMCP(Generic[LifespanResultT]):
492
522
  async with fastmcp.server.context.Context(fastmcp=self):
493
523
  resources = await self._list_resources()
494
524
  return [
495
- resource.to_mcp_resource(uri=resource.key) for resource in resources
525
+ resource.to_mcp_resource(
526
+ uri=resource.key,
527
+ include_fastmcp_meta=self.include_fastmcp_meta,
528
+ )
529
+ for resource in resources
496
530
  ]
497
531
 
498
532
  async def _list_resources(self) -> list[Resource]:
@@ -533,7 +567,10 @@ class FastMCP(Generic[LifespanResultT]):
533
567
  async with fastmcp.server.context.Context(fastmcp=self):
534
568
  templates = await self._list_resource_templates()
535
569
  return [
536
- template.to_mcp_template(uriTemplate=template.key)
570
+ template.to_mcp_template(
571
+ uriTemplate=template.key,
572
+ include_fastmcp_meta=self.include_fastmcp_meta,
573
+ )
537
574
  for template in templates
538
575
  ]
539
576
 
@@ -574,7 +611,13 @@ class FastMCP(Generic[LifespanResultT]):
574
611
 
575
612
  async with fastmcp.server.context.Context(fastmcp=self):
576
613
  prompts = await self._list_prompts()
577
- return [prompt.to_mcp_prompt(name=prompt.key) for prompt in prompts]
614
+ return [
615
+ prompt.to_mcp_prompt(
616
+ name=prompt.key,
617
+ include_fastmcp_meta=self.include_fastmcp_meta,
618
+ )
619
+ for prompt in prompts
620
+ ]
578
621
 
579
622
  async def _list_prompts(self) -> list[Prompt]:
580
623
  """
@@ -650,7 +693,7 @@ class FastMCP(Generic[LifespanResultT]):
650
693
  key=context.message.name, arguments=context.message.arguments or {}
651
694
  )
652
695
 
653
- mw_context = MiddlewareContext(
696
+ mw_context = MiddlewareContext[CallToolRequestParams](
654
697
  message=mcp.types.CallToolRequestParams(name=key, arguments=arguments),
655
698
  source="client",
656
699
  type="request",
@@ -772,7 +815,6 @@ class FastMCP(Generic[LifespanResultT]):
772
815
  The tool instance that was added to the server.
773
816
  """
774
817
  self._tool_manager.add_tool(tool)
775
- self._cache.clear()
776
818
 
777
819
  # Send notification if we're in a request context
778
820
  try:
@@ -795,7 +837,6 @@ class FastMCP(Generic[LifespanResultT]):
795
837
  NotFoundError: If the tool is not found
796
838
  """
797
839
  self._tool_manager.remove_tool(name)
798
- self._cache.clear()
799
840
 
800
841
  # Send notification if we're in a request context
801
842
  try:
@@ -806,6 +847,16 @@ class FastMCP(Generic[LifespanResultT]):
806
847
  except RuntimeError:
807
848
  pass # No context available
808
849
 
850
+ def add_tool_transformation(
851
+ self, tool_name: str, transformation: ToolTransformConfig
852
+ ) -> None:
853
+ """Add a tool transformation."""
854
+ self._tool_manager.add_tool_transformation(tool_name, transformation)
855
+
856
+ def remove_tool_transformation(self, tool_name: str) -> None:
857
+ """Remove a tool transformation."""
858
+ self._tool_manager.remove_tool_transformation(tool_name)
859
+
809
860
  @overload
810
861
  def tool(
811
862
  self,
@@ -818,6 +869,7 @@ class FastMCP(Generic[LifespanResultT]):
818
869
  output_schema: dict[str, Any] | None | NotSetT = NotSet,
819
870
  annotations: ToolAnnotations | dict[str, Any] | None = None,
820
871
  exclude_args: list[str] | None = None,
872
+ meta: dict[str, Any] | None = None,
821
873
  enabled: bool | None = None,
822
874
  ) -> FunctionTool: ...
823
875
 
@@ -833,6 +885,7 @@ class FastMCP(Generic[LifespanResultT]):
833
885
  output_schema: dict[str, Any] | None | NotSetT = NotSet,
834
886
  annotations: ToolAnnotations | dict[str, Any] | None = None,
835
887
  exclude_args: list[str] | None = None,
888
+ meta: dict[str, Any] | None = None,
836
889
  enabled: bool | None = None,
837
890
  ) -> Callable[[AnyFunction], FunctionTool]: ...
838
891
 
@@ -847,6 +900,7 @@ class FastMCP(Generic[LifespanResultT]):
847
900
  output_schema: dict[str, Any] | None | NotSetT = NotSet,
848
901
  annotations: ToolAnnotations | dict[str, Any] | None = None,
849
902
  exclude_args: list[str] | None = None,
903
+ meta: dict[str, Any] | None = None,
850
904
  enabled: bool | None = None,
851
905
  ) -> Callable[[AnyFunction], FunctionTool] | FunctionTool:
852
906
  """Decorator to register a tool.
@@ -870,6 +924,7 @@ class FastMCP(Generic[LifespanResultT]):
870
924
  output_schema: Optional JSON schema for the tool's output
871
925
  annotations: Optional annotations about the tool's behavior
872
926
  exclude_args: Optional list of argument names to exclude from the tool schema
927
+ meta: Optional meta information about the tool
873
928
  enabled: Optional boolean to enable or disable the tool
874
929
 
875
930
  Examples:
@@ -928,6 +983,7 @@ class FastMCP(Generic[LifespanResultT]):
928
983
  output_schema=output_schema,
929
984
  annotations=annotations,
930
985
  exclude_args=exclude_args,
986
+ meta=meta,
931
987
  serializer=self._tool_serializer,
932
988
  enabled=enabled,
933
989
  )
@@ -960,6 +1016,7 @@ class FastMCP(Generic[LifespanResultT]):
960
1016
  output_schema=output_schema,
961
1017
  annotations=annotations,
962
1018
  exclude_args=exclude_args,
1019
+ meta=meta,
963
1020
  enabled=enabled,
964
1021
  )
965
1022
 
@@ -973,7 +1030,6 @@ class FastMCP(Generic[LifespanResultT]):
973
1030
  The resource instance that was added to the server.
974
1031
  """
975
1032
  self._resource_manager.add_resource(resource)
976
- self._cache.clear()
977
1033
 
978
1034
  # Send notification if we're in a request context
979
1035
  try:
@@ -1045,7 +1101,6 @@ class FastMCP(Generic[LifespanResultT]):
1045
1101
  mime_type=mime_type,
1046
1102
  tags=tags,
1047
1103
  )
1048
- self._cache.clear()
1049
1104
 
1050
1105
  def resource(
1051
1106
  self,
@@ -1057,6 +1112,8 @@ class FastMCP(Generic[LifespanResultT]):
1057
1112
  mime_type: str | None = None,
1058
1113
  tags: set[str] | None = None,
1059
1114
  enabled: bool | None = None,
1115
+ annotations: Annotations | dict[str, Any] | None = None,
1116
+ meta: dict[str, Any] | None = None,
1060
1117
  ) -> Callable[[AnyFunction], Resource | ResourceTemplate]:
1061
1118
  """Decorator to register a function as a resource.
1062
1119
 
@@ -1080,6 +1137,8 @@ class FastMCP(Generic[LifespanResultT]):
1080
1137
  mime_type: Optional MIME type for the resource
1081
1138
  tags: Optional set of tags for categorizing the resource
1082
1139
  enabled: Optional boolean to enable or disable the resource
1140
+ annotations: Optional annotations about the resource's behavior
1141
+ meta: Optional meta information about the resource
1083
1142
 
1084
1143
  Examples:
1085
1144
  Register a resource with a custom name:
@@ -1108,6 +1167,9 @@ class FastMCP(Generic[LifespanResultT]):
1108
1167
  return f"Weather for {city}: {data}"
1109
1168
  ```
1110
1169
  """
1170
+ if isinstance(annotations, dict):
1171
+ annotations = Annotations(**annotations)
1172
+
1111
1173
  # Check if user passed function directly instead of calling decorator
1112
1174
  if inspect.isroutine(uri):
1113
1175
  raise TypeError(
@@ -1149,6 +1211,8 @@ class FastMCP(Generic[LifespanResultT]):
1149
1211
  mime_type=mime_type,
1150
1212
  tags=tags,
1151
1213
  enabled=enabled,
1214
+ annotations=annotations,
1215
+ meta=meta,
1152
1216
  )
1153
1217
  self.add_template(template)
1154
1218
  return template
@@ -1162,6 +1226,8 @@ class FastMCP(Generic[LifespanResultT]):
1162
1226
  mime_type=mime_type,
1163
1227
  tags=tags,
1164
1228
  enabled=enabled,
1229
+ annotations=annotations,
1230
+ meta=meta,
1165
1231
  )
1166
1232
  self.add_resource(resource)
1167
1233
  return resource
@@ -1183,7 +1249,6 @@ class FastMCP(Generic[LifespanResultT]):
1183
1249
  The prompt instance that was added to the server.
1184
1250
  """
1185
1251
  self._prompt_manager.add_prompt(prompt)
1186
- self._cache.clear()
1187
1252
 
1188
1253
  # Send notification if we're in a request context
1189
1254
  try:
@@ -1206,6 +1271,7 @@ class FastMCP(Generic[LifespanResultT]):
1206
1271
  description: str | None = None,
1207
1272
  tags: set[str] | None = None,
1208
1273
  enabled: bool | None = None,
1274
+ meta: dict[str, Any] | None = None,
1209
1275
  ) -> FunctionPrompt: ...
1210
1276
 
1211
1277
  @overload
@@ -1218,6 +1284,7 @@ class FastMCP(Generic[LifespanResultT]):
1218
1284
  description: str | None = None,
1219
1285
  tags: set[str] | None = None,
1220
1286
  enabled: bool | None = None,
1287
+ meta: dict[str, Any] | None = None,
1221
1288
  ) -> Callable[[AnyFunction], FunctionPrompt]: ...
1222
1289
 
1223
1290
  def prompt(
@@ -1229,6 +1296,7 @@ class FastMCP(Generic[LifespanResultT]):
1229
1296
  description: str | None = None,
1230
1297
  tags: set[str] | None = None,
1231
1298
  enabled: bool | None = None,
1299
+ meta: dict[str, Any] | None = None,
1232
1300
  ) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt:
1233
1301
  """Decorator to register a prompt.
1234
1302
 
@@ -1249,6 +1317,7 @@ class FastMCP(Generic[LifespanResultT]):
1249
1317
  description: Optional description of what the prompt does
1250
1318
  tags: Optional set of tags for categorizing the prompt
1251
1319
  enabled: Optional boolean to enable or disable the prompt
1320
+ meta: Optional meta information about the prompt
1252
1321
 
1253
1322
  Examples:
1254
1323
 
@@ -1326,6 +1395,7 @@ class FastMCP(Generic[LifespanResultT]):
1326
1395
  description=description,
1327
1396
  tags=tags,
1328
1397
  enabled=enabled,
1398
+ meta=meta,
1329
1399
  )
1330
1400
  self.add_prompt(prompt)
1331
1401
 
@@ -1355,6 +1425,7 @@ class FastMCP(Generic[LifespanResultT]):
1355
1425
  description=description,
1356
1426
  tags=tags,
1357
1427
  enabled=enabled,
1428
+ meta=meta,
1358
1429
  )
1359
1430
 
1360
1431
  async def run_stdio_async(self, show_banner: bool = True) -> None:
@@ -1662,8 +1733,7 @@ class FastMCP(Generic[LifespanResultT]):
1662
1733
  resource_separator: Deprecated. Separator character for resource URIs.
1663
1734
  prompt_separator: Deprecated. Separator character for prompt names.
1664
1735
  """
1665
- from fastmcp.client.transports import FastMCPTransport
1666
- from fastmcp.server.proxy import FastMCPProxy, ProxyClient
1736
+ from fastmcp.server.proxy import FastMCPProxy
1667
1737
 
1668
1738
  # Deprecated since 2.9.0
1669
1739
  # Prior to 2.9.0, the first positional argument was the prefix and the
@@ -1715,7 +1785,7 @@ class FastMCP(Generic[LifespanResultT]):
1715
1785
  as_proxy = server._has_lifespan
1716
1786
 
1717
1787
  if as_proxy and not isinstance(server, FastMCPProxy):
1718
- server = FastMCPProxy(ProxyClient(transport=FastMCPTransport(server)))
1788
+ server = FastMCP.as_proxy(server)
1719
1789
 
1720
1790
  # Delegate mounting to all three managers
1721
1791
  mounted_server = MountedServer(
@@ -1727,8 +1797,6 @@ class FastMCP(Generic[LifespanResultT]):
1727
1797
  self._resource_manager.mount(mounted_server)
1728
1798
  self._prompt_manager.mount(mounted_server)
1729
1799
 
1730
- self._cache.clear()
1731
-
1732
1800
  async def import_server(
1733
1801
  self,
1734
1802
  server: FastMCP[LifespanResultT],
@@ -1851,55 +1919,72 @@ class FastMCP(Generic[LifespanResultT]):
1851
1919
  else:
1852
1920
  logger.debug(f"Imported server {server.name}")
1853
1921
 
1854
- self._cache.clear()
1855
-
1856
1922
  @classmethod
1857
1923
  def from_openapi(
1858
1924
  cls,
1859
1925
  openapi_spec: dict[str, Any],
1860
1926
  client: httpx.AsyncClient,
1861
- route_maps: list[RouteMap] | None = None,
1862
- route_map_fn: OpenAPIRouteMapFn | None = None,
1863
- mcp_component_fn: OpenAPIComponentFn | None = None,
1927
+ route_maps: list[RouteMap] | list[RouteMapNew] | None = None,
1928
+ route_map_fn: OpenAPIRouteMapFn | OpenAPIRouteMapFnNew | None = None,
1929
+ mcp_component_fn: OpenAPIComponentFn | OpenAPIComponentFnNew | None = None,
1864
1930
  mcp_names: dict[str, str] | None = None,
1865
1931
  tags: set[str] | None = None,
1866
1932
  **settings: Any,
1867
- ) -> FastMCPOpenAPI:
1933
+ ) -> FastMCPOpenAPI | FastMCPOpenAPINew:
1868
1934
  """
1869
1935
  Create a FastMCP server from an OpenAPI specification.
1870
1936
  """
1871
- from .openapi import FastMCPOpenAPI
1872
-
1873
- return FastMCPOpenAPI(
1874
- openapi_spec=openapi_spec,
1875
- client=client,
1876
- route_maps=route_maps,
1877
- route_map_fn=route_map_fn,
1878
- mcp_component_fn=mcp_component_fn,
1879
- mcp_names=mcp_names,
1880
- tags=tags,
1881
- **settings,
1882
- )
1937
+
1938
+ # Check if experimental parser is enabled
1939
+ if fastmcp.settings.experimental.enable_new_openapi_parser:
1940
+ from fastmcp.experimental.server.openapi import FastMCPOpenAPI
1941
+
1942
+ return FastMCPOpenAPI(
1943
+ openapi_spec=openapi_spec,
1944
+ client=client,
1945
+ route_maps=cast(Any, route_maps),
1946
+ route_map_fn=cast(Any, route_map_fn),
1947
+ mcp_component_fn=cast(Any, mcp_component_fn),
1948
+ mcp_names=mcp_names,
1949
+ tags=tags,
1950
+ **settings,
1951
+ )
1952
+ else:
1953
+ logger.info(
1954
+ "Using legacy OpenAPI parser. To use the new parser, set "
1955
+ "FASTMCP_EXPERIMENTAL_ENABLE_NEW_OPENAPI_PARSER=true. The new parser "
1956
+ "was introduced for testing in 2.11 and will become the default soon."
1957
+ )
1958
+ from .openapi import FastMCPOpenAPI
1959
+
1960
+ return FastMCPOpenAPI(
1961
+ openapi_spec=openapi_spec,
1962
+ client=client,
1963
+ route_maps=cast(Any, route_maps),
1964
+ route_map_fn=cast(Any, route_map_fn),
1965
+ mcp_component_fn=cast(Any, mcp_component_fn),
1966
+ mcp_names=mcp_names,
1967
+ tags=tags,
1968
+ **settings,
1969
+ )
1883
1970
 
1884
1971
  @classmethod
1885
1972
  def from_fastapi(
1886
1973
  cls,
1887
1974
  app: Any,
1888
1975
  name: str | None = None,
1889
- route_maps: list[RouteMap] | None = None,
1890
- route_map_fn: OpenAPIRouteMapFn | None = None,
1891
- mcp_component_fn: OpenAPIComponentFn | None = None,
1976
+ route_maps: list[RouteMap] | list[RouteMapNew] | None = None,
1977
+ route_map_fn: OpenAPIRouteMapFn | OpenAPIRouteMapFnNew | None = None,
1978
+ mcp_component_fn: OpenAPIComponentFn | OpenAPIComponentFnNew | None = None,
1892
1979
  mcp_names: dict[str, str] | None = None,
1893
1980
  httpx_client_kwargs: dict[str, Any] | None = None,
1894
1981
  tags: set[str] | None = None,
1895
1982
  **settings: Any,
1896
- ) -> FastMCPOpenAPI:
1983
+ ) -> FastMCPOpenAPI | FastMCPOpenAPINew:
1897
1984
  """
1898
1985
  Create a FastMCP server from a FastAPI application.
1899
1986
  """
1900
1987
 
1901
- from .openapi import FastMCPOpenAPI
1902
-
1903
1988
  if httpx_client_kwargs is None:
1904
1989
  httpx_client_kwargs = {}
1905
1990
  httpx_client_kwargs.setdefault("base_url", "http://fastapi")
@@ -1911,17 +1996,40 @@ class FastMCP(Generic[LifespanResultT]):
1911
1996
 
1912
1997
  name = name or app.title
1913
1998
 
1914
- return FastMCPOpenAPI(
1915
- openapi_spec=app.openapi(),
1916
- client=client,
1917
- name=name,
1918
- route_maps=route_maps,
1919
- route_map_fn=route_map_fn,
1920
- mcp_component_fn=mcp_component_fn,
1921
- mcp_names=mcp_names,
1922
- tags=tags,
1923
- **settings,
1924
- )
1999
+ # Check if experimental parser is enabled
2000
+ if fastmcp.settings.experimental.enable_new_openapi_parser:
2001
+ from fastmcp.experimental.server.openapi import FastMCPOpenAPI
2002
+
2003
+ return FastMCPOpenAPI(
2004
+ openapi_spec=app.openapi(),
2005
+ client=client,
2006
+ name=name,
2007
+ route_maps=cast(Any, route_maps),
2008
+ route_map_fn=cast(Any, route_map_fn),
2009
+ mcp_component_fn=cast(Any, mcp_component_fn),
2010
+ mcp_names=mcp_names,
2011
+ tags=tags,
2012
+ **settings,
2013
+ )
2014
+ else:
2015
+ logger.info(
2016
+ "Using legacy OpenAPI parser. To use the new parser, set "
2017
+ "FASTMCP_EXPERIMENTAL_ENABLE_NEW_OPENAPI_PARSER=true. The new parser "
2018
+ "was introduced for testing in 2.11 and will become the default soon."
2019
+ )
2020
+ from .openapi import FastMCPOpenAPI
2021
+
2022
+ return FastMCPOpenAPI(
2023
+ openapi_spec=app.openapi(),
2024
+ client=client,
2025
+ name=name,
2026
+ route_maps=cast(Any, route_maps),
2027
+ route_map_fn=cast(Any, route_map_fn),
2028
+ mcp_component_fn=cast(Any, mcp_component_fn),
2029
+ mcp_names=mcp_names,
2030
+ tags=tags,
2031
+ **settings,
2032
+ )
1925
2033
 
1926
2034
  @classmethod
1927
2035
  def as_proxy(