fastmcp 2.8.1__py3-none-any.whl → 2.9.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 (38) hide show
  1. fastmcp/cli/cli.py +99 -1
  2. fastmcp/cli/run.py +1 -3
  3. fastmcp/client/auth/oauth.py +1 -2
  4. fastmcp/client/client.py +21 -5
  5. fastmcp/client/transports.py +17 -2
  6. fastmcp/contrib/mcp_mixin/README.md +79 -2
  7. fastmcp/contrib/mcp_mixin/mcp_mixin.py +14 -0
  8. fastmcp/prompts/prompt.py +91 -11
  9. fastmcp/prompts/prompt_manager.py +119 -43
  10. fastmcp/resources/resource.py +11 -1
  11. fastmcp/resources/resource_manager.py +249 -76
  12. fastmcp/resources/template.py +27 -1
  13. fastmcp/server/auth/providers/bearer.py +32 -10
  14. fastmcp/server/context.py +41 -2
  15. fastmcp/server/http.py +8 -0
  16. fastmcp/server/middleware/__init__.py +6 -0
  17. fastmcp/server/middleware/error_handling.py +206 -0
  18. fastmcp/server/middleware/logging.py +165 -0
  19. fastmcp/server/middleware/middleware.py +236 -0
  20. fastmcp/server/middleware/rate_limiting.py +231 -0
  21. fastmcp/server/middleware/timing.py +156 -0
  22. fastmcp/server/proxy.py +250 -140
  23. fastmcp/server/server.py +320 -242
  24. fastmcp/settings.py +2 -2
  25. fastmcp/tools/tool.py +6 -2
  26. fastmcp/tools/tool_manager.py +114 -45
  27. fastmcp/utilities/components.py +22 -2
  28. fastmcp/utilities/inspect.py +326 -0
  29. fastmcp/utilities/json_schema.py +67 -23
  30. fastmcp/utilities/mcp_config.py +13 -7
  31. fastmcp/utilities/openapi.py +5 -3
  32. fastmcp/utilities/tests.py +1 -1
  33. fastmcp/utilities/types.py +90 -1
  34. {fastmcp-2.8.1.dist-info → fastmcp-2.9.0.dist-info}/METADATA +2 -2
  35. {fastmcp-2.8.1.dist-info → fastmcp-2.9.0.dist-info}/RECORD +38 -31
  36. {fastmcp-2.8.1.dist-info → fastmcp-2.9.0.dist-info}/WHEEL +0 -0
  37. {fastmcp-2.8.1.dist-info → fastmcp-2.9.0.dist-info}/entry_points.txt +0 -0
  38. {fastmcp-2.8.1.dist-info → fastmcp-2.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import copy
4
+ from collections import defaultdict
4
5
 
5
6
 
6
7
  def _prune_param(schema: dict, param: str) -> dict:
@@ -24,25 +25,77 @@ def _prune_param(schema: dict, param: str) -> dict:
24
25
  return schema
25
26
 
26
27
 
28
+ def _prune_unused_defs(schema: dict) -> dict:
29
+ """Walk the schema and prune unused defs."""
30
+
31
+ root_defs: set[str] = set()
32
+ referenced_by: defaultdict[str, list] = defaultdict(list)
33
+
34
+ defs = schema.get("$defs")
35
+ if defs is None:
36
+ return schema
37
+
38
+ def walk(
39
+ node: object, current_def: str | None = None, skip_defs: bool = False
40
+ ) -> None:
41
+ if isinstance(node, dict):
42
+ # Process $ref for definition tracking
43
+ ref = node.get("$ref")
44
+ if isinstance(ref, str) and ref.startswith("#/$defs/"):
45
+ def_name = ref.split("/")[-1]
46
+ if current_def:
47
+ referenced_by[def_name].append(current_def)
48
+ else:
49
+ root_defs.add(def_name)
50
+
51
+ # Walk children
52
+ for k, v in node.items():
53
+ if skip_defs and k == "$defs":
54
+ continue
55
+
56
+ walk(v, current_def=current_def)
57
+
58
+ elif isinstance(node, list):
59
+ for v in node:
60
+ walk(v)
61
+
62
+ # Traverse the schema once, skipping the $defs
63
+ walk(schema, skip_defs=True)
64
+
65
+ # Now figure out what defs reference other defs
66
+ for def_name, value in defs.items():
67
+ walk(value, current_def=def_name)
68
+
69
+ # Figure out what defs were referenced directly or recursively
70
+ def def_is_referenced(def_name):
71
+ if def_name in root_defs:
72
+ return True
73
+ references = referenced_by.get(def_name)
74
+ if references:
75
+ for reference in references:
76
+ if def_is_referenced(reference):
77
+ return True
78
+ return False
79
+
80
+ # Remove orphaned definitions if requested
81
+ for def_name in list(defs):
82
+ if not def_is_referenced(def_name):
83
+ defs.pop(def_name)
84
+ if not defs:
85
+ schema.pop("$defs", None)
86
+
87
+ return schema
88
+
89
+
27
90
  def _walk_and_prune(
28
91
  schema: dict,
29
- prune_defs: bool = False,
30
92
  prune_titles: bool = False,
31
93
  prune_additional_properties: bool = False,
32
94
  ) -> dict:
33
- """Walk the schema and optionally prune titles, unused definitions, and additionalProperties: false."""
34
-
35
- # Will only be used if prune_defs is True
36
- used_defs: set[str] = set()
95
+ """Walk the schema and optionally prune titles and additionalProperties: false."""
37
96
 
38
97
  def walk(node: object) -> None:
39
98
  if isinstance(node, dict):
40
- # Process $ref for definition tracking
41
- if prune_defs:
42
- ref = node.get("$ref")
43
- if isinstance(ref, str) and ref.startswith("#/$defs/"):
44
- used_defs.add(ref.split("/")[-1])
45
-
46
99
  # Remove title if requested
47
100
  if prune_titles and "title" in node:
48
101
  node.pop("title")
@@ -62,18 +115,8 @@ def _walk_and_prune(
62
115
  for v in node:
63
116
  walk(v)
64
117
 
65
- # Traverse the schema once
66
118
  walk(schema)
67
119
 
68
- # Remove orphaned definitions if requested
69
- if prune_defs:
70
- defs = schema.get("$defs", {})
71
- for def_name in list(defs):
72
- if def_name not in used_defs:
73
- defs.pop(def_name)
74
- if not defs:
75
- schema.pop("$defs", None)
76
-
77
120
  return schema
78
121
 
79
122
 
@@ -109,12 +152,13 @@ def compress_schema(
109
152
  schema = _prune_param(schema, param=param)
110
153
 
111
154
  # Do a single walk to handle pruning operations
112
- if prune_defs or prune_titles or prune_additional_properties:
155
+ if prune_titles or prune_additional_properties:
113
156
  schema = _walk_and_prune(
114
157
  schema,
115
- prune_defs=prune_defs,
116
158
  prune_titles=prune_titles,
117
159
  prune_additional_properties=prune_additional_properties,
118
160
  )
161
+ if prune_defs:
162
+ schema = _prune_unused_defs(schema)
119
163
 
120
164
  return schema
@@ -1,9 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import re
3
4
  from typing import TYPE_CHECKING, Annotated, Any, Literal
4
5
  from urllib.parse import urlparse
5
6
 
6
- from pydantic import AnyUrl, Field
7
+ import httpx
8
+ from pydantic import AnyUrl, ConfigDict, Field
7
9
 
8
10
  from fastmcp.utilities.types import FastMCPBaseModel
9
11
 
@@ -17,7 +19,7 @@ if TYPE_CHECKING:
17
19
 
18
20
  def infer_transport_type_from_url(
19
21
  url: str | AnyUrl,
20
- ) -> Literal["streamable-http", "sse"]:
22
+ ) -> Literal["http", "sse"]:
21
23
  """
22
24
  Infer the appropriate transport type from the given URL.
23
25
  """
@@ -28,10 +30,11 @@ def infer_transport_type_from_url(
28
30
  parsed_url = urlparse(url)
29
31
  path = parsed_url.path
30
32
 
31
- if "/sse/" in path or path.rstrip("/").endswith("/sse"):
33
+ # Match /sse followed by /, ?, &, or end of string
34
+ if re.search(r"/sse(/|\?|&|$)", path):
32
35
  return "sse"
33
36
  else:
34
- return "streamable-http"
37
+ return "http"
35
38
 
36
39
 
37
40
  class StdioMCPServer(FastMCPBaseModel):
@@ -55,14 +58,16 @@ class StdioMCPServer(FastMCPBaseModel):
55
58
  class RemoteMCPServer(FastMCPBaseModel):
56
59
  url: str
57
60
  headers: dict[str, str] = Field(default_factory=dict)
58
- transport: Literal["streamable-http", "sse"] | None = None
61
+ transport: Literal["http", "streamable-http", "sse"] | None = None
59
62
  auth: Annotated[
60
- str | Literal["oauth"] | None,
63
+ str | Literal["oauth"] | httpx.Auth | None,
61
64
  Field(
62
- description='Either a string representing a Bearer token or the literal "oauth" to use OAuth authentication.'
65
+ description='Either a string representing a Bearer token, the literal "oauth" to use OAuth authentication, or an httpx.Auth instance for custom authentication.',
63
66
  ),
64
67
  ] = None
65
68
 
69
+ model_config = ConfigDict(arbitrary_types_allowed=True)
70
+
66
71
  def to_transport(self) -> StreamableHttpTransport | SSETransport:
67
72
  from fastmcp.client.transports import SSETransport, StreamableHttpTransport
68
73
 
@@ -74,6 +79,7 @@ class RemoteMCPServer(FastMCPBaseModel):
74
79
  if transport == "sse":
75
80
  return SSETransport(self.url, headers=self.headers, auth=self.auth)
76
81
  else:
82
+ # Both "http" and "streamable-http" map to StreamableHttpTransport
77
83
  return StreamableHttpTransport(
78
84
  self.url, headers=self.headers, auth=self.auth
79
85
  )
@@ -262,16 +262,18 @@ class OpenAPIParser(
262
262
 
263
263
  if isinstance(resolved_schema, (self.schema_cls)):
264
264
  # Convert schema to dictionary
265
- return resolved_schema.model_dump(
265
+ result = resolved_schema.model_dump(
266
266
  mode="json", by_alias=True, exclude_none=True
267
267
  )
268
268
  elif isinstance(resolved_schema, dict):
269
- return resolved_schema
269
+ result = resolved_schema
270
270
  else:
271
271
  logger.warning(
272
272
  f"Expected Schema after resolving, got {type(resolved_schema)}. Returning empty dict."
273
273
  )
274
- return {}
274
+ result = {}
275
+
276
+ return _replace_ref_with_defs(result)
275
277
  except Exception as e:
276
278
  logger.error(f"Failed to extract schema as dict: {e}", exc_info=False)
277
279
  return {}
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
20
20
  @contextmanager
21
21
  def temporary_settings(**kwargs: Any):
22
22
  """
23
- Temporarily override ControlFlow setting values.
23
+ Temporarily override FastMCP setting values.
24
24
 
25
25
  Args:
26
26
  **kwargs: The settings to override, including nested settings.
@@ -2,6 +2,7 @@
2
2
 
3
3
  import base64
4
4
  import inspect
5
+ import mimetypes
5
6
  from collections.abc import Callable
6
7
  from functools import lru_cache
7
8
  from pathlib import Path
@@ -11,11 +12,13 @@ from typing import Annotated, TypeAlias, TypeVar, Union, get_args, get_origin
11
12
  from mcp.types import (
12
13
  Annotations,
13
14
  AudioContent,
15
+ BlobResourceContents,
14
16
  EmbeddedResource,
15
17
  ImageContent,
16
18
  TextContent,
19
+ TextResourceContents, # Added import
17
20
  )
18
- from pydantic import BaseModel, ConfigDict, TypeAdapter
21
+ from pydantic import AnyUrl, BaseModel, ConfigDict, TypeAdapter, UrlConstraints
19
22
 
20
23
  T = TypeVar("T")
21
24
 
@@ -203,3 +206,89 @@ class Audio:
203
206
  mimeType=mime_type or self._mime_type,
204
207
  annotations=annotations or self.annotations,
205
208
  )
209
+
210
+
211
+ class File:
212
+ """Helper class for returning audio from tools."""
213
+
214
+ def __init__(
215
+ self,
216
+ path: str | Path | None = None,
217
+ data: bytes | None = None,
218
+ format: str | None = None,
219
+ name: str | None = None,
220
+ annotations: Annotations | None = None,
221
+ ):
222
+ if path is None and data is None:
223
+ raise ValueError("Either path or data must be provided")
224
+ if path is not None and data is not None:
225
+ raise ValueError("Only one of path or data can be provided")
226
+
227
+ self.path = Path(path) if path else None
228
+ self.data = data
229
+ self._format = format
230
+ self._mime_type = self._get_mime_type()
231
+ self._name = name
232
+ self.annotations = annotations
233
+
234
+ def _get_mime_type(self) -> str:
235
+ """Get MIME type from format or guess from file extension."""
236
+ if self._format:
237
+ fmt = self._format.lower()
238
+ # Map common text formats to text/plain
239
+ if fmt in {"plain", "txt", "text"}:
240
+ return "text/plain"
241
+ return f"application/{fmt}"
242
+
243
+ if self.path:
244
+ mime_type, _ = mimetypes.guess_type(self.path)
245
+ if mime_type:
246
+ return mime_type
247
+
248
+ return "application/octet-stream"
249
+
250
+ def to_resource_content(
251
+ self,
252
+ mime_type: str | None = None,
253
+ annotations: Annotations | None = None,
254
+ ) -> EmbeddedResource:
255
+ if self.path:
256
+ with open(self.path, "rb") as f:
257
+ raw_data = f.read()
258
+ uri_str = self.path.resolve().as_uri()
259
+ elif self.data is not None:
260
+ raw_data = self.data
261
+ if self._name:
262
+ uri_str = f"file:///{self._name}.{self._mime_type.split('/')[1]}"
263
+ else:
264
+ uri_str = f"file:///resource.{self._mime_type.split('/')[1]}"
265
+ else:
266
+ raise ValueError("No resource data available")
267
+
268
+ mime = mime_type or self._mime_type
269
+ UriType = Annotated[AnyUrl, UrlConstraints(host_required=False)]
270
+ uri = TypeAdapter(UriType).validate_python(uri_str)
271
+
272
+ if mime.startswith("text/"):
273
+ try:
274
+ text = raw_data.decode("utf-8")
275
+ except UnicodeDecodeError:
276
+ text = raw_data.decode("latin-1")
277
+ resource = TextResourceContents(
278
+ text=text,
279
+ mimeType=mime,
280
+ uri=uri,
281
+ )
282
+ else:
283
+ data = base64.b64encode(raw_data).decode()
284
+ resource = BlobResourceContents(
285
+ blob=data,
286
+ mimeType=mime,
287
+ uri=uri,
288
+ )
289
+
290
+ return EmbeddedResource(
291
+ type="resource",
292
+ resource=resource,
293
+ annotations=annotations or self.annotations,
294
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastmcp
3
- Version: 2.8.1
3
+ Version: 2.9.0
4
4
  Summary: The fast, Pythonic way to build MCP servers.
5
5
  Project-URL: Homepage, https://gofastmcp.com
6
6
  Project-URL: Repository, https://github.com/jlowin/fastmcp
@@ -380,7 +380,7 @@ mcp.run(transport="stdio") # Default, so transport argument is optional
380
380
  **Streamable HTTP**: Recommended for web deployments.
381
381
 
382
382
  ```python
383
- mcp.run(transport="streamable-http", host="127.0.0.1", port=8000, path="/mcp")
383
+ mcp.run(transport="http", host="127.0.0.1", port=8000, path="/mcp")
384
384
  ```
385
385
 
386
386
  **SSE**: For compatibility with existing SSE clients.
@@ -1,69 +1,76 @@
1
1
  fastmcp/__init__.py,sha256=5ChT4kg3srdFl0-9dZekGqpzCESlpc6ohrfPbWf1aTo,1300
2
2
  fastmcp/exceptions.py,sha256=-krEavxwddQau6T7MESCR4VjKNLfP9KHJrU1p3y72FU,744
3
3
  fastmcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- fastmcp/settings.py,sha256=DZU5tmyNz7bzc3jhxE4wOzsj_TcPhXiXF_-OPbfr4d0,9009
4
+ fastmcp/settings.py,sha256=2IgZ2cOiwr_bVWkFgY4BZxDKFnayZpCN4q3iT_FEfyE,9011
5
5
  fastmcp/cli/__init__.py,sha256=Ii284TNoG5lxTP40ETMGhHEq3lQZWxu9m9JuU57kUpQ,87
6
6
  fastmcp/cli/claude.py,sha256=IAlcZ4qZKBBj09jZUMEx7EANZE_IR3vcu7zOBJmMOuU,4567
7
- fastmcp/cli/cli.py,sha256=NQ_byPYUhJ8zyMW6VV2JlUlBH8xwB4tRejLK7n-yypc,12681
8
- fastmcp/cli/run.py,sha256=sGH7M3Yi8HGju4sPypKGk3P2cdZq1n3l-_CpJmdGvDc,6277
7
+ fastmcp/cli/cli.py,sha256=598s1S-KdqIB85mwqvXJaBVen6xYY65ek4v-q3lmY4k,15933
8
+ fastmcp/cli/run.py,sha256=Pw3vH5wKRHfbmHRn0saIbC4l450KPOzeQbzPFqG4AbY,6208
9
9
  fastmcp/client/__init__.py,sha256=kd2hhSuD8rZuF87c9zlPJP_icJ-Rx3exyNoK0EzfOtE,617
10
- fastmcp/client/client.py,sha256=QrPWcf0mM5k32Sb8-SG8-3oua8-VxZwGg7egRWcBHho,24957
10
+ fastmcp/client/client.py,sha256=aVeR2S8WeGs2aZDcG1lIdX1gdRPGml2jnfHkLPJNQ-c,25598
11
11
  fastmcp/client/logging.py,sha256=hOPRailZUp89RUck6V4HPaWVZinVrNY8HD4hD0dd-fE,822
12
12
  fastmcp/client/oauth_callback.py,sha256=ODAnVX-ettL82RuI5KpfkKf8iDtYMDue3Tnab5sjQtM,10071
13
13
  fastmcp/client/progress.py,sha256=WjLLDbUKMsx8DK-fqO7AGsXb83ak-6BMrLvzzznGmcI,1043
14
14
  fastmcp/client/roots.py,sha256=IxI_bHwHTmg6c2H-s1av1ZgrRnNDieHtYwdGFbzXT5c,2471
15
15
  fastmcp/client/sampling.py,sha256=Q8PzYCERa1W3xGGI9I9QOhhDM-M4i3P5lESb0cp2iI8,1595
16
- fastmcp/client/transports.py,sha256=QdfWw2AQ6upx9pyInLaW14xcfzI9auA5G67Gy4aWeac,32930
16
+ fastmcp/client/transports.py,sha256=K_5hBTGuJ7iuseQ4Hkjl1ypgdJwZ-Sdt0xgxxEy1W7w,33472
17
17
  fastmcp/client/auth/__init__.py,sha256=4DNsfp4iaQeBcpds0JDdMn6Mmfud44stWLsret0sVKY,91
18
18
  fastmcp/client/auth/bearer.py,sha256=MFEFqcH6u_V86msYiOsEFKN5ks1V9BnBNiPsPLHUTqo,399
19
- fastmcp/client/auth/oauth.py,sha256=xiwLftGkadRNsB5eNPl7JtjOI936qgVjsogvOzoxdO0,14700
19
+ fastmcp/client/auth/oauth.py,sha256=Gu0P4M6875dinVNqjczcJsJJIJNrkoA7UqrSx5NuuwE,14692
20
20
  fastmcp/contrib/README.md,sha256=rKknYSI1T192UvSszqwwDlQ2eYQpxywrNTLoj177SYU,878
21
21
  fastmcp/contrib/bulk_tool_caller/README.md,sha256=5aUUY1TSFKtz1pvTLSDqkUCkGkuqMfMZNsLeaNqEgAc,1960
22
22
  fastmcp/contrib/bulk_tool_caller/__init__.py,sha256=xvGSSaUXTQrc31erBoi1Gh7BikgOliETDiYVTP3rLxY,75
23
23
  fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py,sha256=2NcrGS59qvHo1lfbRaT8NSWfCxN66knciLxFvnGwCLY,4165
24
24
  fastmcp/contrib/bulk_tool_caller/example.py,sha256=6og_8pCJN_CabworC5R82zPAwwwM-W7HNJLQQSnS3lU,319
25
- fastmcp/contrib/mcp_mixin/README.md,sha256=9DDTJXWkA3yv1fp5V58gofmARPQ2xWDhblYGvUhKpDQ,1689
25
+ fastmcp/contrib/mcp_mixin/README.md,sha256=X6rzt_4vC_rmq9jbHmrVPqYLGVVlw9b4TVL4H_0SMmQ,4277
26
26
  fastmcp/contrib/mcp_mixin/__init__.py,sha256=aw9IQ1ssNjCgws4ZNt8bkdpossAAGVAwwjBpMp9O5ZQ,153
27
27
  fastmcp/contrib/mcp_mixin/example.py,sha256=GnunkXmtG5hLLTUsM8aW5ZURU52Z8vI4tNLl-fK7Dg0,1228
28
- fastmcp/contrib/mcp_mixin/mcp_mixin.py,sha256=3e0wHlKI9OF12t-SbpRTL-TWjBBLw7T8ATjCdoDtX6k,8173
28
+ fastmcp/contrib/mcp_mixin/mcp_mixin.py,sha256=sUSJ2o0sTsb061MyPN2xuYP0oI4W6YVQXupY3nnjD50,8687
29
29
  fastmcp/prompts/__init__.py,sha256=An8uMBUh9Hrb7qqcn_5_Hent7IOeSh7EA2IUVsIrtHc,179
30
- fastmcp/prompts/prompt.py,sha256=IZncQ5NrrAdbuQv9iMYGlBdkfteJpLdLGMK8cxVV3xw,9041
31
- fastmcp/prompts/prompt_manager.py,sha256=TKFxndDH5mHzk2b35TlaNpMz0gRf2OV_17gH2bMKAcU,4369
30
+ fastmcp/prompts/prompt.py,sha256=A1IE5kadPEZ8s0wzsAvuwaAY0iMJjyJhzT9MMoecASs,13227
31
+ fastmcp/prompts/prompt_manager.py,sha256=nnQyzAG-k-bAlUA7ftG1djoGnsPLAG_OlCwLRP72oHM,7687
32
32
  fastmcp/resources/__init__.py,sha256=y1iAuqx-GIrS1NqIYzKezIDiYyjNEzzHD35epHpMnXE,463
33
- fastmcp/resources/resource.py,sha256=CY7clkTrF1_3z1yT2HvkA7tGSX9uY0iyZ2AVAXreCCE,4980
34
- fastmcp/resources/resource_manager.py,sha256=y7J8nnLbCPl_9IASYw2IzmUEwDhS56FWi0Dare9Uf2U,11951
35
- fastmcp/resources/template.py,sha256=ohbjlgMzkhVjmjhqa1Bkh5jzj6oWOHKwRxcneYZDt1Q,8415
33
+ fastmcp/resources/resource.py,sha256=l88biP6r5_OWZfWNp9ugIdHyySgI7r6wvVGyEv-EcM4,5384
34
+ fastmcp/resources/resource_manager.py,sha256=pUKHWLjGw21jvHSzBzBPlput7nEa7dEDGR1gt3mF4bI,19797
35
+ fastmcp/resources/template.py,sha256=c8Y_sc4fCnhElE-B5n0J3W5vt-B7oK96_WGce4rav6g,9680
36
36
  fastmcp/resources/types.py,sha256=SiYNLnpXT-mHgNUrzqKUvXYUsY-V3gwJIrYdJfFwDDo,4868
37
37
  fastmcp/server/__init__.py,sha256=bMD4aQD4yJqLz7-mudoNsyeV8UgQfRAg3PRwPvwTEds,119
38
- fastmcp/server/context.py,sha256=Ibn3nv2RpwttPzxElbAkZJNX_SiXrjCCjN5S0vwnGVY,10257
38
+ fastmcp/server/context.py,sha256=wChVb8MxdZNxveWfjGbOrLgiYpUzNjyyQuWOkbburdY,11749
39
39
  fastmcp/server/dependencies.py,sha256=iKJdz1XsVJcrfHo_reXj9ZSldw-HeAwsp9S6lAgfGA8,2358
40
- fastmcp/server/http.py,sha256=2v4_N9piolv4z8Nbkn8K0TtHOZzs683mUNA81uGdDdY,11687
40
+ fastmcp/server/http.py,sha256=gwovXTVKd7UR_mrbMP3WI3eaxFKvZcxwjm3RwKxL6wU,12055
41
41
  fastmcp/server/openapi.py,sha256=rF8umkOQGLejDVH7Ef36QdMmjv6zwPB5tmkgmQscM7A,39539
42
- fastmcp/server/proxy.py,sha256=t0y3mw4X5yO084nevBL-a5mvrLyGc8491F0OTHeuUPQ,10030
43
- fastmcp/server/server.py,sha256=Umn_yjPHcwmxu-PTQGCmuD3GTbWEY2BcUBVqq5ej2CQ,73895
42
+ fastmcp/server/proxy.py,sha256=nz8DSDMd3LWDgtI2a3l3-EYn2i45wvgxx7zdLMs8C84,14944
43
+ fastmcp/server/server.py,sha256=VNtVQx0nBpcGF5kDPS-I_3EfMScL2Lr5dxAQ1WAPFBU,76428
44
44
  fastmcp/server/auth/__init__.py,sha256=doHCLwOIElvH1NrTdpeP9JKfnNf3MDYPSpQfdsQ-uI0,84
45
45
  fastmcp/server/auth/auth.py,sha256=kz02HGwXYU0N0clURZDjFNWdKSpTYmgmCnGJN-jSG3Y,1640
46
46
  fastmcp/server/auth/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
- fastmcp/server/auth/providers/bearer.py,sha256=3pTKL3tEU7FlCD5yI81LTa2n0dBsM7GRpIIn30WCWsA,12679
47
+ fastmcp/server/auth/providers/bearer.py,sha256=RxYPvZiUNhACeSaoFV2rmtY-094jwWdR3ytLL1xjtnE,13961
48
48
  fastmcp/server/auth/providers/bearer_env.py,sha256=zHbJmzT6RhEW9tGG-_aRACQ_t0GwXCvKEAnKQLCO9mY,1892
49
49
  fastmcp/server/auth/providers/in_memory.py,sha256=_8hRo6KZEVqsSSMNxpseJH48LZEywF4uZ687XuOmqYw,13772
50
+ fastmcp/server/middleware/__init__.py,sha256=sKrgbpTlaVdzg_bL8ZI5SGf7EceVqqFUcUr9rvt1r08,112
51
+ fastmcp/server/middleware/error_handling.py,sha256=SoDatr9i3T2qSIUbSEGWrOnu4WPPyMDymnsF5GR_BiE,7572
52
+ fastmcp/server/middleware/logging.py,sha256=igGYQiQ7zvkbhN35kU9LWT7-0cSpH7V-31m6yg6ddSc,5732
53
+ fastmcp/server/middleware/middleware.py,sha256=v6nKcphMhCxwDvbtffPYHHl-WYr9V09czaBRNi-ebqI,6882
54
+ fastmcp/server/middleware/rate_limiting.py,sha256=VTrCoQFmWCm0BxwOrNfG21CBFDDOKJT7IiSEjpJgmPA,7921
55
+ fastmcp/server/middleware/timing.py,sha256=lL_xc-ErLD5lplfvd5-HIyWEbZhgNBYkcQ74KFXAMkA,5591
50
56
  fastmcp/tools/__init__.py,sha256=vzqb-Y7Kf0d5T0aOsld-O-FA8kD7-4uFExChewFHEzY,201
51
- fastmcp/tools/tool.py,sha256=UoqX8Hv2FsYYQkP8dpPlvPoDZMMZf4VJagt6_76iqtE,11123
52
- fastmcp/tools/tool_manager.py,sha256=gq7wYrj1EMjmqJgnJ_ozipEVWmnlSNjIe1zL0-OObss,4805
57
+ fastmcp/tools/tool.py,sha256=I_johIZKUY3Vi--wxuYFBDDc0YDxKiT4CARFHMOxes8,11230
58
+ fastmcp/tools/tool_manager.py,sha256=F3J8IHl-fJ8ocoTEhNrzxgwsgGdX_K5gwXCHz2gfGp0,7790
53
59
  fastmcp/tools/tool_transform.py,sha256=pBRLu6qoXsdg1fwkV219PyJQy_Rp6fFCNOqFFbI4VOc,27612
54
60
  fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31
55
61
  fastmcp/utilities/cache.py,sha256=aV3oZ-ZhMgLSM9iAotlUlEy5jFvGXrVo0Y5Bj4PBtqY,707
56
- fastmcp/utilities/components.py,sha256=NJXop6vn42DC2MyLtJRuJ7QEyac4T5WcOsYaClIog6E,1669
62
+ fastmcp/utilities/components.py,sha256=JhXTFWQ2lUe5h2eDVKQLVWnVfvQ77iCbBxE4CYQEuTs,2382
57
63
  fastmcp/utilities/exceptions.py,sha256=7Z9j5IzM5rT27BC1Mcn8tkS-bjqCYqMKwb2MMTaxJYU,1350
58
64
  fastmcp/utilities/http.py,sha256=1ns1ymBS-WSxbZjGP6JYjSO52Wa_ls4j4WbnXiupoa4,245
59
- fastmcp/utilities/json_schema.py,sha256=m65XU9lPq7pCxJ9vvCeGRl0HOFr6ArezvYpMBR6-gAg,3777
65
+ fastmcp/utilities/inspect.py,sha256=XNA0dfYM5G-FVbJaVJO8loSUUCNypyLA-QjqTOneJyU,10833
66
+ fastmcp/utilities/json_schema.py,sha256=K0QH5UazBD_tweBi-TguWYjUu5Lgp9wcM-wT42Fet5w,5022
60
67
  fastmcp/utilities/logging.py,sha256=B1WNO-ZWFjd9wiFSh13YtW1hAKaNmbpscDZleIAhr-g,1317
61
- fastmcp/utilities/mcp_config.py,sha256=kbmvpF5YE7eiDH68XObagFGPKw26SwuDchmH7pyFSD4,2519
62
- fastmcp/utilities/openapi.py,sha256=ctceiGb4jYgzZGSseMb-yZccEEXf41P-dhB3ae9lGdk,38992
63
- fastmcp/utilities/tests.py,sha256=72ryn-IyrvE9BKL_RPJ6T__qTcSRp8yzhOQSM6cdYpE,3903
64
- fastmcp/utilities/types.py,sha256=Ro5UMB1K-uKtLgzbCCHAb_3ABh0v7QF5Or70_0Yyo00,6650
65
- fastmcp-2.8.1.dist-info/METADATA,sha256=hJrGycsSOIR62GmBlTfYRS6GN7LjPa3eLsrpDO58HCM,17773
66
- fastmcp-2.8.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
67
- fastmcp-2.8.1.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
68
- fastmcp-2.8.1.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
69
- fastmcp-2.8.1.dist-info/RECORD,,
68
+ fastmcp/utilities/mcp_config.py,sha256=ryjAfJUPquDSoKdSymPH4M2B0WvuM3pWUGI3cOgAX80,2782
69
+ fastmcp/utilities/openapi.py,sha256=54rABuCPw067sDkbqPVDuqxeelWqRAdDX8oC_YUx4m4,39049
70
+ fastmcp/utilities/tests.py,sha256=O9hRSjnyaYQqu1RJ-CFBw1cIjezlwSQtS-Ea_iqO4sY,3899
71
+ fastmcp/utilities/types.py,sha256=XfTwZU1MhBfMCPU5SDNu3z8-D_yaLbw_PfoXCZOm530,9589
72
+ fastmcp-2.9.0.dist-info/METADATA,sha256=DfZzyvO8K8CmlttO9qA4LiHF3v6Aq06XH9jN15nZgng,17762
73
+ fastmcp-2.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
74
+ fastmcp-2.9.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
75
+ fastmcp-2.9.0.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
76
+ fastmcp-2.9.0.dist-info/RECORD,,