fastmcp 2.14.4__py3-none-any.whl → 3.0.0b1__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 (175) hide show
  1. fastmcp/_vendor/__init__.py +1 -0
  2. fastmcp/_vendor/docket_di/README.md +7 -0
  3. fastmcp/_vendor/docket_di/__init__.py +163 -0
  4. fastmcp/cli/cli.py +112 -28
  5. fastmcp/cli/install/claude_code.py +1 -5
  6. fastmcp/cli/install/claude_desktop.py +1 -5
  7. fastmcp/cli/install/cursor.py +1 -5
  8. fastmcp/cli/install/gemini_cli.py +1 -5
  9. fastmcp/cli/install/mcp_json.py +1 -6
  10. fastmcp/cli/run.py +146 -5
  11. fastmcp/client/__init__.py +7 -9
  12. fastmcp/client/auth/oauth.py +18 -17
  13. fastmcp/client/client.py +100 -870
  14. fastmcp/client/elicitation.py +1 -1
  15. fastmcp/client/mixins/__init__.py +13 -0
  16. fastmcp/client/mixins/prompts.py +295 -0
  17. fastmcp/client/mixins/resources.py +325 -0
  18. fastmcp/client/mixins/task_management.py +157 -0
  19. fastmcp/client/mixins/tools.py +397 -0
  20. fastmcp/client/sampling/handlers/anthropic.py +2 -2
  21. fastmcp/client/sampling/handlers/openai.py +1 -1
  22. fastmcp/client/tasks.py +3 -3
  23. fastmcp/client/telemetry.py +47 -0
  24. fastmcp/client/transports/__init__.py +38 -0
  25. fastmcp/client/transports/base.py +82 -0
  26. fastmcp/client/transports/config.py +170 -0
  27. fastmcp/client/transports/http.py +145 -0
  28. fastmcp/client/transports/inference.py +154 -0
  29. fastmcp/client/transports/memory.py +90 -0
  30. fastmcp/client/transports/sse.py +89 -0
  31. fastmcp/client/transports/stdio.py +543 -0
  32. fastmcp/contrib/component_manager/README.md +4 -10
  33. fastmcp/contrib/component_manager/__init__.py +1 -2
  34. fastmcp/contrib/component_manager/component_manager.py +95 -160
  35. fastmcp/contrib/component_manager/example.py +1 -1
  36. fastmcp/contrib/mcp_mixin/example.py +4 -4
  37. fastmcp/contrib/mcp_mixin/mcp_mixin.py +11 -4
  38. fastmcp/decorators.py +41 -0
  39. fastmcp/dependencies.py +12 -1
  40. fastmcp/exceptions.py +4 -0
  41. fastmcp/experimental/server/openapi/__init__.py +18 -15
  42. fastmcp/mcp_config.py +13 -4
  43. fastmcp/prompts/__init__.py +6 -3
  44. fastmcp/prompts/function_prompt.py +465 -0
  45. fastmcp/prompts/prompt.py +321 -271
  46. fastmcp/resources/__init__.py +5 -3
  47. fastmcp/resources/function_resource.py +335 -0
  48. fastmcp/resources/resource.py +325 -115
  49. fastmcp/resources/template.py +215 -43
  50. fastmcp/resources/types.py +27 -12
  51. fastmcp/server/__init__.py +2 -2
  52. fastmcp/server/auth/__init__.py +14 -0
  53. fastmcp/server/auth/auth.py +30 -10
  54. fastmcp/server/auth/authorization.py +190 -0
  55. fastmcp/server/auth/oauth_proxy/__init__.py +14 -0
  56. fastmcp/server/auth/oauth_proxy/consent.py +361 -0
  57. fastmcp/server/auth/oauth_proxy/models.py +178 -0
  58. fastmcp/server/auth/{oauth_proxy.py → oauth_proxy/proxy.py} +24 -778
  59. fastmcp/server/auth/oauth_proxy/ui.py +277 -0
  60. fastmcp/server/auth/oidc_proxy.py +2 -2
  61. fastmcp/server/auth/providers/auth0.py +24 -94
  62. fastmcp/server/auth/providers/aws.py +26 -95
  63. fastmcp/server/auth/providers/azure.py +41 -129
  64. fastmcp/server/auth/providers/descope.py +18 -49
  65. fastmcp/server/auth/providers/discord.py +25 -86
  66. fastmcp/server/auth/providers/github.py +23 -87
  67. fastmcp/server/auth/providers/google.py +24 -87
  68. fastmcp/server/auth/providers/introspection.py +60 -79
  69. fastmcp/server/auth/providers/jwt.py +30 -67
  70. fastmcp/server/auth/providers/oci.py +47 -110
  71. fastmcp/server/auth/providers/scalekit.py +23 -61
  72. fastmcp/server/auth/providers/supabase.py +18 -47
  73. fastmcp/server/auth/providers/workos.py +34 -127
  74. fastmcp/server/context.py +372 -419
  75. fastmcp/server/dependencies.py +541 -251
  76. fastmcp/server/elicitation.py +20 -18
  77. fastmcp/server/event_store.py +3 -3
  78. fastmcp/server/http.py +16 -6
  79. fastmcp/server/lifespan.py +198 -0
  80. fastmcp/server/low_level.py +92 -2
  81. fastmcp/server/middleware/__init__.py +5 -1
  82. fastmcp/server/middleware/authorization.py +312 -0
  83. fastmcp/server/middleware/caching.py +101 -54
  84. fastmcp/server/middleware/middleware.py +6 -9
  85. fastmcp/server/middleware/ping.py +70 -0
  86. fastmcp/server/middleware/tool_injection.py +2 -2
  87. fastmcp/server/mixins/__init__.py +7 -0
  88. fastmcp/server/mixins/lifespan.py +217 -0
  89. fastmcp/server/mixins/mcp_operations.py +392 -0
  90. fastmcp/server/mixins/transport.py +342 -0
  91. fastmcp/server/openapi/__init__.py +41 -21
  92. fastmcp/server/openapi/components.py +16 -339
  93. fastmcp/server/openapi/routing.py +34 -118
  94. fastmcp/server/openapi/server.py +67 -392
  95. fastmcp/server/providers/__init__.py +71 -0
  96. fastmcp/server/providers/aggregate.py +261 -0
  97. fastmcp/server/providers/base.py +578 -0
  98. fastmcp/server/providers/fastmcp_provider.py +674 -0
  99. fastmcp/server/providers/filesystem.py +226 -0
  100. fastmcp/server/providers/filesystem_discovery.py +327 -0
  101. fastmcp/server/providers/local_provider/__init__.py +11 -0
  102. fastmcp/server/providers/local_provider/decorators/__init__.py +15 -0
  103. fastmcp/server/providers/local_provider/decorators/prompts.py +256 -0
  104. fastmcp/server/providers/local_provider/decorators/resources.py +240 -0
  105. fastmcp/server/providers/local_provider/decorators/tools.py +315 -0
  106. fastmcp/server/providers/local_provider/local_provider.py +465 -0
  107. fastmcp/server/providers/openapi/__init__.py +39 -0
  108. fastmcp/server/providers/openapi/components.py +332 -0
  109. fastmcp/server/providers/openapi/provider.py +405 -0
  110. fastmcp/server/providers/openapi/routing.py +109 -0
  111. fastmcp/server/providers/proxy.py +867 -0
  112. fastmcp/server/providers/skills/__init__.py +59 -0
  113. fastmcp/server/providers/skills/_common.py +101 -0
  114. fastmcp/server/providers/skills/claude_provider.py +44 -0
  115. fastmcp/server/providers/skills/directory_provider.py +153 -0
  116. fastmcp/server/providers/skills/skill_provider.py +432 -0
  117. fastmcp/server/providers/skills/vendor_providers.py +142 -0
  118. fastmcp/server/providers/wrapped_provider.py +140 -0
  119. fastmcp/server/proxy.py +34 -700
  120. fastmcp/server/sampling/run.py +341 -2
  121. fastmcp/server/sampling/sampling_tool.py +4 -3
  122. fastmcp/server/server.py +1214 -2171
  123. fastmcp/server/tasks/__init__.py +2 -1
  124. fastmcp/server/tasks/capabilities.py +13 -1
  125. fastmcp/server/tasks/config.py +66 -3
  126. fastmcp/server/tasks/handlers.py +65 -273
  127. fastmcp/server/tasks/keys.py +4 -6
  128. fastmcp/server/tasks/requests.py +474 -0
  129. fastmcp/server/tasks/routing.py +76 -0
  130. fastmcp/server/tasks/subscriptions.py +20 -11
  131. fastmcp/server/telemetry.py +131 -0
  132. fastmcp/server/transforms/__init__.py +244 -0
  133. fastmcp/server/transforms/namespace.py +193 -0
  134. fastmcp/server/transforms/prompts_as_tools.py +175 -0
  135. fastmcp/server/transforms/resources_as_tools.py +190 -0
  136. fastmcp/server/transforms/tool_transform.py +96 -0
  137. fastmcp/server/transforms/version_filter.py +124 -0
  138. fastmcp/server/transforms/visibility.py +526 -0
  139. fastmcp/settings.py +34 -96
  140. fastmcp/telemetry.py +122 -0
  141. fastmcp/tools/__init__.py +10 -3
  142. fastmcp/tools/function_parsing.py +201 -0
  143. fastmcp/tools/function_tool.py +467 -0
  144. fastmcp/tools/tool.py +215 -362
  145. fastmcp/tools/tool_transform.py +38 -21
  146. fastmcp/utilities/async_utils.py +69 -0
  147. fastmcp/utilities/components.py +152 -91
  148. fastmcp/utilities/inspect.py +8 -20
  149. fastmcp/utilities/json_schema.py +12 -5
  150. fastmcp/utilities/json_schema_type.py +17 -15
  151. fastmcp/utilities/lifespan.py +56 -0
  152. fastmcp/utilities/logging.py +12 -4
  153. fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +3 -3
  154. fastmcp/utilities/openapi/parser.py +3 -3
  155. fastmcp/utilities/pagination.py +80 -0
  156. fastmcp/utilities/skills.py +253 -0
  157. fastmcp/utilities/tests.py +0 -16
  158. fastmcp/utilities/timeout.py +47 -0
  159. fastmcp/utilities/types.py +1 -1
  160. fastmcp/utilities/versions.py +285 -0
  161. {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/METADATA +8 -5
  162. fastmcp-3.0.0b1.dist-info/RECORD +228 -0
  163. fastmcp/client/transports.py +0 -1170
  164. fastmcp/contrib/component_manager/component_service.py +0 -209
  165. fastmcp/prompts/prompt_manager.py +0 -117
  166. fastmcp/resources/resource_manager.py +0 -338
  167. fastmcp/server/tasks/converters.py +0 -206
  168. fastmcp/server/tasks/protocol.py +0 -359
  169. fastmcp/tools/tool_manager.py +0 -170
  170. fastmcp/utilities/mcp_config.py +0 -56
  171. fastmcp-2.14.4.dist-info/RECORD +0 -161
  172. /fastmcp/server/{openapi → providers/openapi}/README.md +0 -0
  173. {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/WHEEL +0 -0
  174. {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/entry_points.txt +0 -0
  175. {fastmcp-2.14.4.dist-info → fastmcp-3.0.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -1,347 +1,24 @@
1
- """OpenAPI component implementations: Tool, Resource, and ResourceTemplate classes."""
1
+ """OpenAPI component implementations - backwards compatibility stub.
2
2
 
3
- import json
4
- import re
5
- from collections.abc import Callable
6
- from typing import TYPE_CHECKING, Any
3
+ This module is deprecated. Import from fastmcp.server.providers.openapi instead.
4
+ """
7
5
 
8
- import httpx
9
- from mcp.types import ToolAnnotations
10
- from pydantic.networks import AnyUrl
6
+ from __future__ import annotations
11
7
 
12
- from fastmcp.resources import Resource, ResourceTemplate
13
- from fastmcp.server.dependencies import get_http_headers
14
- from fastmcp.tools.tool import Tool, ToolResult
15
- from fastmcp.utilities.logging import get_logger
8
+ import warnings
16
9
 
17
- # Import from our new utilities
18
- from fastmcp.utilities.openapi import HTTPRoute
19
- from fastmcp.utilities.openapi.director import RequestDirector
20
-
21
- if TYPE_CHECKING:
22
- from fastmcp.server import Context
23
-
24
- logger = get_logger(__name__)
25
-
26
-
27
- class OpenAPITool(Tool):
28
- """Tool implementation for OpenAPI endpoints."""
29
-
30
- def __init__(
31
- self,
32
- client: httpx.AsyncClient,
33
- route: HTTPRoute,
34
- director: RequestDirector,
35
- name: str,
36
- description: str,
37
- parameters: dict[str, Any],
38
- output_schema: dict[str, Any] | None = None,
39
- tags: set[str] | None = None,
40
- timeout: float | None = None,
41
- annotations: ToolAnnotations | None = None,
42
- serializer: Callable[[Any], str] | None = None,
43
- ):
44
- super().__init__(
45
- name=name,
46
- description=description,
47
- parameters=parameters,
48
- output_schema=output_schema,
49
- tags=tags or set(),
50
- annotations=annotations,
51
- serializer=serializer,
52
- )
53
- self._client = client
54
- self._route = route
55
- self._director = director
56
- self._timeout = timeout
57
-
58
- def __repr__(self) -> str:
59
- """Custom representation to prevent recursion errors when printing."""
60
- return f"OpenAPITool(name={self.name!r}, method={self._route.method}, path={self._route.path})"
61
-
62
- async def run(self, arguments: dict[str, Any]) -> ToolResult:
63
- """Execute the HTTP request using RequestDirector for simplified parameter handling."""
64
- try:
65
- # Get base URL from client
66
- base_url = (
67
- str(self._client.base_url) if hasattr(self._client, "base_url") else ""
68
- ) or "http://localhost"
69
-
70
- # Get Headers from client
71
- cli_headers = (
72
- self._client.headers
73
- if hasattr(self._client, "headers") and self._client.headers
74
- else {}
75
- )
76
-
77
- # Build the request using RequestDirector
78
- request = self._director.build(self._route, arguments, base_url)
79
-
80
- # First add server headers (lowest precedence)
81
- if cli_headers:
82
- # Merge with existing headers, _client headers as base
83
- if request.headers:
84
- # Start with request headers, then add client headers
85
- for key, value in cli_headers.items():
86
- if key not in request.headers:
87
- request.headers[key] = value
88
- else:
89
- # Create new headers from cli_headers
90
- for key, value in cli_headers.items():
91
- request.headers[key] = value
92
-
93
- # Then add MCP client transport headers (highest precedence)
94
- mcp_headers = get_http_headers()
95
- if mcp_headers:
96
- # Merge with existing headers, MCP headers take precedence over all
97
- if request.headers:
98
- request.headers.update(mcp_headers)
99
- else:
100
- # Create new headers from mcp_headers
101
- for key, value in mcp_headers.items():
102
- request.headers[key] = value
103
- # print logger
104
- logger.debug(f"run - sending request; headers: {request.headers}")
105
-
106
- # Execute the request
107
- # Note: httpx.AsyncClient.send() doesn't accept timeout parameter
108
- # The timeout should be configured on the client itself
109
- response = await self._client.send(request)
110
-
111
- # Raise for 4xx/5xx responses
112
- response.raise_for_status()
113
-
114
- # Try to parse as JSON first
115
- try:
116
- result = response.json()
117
-
118
- # Handle structured content based on output schema, if any
119
- structured_output = None
120
- if self.output_schema is not None:
121
- if self.output_schema.get("x-fastmcp-wrap-result"):
122
- # Schema says wrap - always wrap in result key
123
- structured_output = {"result": result}
124
- else:
125
- structured_output = result
126
- # If no output schema, use fallback logic for backward compatibility
127
- elif not isinstance(result, dict):
128
- structured_output = {"result": result}
129
- else:
130
- structured_output = result
131
-
132
- return ToolResult(structured_content=structured_output)
133
- except json.JSONDecodeError:
134
- return ToolResult(content=response.text)
135
-
136
- except httpx.HTTPStatusError as e:
137
- # Handle HTTP errors (4xx, 5xx)
138
- error_message = (
139
- f"HTTP error {e.response.status_code}: {e.response.reason_phrase}"
140
- )
141
- try:
142
- error_data = e.response.json()
143
- error_message += f" - {error_data}"
144
- except (json.JSONDecodeError, ValueError):
145
- if e.response.text:
146
- error_message += f" - {e.response.text}"
147
-
148
- raise ValueError(error_message) from e
149
-
150
- except httpx.RequestError as e:
151
- # Handle request errors (connection, timeout, etc.)
152
- raise ValueError(f"Request error: {e!s}") from e
153
-
154
-
155
- class OpenAPIResource(Resource):
156
- """Resource implementation for OpenAPI endpoints."""
157
-
158
- def __init__(
159
- self,
160
- client: httpx.AsyncClient,
161
- route: HTTPRoute,
162
- director: RequestDirector,
163
- uri: str,
164
- name: str,
165
- description: str,
166
- mime_type: str = "application/json",
167
- tags: set[str] | None = None,
168
- timeout: float | None = None,
169
- ):
170
- if tags is None:
171
- tags = set()
172
- super().__init__(
173
- uri=AnyUrl(uri), # Convert string to AnyUrl
174
- name=name,
175
- description=description,
176
- mime_type=mime_type,
177
- tags=tags,
178
- )
179
- self._client = client
180
- self._route = route
181
- self._director = director
182
- self._timeout = timeout
183
-
184
- def __repr__(self) -> str:
185
- """Custom representation to prevent recursion errors when printing."""
186
- return f"OpenAPIResource(name={self.name!r}, uri={self.uri!r}, path={self._route.path})"
187
-
188
- async def read(self) -> str | bytes:
189
- """Fetch the resource data by making an HTTP request."""
190
- try:
191
- # Extract path parameters from the URI if present
192
- path = self._route.path
193
- resource_uri = str(self.uri)
194
-
195
- # If this is a templated resource, extract path parameters from the URI
196
- if "{" in path and "}" in path:
197
- # Extract the resource ID from the URI (the last part after the last slash)
198
- parts = resource_uri.split("/")
199
-
200
- if len(parts) > 1:
201
- # Find all path parameters in the route path
202
- path_params = {}
203
-
204
- # Find the path parameter names from the route path
205
- param_matches = re.findall(r"\{([^}]+)\}", path)
206
- if param_matches:
207
- # Reverse sorting from creation order (traversal is backwards)
208
- param_matches.sort(reverse=True)
209
- # Number of sent parameters is number of parts -1 (assuming first part is resource identifier)
210
- expected_param_count = len(parts) - 1
211
- # Map parameters from the end of the URI to the parameters in the path
212
- # Last parameter in URI (parts[-1]) maps to last parameter in path, and so on
213
- for i, param_name in enumerate(param_matches):
214
- # Ensure we don't use resource identifier as parameter
215
- if i < expected_param_count:
216
- # Get values from the end of parts
217
- param_value = parts[-1 - i]
218
- path_params[param_name] = param_value
219
-
220
- # Replace path parameters with their values
221
- for param_name, param_value in path_params.items():
222
- path = path.replace(f"{{{param_name}}}", str(param_value))
223
-
224
- # Filter any query parameters - get query parameters and filter out None/empty values
225
- query_params = {}
226
- for param in self._route.parameters:
227
- if param.location == "query" and hasattr(self, f"_{param.name}"):
228
- value = getattr(self, f"_{param.name}")
229
- if value is not None and value != "":
230
- query_params[param.name] = value
231
-
232
- # Prepare headers with correct precedence: server < client transport
233
- headers = {}
234
- # Start with server headers (lowest precedence)
235
- cli_headers = (
236
- self._client.headers
237
- if hasattr(self._client, "headers") and self._client.headers
238
- else {}
239
- )
240
- headers.update(cli_headers)
241
-
242
- # Add MCP client transport headers (highest precedence)
243
- mcp_headers = get_http_headers()
244
- headers.update(mcp_headers)
245
-
246
- response = await self._client.request(
247
- method=self._route.method,
248
- url=path,
249
- params=query_params,
250
- headers=headers,
251
- timeout=self._timeout,
252
- )
253
-
254
- # Raise for 4xx/5xx responses
255
- response.raise_for_status()
256
-
257
- # Determine content type and return appropriate format
258
- content_type = response.headers.get("content-type", "").lower()
259
-
260
- if "application/json" in content_type:
261
- result = response.json()
262
- return json.dumps(result)
263
- elif any(ct in content_type for ct in ["text/", "application/xml"]):
264
- return response.text
265
- else:
266
- return response.content
267
-
268
- except httpx.HTTPStatusError as e:
269
- # Handle HTTP errors (4xx, 5xx)
270
- error_message = (
271
- f"HTTP error {e.response.status_code}: {e.response.reason_phrase}"
272
- )
273
- try:
274
- error_data = e.response.json()
275
- error_message += f" - {error_data}"
276
- except (json.JSONDecodeError, ValueError):
277
- if e.response.text:
278
- error_message += f" - {e.response.text}"
279
-
280
- raise ValueError(error_message) from e
281
-
282
- except httpx.RequestError as e:
283
- # Handle request errors (connection, timeout, etc.)
284
- raise ValueError(f"Request error: {e!s}") from e
285
-
286
-
287
- class OpenAPIResourceTemplate(ResourceTemplate):
288
- """Resource template implementation for OpenAPI endpoints."""
289
-
290
- def __init__(
291
- self,
292
- client: httpx.AsyncClient,
293
- route: HTTPRoute,
294
- director: RequestDirector,
295
- uri_template: str,
296
- name: str,
297
- description: str,
298
- parameters: dict[str, Any],
299
- tags: set[str] | None = None,
300
- timeout: float | None = None,
301
- ):
302
- if tags is None:
303
- tags = set()
304
- super().__init__(
305
- uri_template=uri_template,
306
- name=name,
307
- description=description,
308
- parameters=parameters,
309
- tags=tags,
310
- )
311
- self._client = client
312
- self._route = route
313
- self._director = director
314
- self._timeout = timeout
315
-
316
- def __repr__(self) -> str:
317
- """Custom representation to prevent recursion errors when printing."""
318
- return f"OpenAPIResourceTemplate(name={self.name!r}, uri_template={self.uri_template!r}, path={self._route.path})"
319
-
320
- async def create_resource(
321
- self,
322
- uri: str,
323
- params: dict[str, Any],
324
- context: "Context | None" = None,
325
- ) -> Resource:
326
- """Create a resource with the given parameters."""
327
- # Generate a URI for this resource instance
328
- uri_parts = []
329
- for key, value in params.items():
330
- uri_parts.append(f"{key}={value}")
331
-
332
- # Create and return a resource
333
- return OpenAPIResource(
334
- client=self._client,
335
- route=self._route,
336
- director=self._director,
337
- uri=uri,
338
- name=f"{self.name}-{'-'.join(uri_parts)}",
339
- description=self.description or f"Resource for {self._route.path}",
340
- mime_type="application/json",
341
- tags=set(self._route.tags or []),
342
- timeout=self._timeout,
343
- )
10
+ warnings.warn(
11
+ "fastmcp.server.openapi.components is deprecated. "
12
+ "Import from fastmcp.server.providers.openapi instead.",
13
+ DeprecationWarning,
14
+ stacklevel=2,
15
+ )
344
16
 
17
+ from fastmcp.server.providers.openapi import ( # noqa: E402
18
+ OpenAPIResource,
19
+ OpenAPIResourceTemplate,
20
+ OpenAPITool,
21
+ )
345
22
 
346
23
  # Export public symbols
347
24
  __all__ = [
@@ -1,125 +1,14 @@
1
- """Route mapping logic for OpenAPI operations."""
1
+ """Route mapping logic for OpenAPI operations.
2
2
 
3
- import enum
4
- import re
5
- from collections.abc import Callable
6
- from dataclasses import dataclass, field
7
- from re import Pattern
8
- from typing import TYPE_CHECKING, Literal
3
+ .. deprecated::
4
+ This module is deprecated. Import from fastmcp.server.providers.openapi instead.
5
+ """
9
6
 
10
- if TYPE_CHECKING:
11
- from .components import (
12
- OpenAPIResource,
13
- OpenAPIResourceTemplate,
14
- OpenAPITool,
15
- )
16
- # Import from our new utilities
17
- from fastmcp.utilities.logging import get_logger
18
- from fastmcp.utilities.openapi import HttpMethod, HTTPRoute
7
+ # ruff: noqa: E402
19
8
 
20
- logger = get_logger(__name__)
9
+ import warnings
21
10
 
22
- # Type definitions for the mapping functions
23
- RouteMapFn = Callable[[HTTPRoute, "MCPType"], "MCPType | None"]
24
- ComponentFn = Callable[
25
- [
26
- HTTPRoute,
27
- "OpenAPITool | OpenAPIResource | OpenAPIResourceTemplate",
28
- ],
29
- None,
30
- ]
31
-
32
-
33
- class MCPType(enum.Enum):
34
- """Type of FastMCP component to create from a route.
35
-
36
- Enum values:
37
- TOOL: Convert the route to a callable Tool
38
- RESOURCE: Convert the route to a Resource (typically GET endpoints)
39
- RESOURCE_TEMPLATE: Convert the route to a ResourceTemplate (typically GET with path params)
40
- EXCLUDE: Exclude the route from being converted to any MCP component
41
- """
42
-
43
- TOOL = "TOOL"
44
- RESOURCE = "RESOURCE"
45
- RESOURCE_TEMPLATE = "RESOURCE_TEMPLATE"
46
- # PROMPT = "PROMPT"
47
- EXCLUDE = "EXCLUDE"
48
-
49
-
50
- @dataclass(kw_only=True)
51
- class RouteMap:
52
- """Mapping configuration for HTTP routes to FastMCP component types."""
53
-
54
- methods: list[HttpMethod] | Literal["*"] = field(default="*")
55
- pattern: Pattern[str] | str = field(default=r".*")
56
-
57
- tags: set[str] = field(
58
- default_factory=set,
59
- metadata={"description": "A set of tags to match. All tags must match."},
60
- )
61
- mcp_type: MCPType = field(
62
- metadata={"description": "The type of FastMCP component to create."},
63
- )
64
- mcp_tags: set[str] = field(
65
- default_factory=set,
66
- metadata={
67
- "description": "A set of tags to apply to the generated FastMCP component."
68
- },
69
- )
70
-
71
-
72
- # Default route mapping: all routes become tools.
73
- # Users can provide custom route_maps to override this behavior.
74
- DEFAULT_ROUTE_MAPPINGS = [
75
- RouteMap(mcp_type=MCPType.TOOL),
76
- ]
77
-
78
-
79
- def _determine_route_type(
80
- route: HTTPRoute,
81
- mappings: list[RouteMap],
82
- ) -> RouteMap:
83
- """
84
- Determines the FastMCP component type based on the route and mappings.
85
-
86
- Args:
87
- route: HTTPRoute object
88
- mappings: List of RouteMap objects in priority order
89
-
90
- Returns:
91
- The RouteMap that matches the route, or a catchall "Tool" RouteMap if no match is found.
92
- """
93
- # Check mappings in priority order (first match wins)
94
- for route_map in mappings:
95
- # Check if the HTTP method matches
96
- if route_map.methods == "*" or route.method in route_map.methods:
97
- # Handle both string patterns and compiled Pattern objects
98
- if isinstance(route_map.pattern, Pattern):
99
- pattern_matches = route_map.pattern.search(route.path)
100
- else:
101
- pattern_matches = re.search(route_map.pattern, route.path)
102
-
103
- if pattern_matches:
104
- # Check if tags match (if specified)
105
- # If route_map.tags is empty, tags are not matched
106
- # If route_map.tags is non-empty, all tags must be present in route.tags (AND condition)
107
- if route_map.tags:
108
- route_tags_set = set(route.tags or [])
109
- if not route_map.tags.issubset(route_tags_set):
110
- # Tags don't match, continue to next mapping
111
- continue
112
-
113
- logger.debug(
114
- f"Route {route.method} {route.path} mapped to {route_map.mcp_type.name}"
115
- )
116
- return route_map
117
-
118
- # Default fallback
119
- return RouteMap(mcp_type=MCPType.TOOL)
120
-
121
-
122
- # Export public symbols
11
+ # Backwards compatibility - export everything that was previously public
123
12
  __all__ = [
124
13
  "DEFAULT_ROUTE_MAPPINGS",
125
14
  "ComponentFn",
@@ -128,3 +17,30 @@ __all__ = [
128
17
  "RouteMapFn",
129
18
  "_determine_route_type",
130
19
  ]
20
+
21
+ warnings.warn(
22
+ "fastmcp.server.openapi.routing is deprecated. "
23
+ "Import from fastmcp.server.providers.openapi instead.",
24
+ DeprecationWarning,
25
+ stacklevel=2,
26
+ )
27
+
28
+ # Re-export from new canonical location
29
+ from fastmcp.server.providers.openapi.routing import (
30
+ DEFAULT_ROUTE_MAPPINGS as DEFAULT_ROUTE_MAPPINGS,
31
+ )
32
+ from fastmcp.server.providers.openapi.routing import (
33
+ ComponentFn as ComponentFn,
34
+ )
35
+ from fastmcp.server.providers.openapi.routing import (
36
+ MCPType as MCPType,
37
+ )
38
+ from fastmcp.server.providers.openapi.routing import (
39
+ RouteMap as RouteMap,
40
+ )
41
+ from fastmcp.server.providers.openapi.routing import (
42
+ RouteMapFn as RouteMapFn,
43
+ )
44
+ from fastmcp.server.providers.openapi.routing import (
45
+ _determine_route_type as _determine_route_type,
46
+ )