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
@@ -0,0 +1,261 @@
1
+ """AggregateProvider for combining multiple providers into one.
2
+
3
+ This module provides `AggregateProvider`, a utility class that presents
4
+ multiple providers as a single unified provider. Useful when you want to
5
+ combine custom providers without creating a full FastMCP server.
6
+
7
+ Example:
8
+ ```python
9
+ from fastmcp.server.providers import AggregateProvider
10
+
11
+ # Combine multiple providers into one
12
+ combined = AggregateProvider()
13
+ combined.add_provider(provider1)
14
+ combined.add_provider(provider2, namespace="api") # Tools become "api_foo"
15
+
16
+ # Use like any other provider
17
+ tools = await combined.list_tools()
18
+ ```
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+ from collections.abc import AsyncIterator, Sequence
25
+ from contextlib import AsyncExitStack, asynccontextmanager
26
+ from typing import TYPE_CHECKING, TypeVar
27
+
28
+ from fastmcp.exceptions import NotFoundError
29
+ from fastmcp.server.providers.base import Provider
30
+ from fastmcp.server.transforms import Namespace
31
+ from fastmcp.utilities.async_utils import gather
32
+ from fastmcp.utilities.components import FastMCPComponent
33
+ from fastmcp.utilities.versions import VersionSpec, version_sort_key
34
+
35
+ if TYPE_CHECKING:
36
+ from fastmcp.prompts.prompt import Prompt
37
+ from fastmcp.resources.resource import Resource
38
+ from fastmcp.resources.template import ResourceTemplate
39
+ from fastmcp.tools.tool import Tool
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ T = TypeVar("T")
44
+
45
+
46
+ class AggregateProvider(Provider):
47
+ """Utility provider that combines multiple providers into one.
48
+
49
+ Components are aggregated from all providers. For get_* operations,
50
+ providers are queried in parallel and the highest version is returned.
51
+
52
+ When adding providers with a namespace, wrap_transform() is used to apply
53
+ the Namespace transform. This means namespace transformation is handled
54
+ by the wrapped provider, not by AggregateProvider.
55
+
56
+ Errors from individual providers are logged and skipped (graceful degradation).
57
+
58
+ Example:
59
+ ```python
60
+ combined = AggregateProvider()
61
+ combined.add_provider(db_provider)
62
+ combined.add_provider(api_provider, namespace="api")
63
+ # db_provider's tools keep original names
64
+ # api_provider's tools become "api_foo", "api_bar", etc.
65
+ ```
66
+ """
67
+
68
+ def __init__(self, providers: Sequence[Provider] | None = None) -> None:
69
+ """Initialize with an optional sequence of providers.
70
+
71
+ Args:
72
+ providers: Optional initial providers (without namespacing).
73
+ For namespaced providers, use add_provider() instead.
74
+ """
75
+ super().__init__()
76
+ self.providers: list[Provider] = list(providers or [])
77
+
78
+ def add_provider(self, provider: Provider, *, namespace: str = "") -> None:
79
+ """Add a provider with optional namespace.
80
+
81
+ If the provider is a FastMCP server, it's automatically wrapped in
82
+ FastMCPProvider to ensure middleware is invoked correctly.
83
+
84
+ Args:
85
+ provider: The provider to add.
86
+ namespace: Optional namespace prefix. When set:
87
+ - Tools become "namespace_toolname"
88
+ - Resources become "protocol://namespace/path"
89
+ - Prompts become "namespace_promptname"
90
+ """
91
+ # Import here to avoid circular imports
92
+ from fastmcp.server.server import FastMCP
93
+
94
+ # Auto-wrap FastMCP servers to ensure middleware is invoked
95
+ if isinstance(provider, FastMCP):
96
+ from fastmcp.server.providers.fastmcp_provider import FastMCPProvider
97
+
98
+ provider = FastMCPProvider(provider)
99
+
100
+ # Apply namespace via wrap_transform if specified
101
+ if namespace:
102
+ provider = provider.wrap_transform(Namespace(namespace))
103
+
104
+ self.providers.append(provider)
105
+
106
+ def _collect_list_results(
107
+ self, results: list[Sequence[T] | BaseException], operation: str
108
+ ) -> list[T]:
109
+ """Collect successful list results, logging any exceptions."""
110
+ collected: list[T] = []
111
+ for i, result in enumerate(results):
112
+ if isinstance(result, BaseException):
113
+ logger.debug(
114
+ f"Error during {operation} from provider "
115
+ f"{self.providers[i]}: {result}"
116
+ )
117
+ continue
118
+ collected.extend(result)
119
+ return collected
120
+
121
+ def _get_highest_version_result(
122
+ self,
123
+ results: list[FastMCPComponent | None | BaseException],
124
+ operation: str,
125
+ ) -> FastMCPComponent | None:
126
+ """Get the highest version from successful non-None results.
127
+
128
+ Used for versioned components where we want the highest version
129
+ across all providers rather than the first match.
130
+ """
131
+ valid: list[FastMCPComponent] = []
132
+ for i, result in enumerate(results):
133
+ if isinstance(result, BaseException):
134
+ if not isinstance(result, NotFoundError):
135
+ logger.debug(
136
+ f"Error during {operation} from provider "
137
+ f"{self.providers[i]}: {result}"
138
+ )
139
+ continue
140
+ if result is not None:
141
+ valid.append(result)
142
+ if not valid:
143
+ return None
144
+ return max(valid, key=version_sort_key)
145
+
146
+ def __repr__(self) -> str:
147
+ return f"AggregateProvider(providers={self.providers!r})"
148
+
149
+ # -------------------------------------------------------------------------
150
+ # Tools
151
+ # -------------------------------------------------------------------------
152
+
153
+ async def _list_tools(self) -> Sequence[Tool]:
154
+ """List all tools from all providers."""
155
+ results = await gather(
156
+ *[p.list_tools() for p in self.providers],
157
+ return_exceptions=True,
158
+ )
159
+ return self._collect_list_results(results, "list_tools")
160
+
161
+ async def _get_tool(
162
+ self, name: str, version: VersionSpec | None = None
163
+ ) -> Tool | None:
164
+ """Get tool by name from providers."""
165
+ results = await gather(
166
+ *[p.get_tool(name, version) for p in self.providers],
167
+ return_exceptions=True,
168
+ )
169
+ return self._get_highest_version_result(results, f"get_tool({name!r})") # type: ignore[return-value]
170
+
171
+ # -------------------------------------------------------------------------
172
+ # Resources
173
+ # -------------------------------------------------------------------------
174
+
175
+ async def _list_resources(self) -> Sequence[Resource]:
176
+ """List all resources from all providers."""
177
+ results = await gather(
178
+ *[p.list_resources() for p in self.providers],
179
+ return_exceptions=True,
180
+ )
181
+ return self._collect_list_results(results, "list_resources")
182
+
183
+ async def _get_resource(
184
+ self, uri: str, version: VersionSpec | None = None
185
+ ) -> Resource | None:
186
+ """Get resource by URI from providers."""
187
+ results = await gather(
188
+ *[p.get_resource(uri, version) for p in self.providers],
189
+ return_exceptions=True,
190
+ )
191
+ return self._get_highest_version_result(results, f"get_resource({uri!r})") # type: ignore[return-value]
192
+
193
+ # -------------------------------------------------------------------------
194
+ # Resource Templates
195
+ # -------------------------------------------------------------------------
196
+
197
+ async def _list_resource_templates(self) -> Sequence[ResourceTemplate]:
198
+ """List all resource templates from all providers."""
199
+ results = await gather(
200
+ *[p.list_resource_templates() for p in self.providers],
201
+ return_exceptions=True,
202
+ )
203
+ return self._collect_list_results(results, "list_resource_templates")
204
+
205
+ async def _get_resource_template(
206
+ self, uri: str, version: VersionSpec | None = None
207
+ ) -> ResourceTemplate | None:
208
+ """Get resource template by URI from providers."""
209
+ results = await gather(
210
+ *[p.get_resource_template(uri, version) for p in self.providers],
211
+ return_exceptions=True,
212
+ )
213
+ return self._get_highest_version_result(
214
+ results, f"get_resource_template({uri!r})"
215
+ ) # type: ignore[return-value]
216
+
217
+ # -------------------------------------------------------------------------
218
+ # Prompts
219
+ # -------------------------------------------------------------------------
220
+
221
+ async def _list_prompts(self) -> Sequence[Prompt]:
222
+ """List all prompts from all providers."""
223
+ results = await gather(
224
+ *[p.list_prompts() for p in self.providers],
225
+ return_exceptions=True,
226
+ )
227
+ return self._collect_list_results(results, "list_prompts")
228
+
229
+ async def _get_prompt(
230
+ self, name: str, version: VersionSpec | None = None
231
+ ) -> Prompt | None:
232
+ """Get prompt by name from providers."""
233
+ results = await gather(
234
+ *[p.get_prompt(name, version) for p in self.providers],
235
+ return_exceptions=True,
236
+ )
237
+ return self._get_highest_version_result(results, f"get_prompt({name!r})") # type: ignore[return-value]
238
+
239
+ # -------------------------------------------------------------------------
240
+ # Tasks
241
+ # -------------------------------------------------------------------------
242
+
243
+ async def get_tasks(self) -> Sequence[FastMCPComponent]:
244
+ """Get all task-eligible components from all providers."""
245
+ results = await gather(
246
+ *[p.get_tasks() for p in self.providers],
247
+ return_exceptions=True,
248
+ )
249
+ return self._collect_list_results(results, "get_tasks")
250
+
251
+ # -------------------------------------------------------------------------
252
+ # Lifecycle
253
+ # -------------------------------------------------------------------------
254
+
255
+ @asynccontextmanager
256
+ async def lifespan(self) -> AsyncIterator[None]:
257
+ """Combine lifespans of all providers."""
258
+ async with AsyncExitStack() as stack:
259
+ for p in self.providers:
260
+ await stack.enter_async_context(p.lifespan())
261
+ yield