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,186 +1,121 @@
1
1
  """
2
- Routes and helpers for managing tools, resources, and prompts in FastMCP.
3
- Provides endpoints for enabling/disabling components via HTTP, with optional authentication scopes.
4
- """
2
+ HTTP routes for enabling/disabling components in FastMCP.
5
3
 
6
- from typing import Any
4
+ Provides REST endpoints for controlling component enabled state with optional
5
+ authentication scopes.
6
+ """
7
7
 
8
8
  from mcp.server.auth.middleware.bearer_auth import RequireAuthMiddleware
9
9
  from starlette.applications import Starlette
10
- from starlette.exceptions import HTTPException as StarletteHTTPException
11
10
  from starlette.requests import Request
12
11
  from starlette.responses import JSONResponse
13
12
  from starlette.routing import Mount, Route
14
13
 
15
- from fastmcp.contrib.component_manager.component_service import ComponentService
16
- from fastmcp.exceptions import NotFoundError
17
14
  from fastmcp.server.server import FastMCP
18
15
 
19
16
 
20
17
  def set_up_component_manager(
21
18
  server: FastMCP, path: str = "/", required_scopes: list[str] | None = None
22
- ):
23
- """Set up routes for enabling/disabling tools, resources, and prompts.
19
+ ) -> None:
20
+ """Set up HTTP routes for enabling/disabling tools, resources, and prompts.
21
+
24
22
  Args:
25
- server: The FastMCP server instance
26
- path: Path used to mount all component-related routes on the server
27
- required_scopes: Optional list of scopes required for these routes. Applies only if authentication is enabled.
23
+ server: The FastMCP server instance.
24
+ path: Base path for component management routes.
25
+ required_scopes: Optional list of scopes required for these routes.
26
+ Applies only if authentication is enabled.
27
+
28
+ Routes created:
29
+ POST /tools/{name}/enable[?version=v1]
30
+ POST /tools/{name}/disable[?version=v1]
31
+ POST /resources/{uri}/enable[?version=v1]
32
+ POST /resources/{uri}/disable[?version=v1]
33
+ POST /prompts/{name}/enable[?version=v1]
34
+ POST /prompts/{name}/disable[?version=v1]
28
35
  """
29
-
30
- service = ComponentService(server)
31
- routes: list[Route] = []
32
- mounts: list[Mount] = []
33
- route_configs = {
34
- "tool": {
35
- "param": "tool_name",
36
- "enable": service._enable_tool,
37
- "disable": service._disable_tool,
38
- },
39
- "resource": {
40
- "param": "uri:path",
41
- "enable": service._enable_resource,
42
- "disable": service._disable_resource,
43
- },
44
- "prompt": {
45
- "param": "prompt_name",
46
- "enable": service._enable_prompt,
47
- "disable": service._disable_prompt,
48
- },
49
- }
50
-
51
36
  if required_scopes is None:
52
- routes.extend(build_component_manager_endpoints(route_configs, path))
37
+ # No auth - include path prefix in routes
38
+ routes = _build_routes(server, path)
39
+ server._additional_http_routes.extend(routes)
53
40
  else:
54
- if path != "/":
55
- mounts.append(
56
- build_component_manager_mount(route_configs, path, required_scopes)
57
- )
58
- else:
59
- mounts.append(
60
- build_component_manager_mount(
61
- {"tool": route_configs["tool"]}, "/tools", required_scopes
62
- )
63
- )
64
- mounts.append(
65
- build_component_manager_mount(
66
- {"resource": route_configs["resource"]},
67
- "/resources",
68
- required_scopes,
69
- )
70
- )
71
- mounts.append(
72
- build_component_manager_mount(
73
- {"prompt": route_configs["prompt"]}, "/prompts", required_scopes
74
- )
75
- )
76
-
77
- server._additional_http_routes.extend(routes)
78
- server._additional_http_routes.extend(mounts)
79
-
80
-
81
- def make_endpoint(action, component, config):
82
- """
83
- Factory for creating Starlette endpoint functions for enabling/disabling a component.
84
- Args:
85
- action: 'enable' or 'disable'
86
- component: The component type (e.g., 'tool', 'resource', or 'prompt')
87
- config: Dict with param and handler functions for the component
88
- Returns:
89
- An async endpoint function for Starlette.
90
- """
91
-
92
- async def endpoint(request: Request):
93
- name = request.path_params[config["param"].split(":")[0]]
41
+ # With auth - Mount handles path prefix, routes shouldn't have it
42
+ routes = _build_routes(server, "/")
43
+ mount = Mount(
44
+ path if path != "/" else "",
45
+ app=RequireAuthMiddleware(Starlette(routes=routes), required_scopes),
46
+ )
47
+ server._additional_http_routes.append(mount)
48
+
49
+
50
+ def _build_routes(server: FastMCP, base_path: str) -> list[Route]:
51
+ """Build all component management routes."""
52
+ prefix = base_path.rstrip("/") if base_path != "/" else ""
53
+
54
+ return [
55
+ # Tools
56
+ Route(
57
+ f"{prefix}/tools/{{name}}/enable",
58
+ endpoint=_make_endpoint(server, "tool", "enable"),
59
+ methods=["POST"],
60
+ ),
61
+ Route(
62
+ f"{prefix}/tools/{{name}}/disable",
63
+ endpoint=_make_endpoint(server, "tool", "disable"),
64
+ methods=["POST"],
65
+ ),
66
+ # Resources
67
+ Route(
68
+ f"{prefix}/resources/{{uri:path}}/enable",
69
+ endpoint=_make_endpoint(server, "resource", "enable"),
70
+ methods=["POST"],
71
+ ),
72
+ Route(
73
+ f"{prefix}/resources/{{uri:path}}/disable",
74
+ endpoint=_make_endpoint(server, "resource", "disable"),
75
+ methods=["POST"],
76
+ ),
77
+ # Prompts
78
+ Route(
79
+ f"{prefix}/prompts/{{name}}/enable",
80
+ endpoint=_make_endpoint(server, "prompt", "enable"),
81
+ methods=["POST"],
82
+ ),
83
+ Route(
84
+ f"{prefix}/prompts/{{name}}/disable",
85
+ endpoint=_make_endpoint(server, "prompt", "disable"),
86
+ methods=["POST"],
87
+ ),
88
+ ]
94
89
 
95
- try:
96
- await config[action](name)
97
- return JSONResponse(
98
- {"message": f"{action.capitalize()}d {component}: {name}"}
99
- )
100
- except NotFoundError as e:
101
- raise StarletteHTTPException(
102
- status_code=404,
103
- detail=f"Unknown {component}: {name}",
104
- ) from e
105
90
 
106
- return endpoint
91
+ def _make_endpoint(server: FastMCP, component_type: str, action: str):
92
+ """Create an endpoint function for enabling/disabling a component type."""
107
93
 
94
+ async def endpoint(request: Request) -> JSONResponse:
95
+ # Get name from path params (tools/prompts use 'name', resources use 'uri')
96
+ name = request.path_params.get("name") or request.path_params.get("uri")
97
+ version = request.query_params.get("version")
108
98
 
109
- def make_route(action, component, config, required_scopes, root_path) -> Route:
110
- """
111
- Creates a Starlette Route for enabling/disabling a component.
112
- Args:
113
- action: 'enable' or 'disable'
114
- component: The component type
115
- config: Dict with param and handler functions
116
- required_scopes: Optional list of required auth scopes
117
- root_path: The base path for the route
118
- Returns:
119
- A Starlette Route object.
120
- """
121
- endpoint = make_endpoint(action, component, config)
122
-
123
- if required_scopes is not None and root_path in [
124
- "/tools",
125
- "/resources",
126
- "/prompts",
127
- ]:
128
- path = f"/{{{config['param']}}}/{action}"
129
- else:
130
- if root_path != "/" and required_scopes is None:
131
- path = f"{root_path}/{component}s/{{{config['param']}}}/{action}"
99
+ # Map component type to components list
100
+ # Note: "resource" in the route can refer to either a resource or template
101
+ # We need to check if it's a template (contains {}) and use "template" if so
102
+ if component_type == "resource" and name is not None and "{" in name:
103
+ components = ["template"]
104
+ elif component_type == "resource":
105
+ components = ["resource"]
132
106
  else:
133
- path = f"/{component}s/{{{config['param']}}}/{action}"
134
-
135
- return Route(path, endpoint=endpoint, methods=["POST"])
136
-
137
-
138
- def build_component_manager_endpoints(
139
- route_configs, root_path, required_scopes=None
140
- ) -> list[Route]:
141
- """
142
- Build a list of Starlette Route objects for all components/actions.
143
- Args:
144
- route_configs: Dict describing component types and their handlers
145
- root_path: The base path for the routes
146
- required_scopes: Optional list of required auth scopes
147
- Returns:
148
- List of Starlette Route objects for component management.
149
- """
150
- component_management_routes: list[Route] = []
107
+ component_map = {
108
+ "tool": ["tool"],
109
+ "prompt": ["prompt"],
110
+ }
111
+ components = component_map[component_type]
151
112
 
152
- for component in route_configs:
153
- config: dict[str, Any] = route_configs[component]
154
- for action in ["enable", "disable"]:
155
- component_management_routes.append(
156
- make_route(action, component, config, required_scopes, root_path)
157
- )
113
+ # Call server.enable() or server.disable()
114
+ method = getattr(server, action)
115
+ method(names={name} if name else None, version=version, components=components)
158
116
 
159
- return component_management_routes
117
+ return JSONResponse(
118
+ {"message": f"{action.capitalize()}d {component_type}: {name}"}
119
+ )
160
120
 
161
-
162
- def build_component_manager_mount(route_configs, root_path, required_scopes) -> Mount:
163
- """
164
- Build a Starlette Mount with authentication for component management routes.
165
- Args:
166
- route_configs: Dict describing component types and their handlers
167
- root_path: The base path for the mount
168
- required_scopes: List of required auth scopes
169
- Returns:
170
- A Starlette Mount object with authentication middleware.
171
- """
172
- component_management_routes: list[Route] = []
173
-
174
- for component in route_configs:
175
- config: dict[str, Any] = route_configs[component]
176
- for action in ["enable", "disable"]:
177
- component_management_routes.append(
178
- make_route(action, component, config, required_scopes, root_path)
179
- )
180
-
181
- return Mount(
182
- f"{root_path}",
183
- app=RequireAuthMiddleware(
184
- Starlette(routes=component_management_routes), required_scopes
185
- ),
186
- )
121
+ return endpoint
@@ -44,7 +44,7 @@ mounted = FastMCP(
44
44
  set_up_component_manager(server=mounted, required_scopes=["mounted:write"])
45
45
 
46
46
  # Mount
47
- mcp.mount(server=mounted, prefix="mo")
47
+ mcp.mount(server=mounted, namespace="mo")
48
48
 
49
49
 
50
50
  @mcp.resource("resource://greeting")
@@ -40,11 +40,11 @@ first_sample.register_all(mcp_server=mcp, prefix="first")
40
40
  second_sample.register_all(mcp_server=mcp, prefix="second")
41
41
 
42
42
 
43
- async def list_components():
43
+ async def list_components() -> None:
44
44
  print("MCP Server running with registered components...")
45
- print("Tools:", list(await mcp.get_tools()))
46
- print("Resources:", list(await mcp.get_resources()))
47
- print("Prompts:", list(await mcp.get_prompts()))
45
+ print("Tools:", list(await mcp.list_tools()))
46
+ print("Resources:", list(await mcp.list_resources()))
47
+ print("Prompts:", list(await mcp.list_prompts()))
48
48
 
49
49
 
50
50
  if __name__ == "__main__":
@@ -1,10 +1,12 @@
1
1
  """Provides a base mixin class and decorators for easy registration of class methods with FastMCP."""
2
2
 
3
+ import warnings
3
4
  from collections.abc import Callable
4
5
  from typing import TYPE_CHECKING, Any
5
6
 
6
7
  from mcp.types import Annotations, ToolAnnotations
7
8
 
9
+ import fastmcp
8
10
  from fastmcp.prompts.prompt import Prompt
9
11
  from fastmcp.resources.resource import Resource
10
12
  from fastmcp.tools.tool import Tool
@@ -28,11 +30,19 @@ def mcp_tool(
28
30
  tags: set[str] | None = None,
29
31
  annotations: ToolAnnotations | dict[str, Any] | None = None,
30
32
  exclude_args: list[str] | None = None,
31
- serializer: Callable[[Any], str] | None = None,
33
+ serializer: Callable[[Any], str] | None = None, # Deprecated
32
34
  meta: dict[str, Any] | None = None,
33
35
  enabled: bool | None = None,
34
36
  ) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
35
37
  """Decorator to mark a method as an MCP tool for later registration."""
38
+ if serializer is not None and fastmcp.settings.deprecation_warnings:
39
+ warnings.warn(
40
+ "The `serializer` parameter is deprecated. "
41
+ "Return ToolResult from your tools for full control over serialization. "
42
+ "See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.",
43
+ DeprecationWarning,
44
+ stacklevel=2,
45
+ )
36
46
 
37
47
  def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
38
48
  call_args = {
@@ -170,7 +180,6 @@ class MCPMixin:
170
180
  serializer=registration_info.get("serializer"),
171
181
  output_schema=registration_info.get("output_schema"),
172
182
  meta=registration_info.get("meta"),
173
- enabled=registration_info.get("enabled"),
174
183
  )
175
184
 
176
185
  mcp_server.add_tool(tool)
@@ -210,7 +219,6 @@ class MCPMixin:
210
219
  description=registration_info.get("description"),
211
220
  mime_type=registration_info.get("mime_type"),
212
221
  tags=registration_info.get("tags"),
213
- enabled=registration_info.get("enabled"),
214
222
  annotations=registration_info.get("annotations"),
215
223
  meta=registration_info.get("meta"),
216
224
  )
@@ -245,7 +253,6 @@ class MCPMixin:
245
253
  title=registration_info.get("title"),
246
254
  description=registration_info.get("description"),
247
255
  tags=registration_info.get("tags"),
248
- enabled=registration_info.get("enabled"),
249
256
  meta=registration_info.get("meta"),
250
257
  )
251
258
  mcp_server.add_prompt(prompt)
fastmcp/decorators.py ADDED
@@ -0,0 +1,41 @@
1
+ """Shared decorator utilities for FastMCP."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import inspect
6
+ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
7
+
8
+ if TYPE_CHECKING:
9
+ from fastmcp.prompts.function_prompt import PromptMeta
10
+ from fastmcp.resources.function_resource import ResourceMeta
11
+ from fastmcp.server.tasks.config import TaskConfig
12
+ from fastmcp.tools.function_tool import ToolMeta
13
+
14
+ FastMCPMeta = ToolMeta | ResourceMeta | PromptMeta
15
+
16
+
17
+ def resolve_task_config(task: bool | TaskConfig | None) -> bool | TaskConfig:
18
+ """Resolve task config, defaulting None to False."""
19
+ return task if task is not None else False
20
+
21
+
22
+ @runtime_checkable
23
+ class HasFastMCPMeta(Protocol):
24
+ """Protocol for callables decorated with FastMCP metadata."""
25
+
26
+ __fastmcp__: Any
27
+
28
+
29
+ def get_fastmcp_meta(fn: Any) -> Any | None:
30
+ """Extract FastMCP metadata from a function, handling bound methods and wrappers."""
31
+ if hasattr(fn, "__fastmcp__"):
32
+ return fn.__fastmcp__
33
+ if hasattr(fn, "__func__") and hasattr(fn.__func__, "__fastmcp__"):
34
+ return fn.__func__.__fastmcp__
35
+ try:
36
+ unwrapped = inspect.unwrap(fn)
37
+ if unwrapped is not fn and hasattr(unwrapped, "__fastmcp__"):
38
+ return unwrapped.__fastmcp__
39
+ except ValueError:
40
+ pass
41
+ return None
fastmcp/dependencies.py CHANGED
@@ -3,9 +3,18 @@
3
3
  This module re-exports dependency injection symbols from Docket and FastMCP
4
4
  to provide a clean, centralized import location for all dependency-related
5
5
  functionality.
6
+
7
+ DI features (Depends, CurrentContext, CurrentFastMCP) work without pydocket
8
+ using a vendored DI engine. Only task-related dependencies (CurrentDocket,
9
+ CurrentWorker) and background task execution require fastmcp[tasks].
6
10
  """
7
11
 
8
- from docket import Depends
12
+ # Try docket first for isinstance compatibility, fall back to vendored
13
+ try:
14
+ from docket import Depends
15
+ except ImportError:
16
+ from fastmcp._vendor.docket_di import Depends
17
+
9
18
 
10
19
  from fastmcp.server.dependencies import (
11
20
  CurrentContext,
@@ -13,6 +22,7 @@ from fastmcp.server.dependencies import (
13
22
  CurrentFastMCP,
14
23
  CurrentWorker,
15
24
  Progress,
25
+ ProgressLike,
16
26
  )
17
27
 
18
28
  __all__ = [
@@ -22,4 +32,5 @@ __all__ = [
22
32
  "CurrentWorker",
23
33
  "Depends",
24
34
  "Progress",
35
+ "ProgressLike",
25
36
  ]
fastmcp/exceptions.py CHANGED
@@ -37,3 +37,7 @@ class NotFoundError(Exception):
37
37
 
38
38
  class DisabledError(Exception):
39
39
  """Object is disabled."""
40
+
41
+
42
+ class AuthorizationError(FastMCPError):
43
+ """Error when authorization check fails."""
@@ -1,28 +1,31 @@
1
- """Deprecated: Import from fastmcp.server.openapi instead."""
1
+ """Deprecated: Import from fastmcp.server.providers.openapi instead."""
2
2
 
3
3
  import warnings
4
4
 
5
- from fastmcp.server.openapi import (
6
- ComponentFn,
7
- DEFAULT_ROUTE_MAPPINGS,
8
- FastMCPOpenAPI,
9
- MCPType,
10
- OpenAPIResource,
11
- OpenAPIResourceTemplate,
12
- OpenAPITool,
13
- RouteMap,
14
- RouteMapFn,
15
- _determine_route_type,
16
- )
17
-
18
5
  # Deprecated in 2.14 when OpenAPI support was promoted out of experimental
19
6
  warnings.warn(
20
7
  "Importing from fastmcp.experimental.server.openapi is deprecated. "
21
- "Import from fastmcp.server.openapi instead.",
8
+ "Import from fastmcp.server.providers.openapi instead.",
22
9
  DeprecationWarning,
23
10
  stacklevel=2,
24
11
  )
25
12
 
13
+ # Import from canonical location
14
+ from fastmcp.server.openapi.server import FastMCPOpenAPI as FastMCPOpenAPI # noqa: E402
15
+ from fastmcp.server.providers.openapi import ( # noqa: E402
16
+ ComponentFn as ComponentFn,
17
+ MCPType as MCPType,
18
+ OpenAPIResource as OpenAPIResource,
19
+ OpenAPIResourceTemplate as OpenAPIResourceTemplate,
20
+ OpenAPITool as OpenAPITool,
21
+ RouteMap as RouteMap,
22
+ RouteMapFn as RouteMapFn,
23
+ )
24
+ from fastmcp.server.providers.openapi.routing import ( # noqa: E402
25
+ DEFAULT_ROUTE_MAPPINGS as DEFAULT_ROUTE_MAPPINGS,
26
+ _determine_route_type as _determine_route_type,
27
+ )
28
+
26
29
  __all__ = [
27
30
  "DEFAULT_ROUTE_MAPPINGS",
28
31
  "ComponentFn",
fastmcp/mcp_config.py CHANGED
@@ -95,25 +95,30 @@ class _TransformingMCPServerMixin(FastMCPBaseModel):
95
95
  client_name: str | None = None,
96
96
  ) -> tuple[FastMCP[Any], ClientTransport]:
97
97
  """Turn the Transforming MCPServer into a FastMCP Server and also return the underlying transport."""
98
- from fastmcp import FastMCP
99
98
  from fastmcp.client import Client
100
99
  from fastmcp.client.transports import (
101
100
  ClientTransport, # pyright: ignore[reportUnusedImport]
102
101
  )
102
+ from fastmcp.server import create_proxy
103
103
 
104
104
  transport: ClientTransport = super().to_transport() # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue, reportUnknownVariableType] # ty: ignore[unresolved-attribute]
105
105
  transport = cast(ClientTransport, transport)
106
106
 
107
107
  client: Client[ClientTransport] = Client(transport=transport, name=client_name)
108
108
 
109
- wrapped_mcp_server = FastMCP.as_proxy(
109
+ wrapped_mcp_server = create_proxy(
110
+ client,
110
111
  name=server_name,
111
- backend=client,
112
- tool_transformations=self.tools,
113
112
  include_tags=self.include_tags,
114
113
  exclude_tags=self.exclude_tags,
115
114
  )
116
115
 
116
+ # Apply tool transforms if configured
117
+ if self.tools:
118
+ from fastmcp.server.transforms import ToolTransform
119
+
120
+ wrapped_mcp_server.add_transform(ToolTransform(self.tools))
121
+
117
122
  return wrapped_mcp_server, transport
118
123
 
119
124
  def to_transport(self) -> ClientTransport:
@@ -143,6 +148,9 @@ class StdioMCPServer(BaseModel):
143
148
  # Execution context
144
149
  cwd: str | None = None # Working directory for command execution
145
150
  timeout: int | None = None # Maximum response time in milliseconds
151
+ keep_alive: bool | None = (
152
+ None # Whether to keep the subprocess alive between connections
153
+ )
146
154
 
147
155
  # Metadata
148
156
  description: str | None = None # Human-readable server description
@@ -161,6 +169,7 @@ class StdioMCPServer(BaseModel):
161
169
  args=self.args,
162
170
  env=self.env,
163
171
  cwd=self.cwd,
172
+ keep_alive=self.keep_alive,
164
173
  )
165
174
 
166
175
 
@@ -1,9 +1,12 @@
1
- from .prompt import Prompt, PromptMessage, Message
2
- from .prompt_manager import PromptManager
1
+ from .function_prompt import FunctionPrompt, prompt
2
+ from .prompt import Message, Prompt, PromptArgument, PromptMessage, PromptResult
3
3
 
4
4
  __all__ = [
5
+ "FunctionPrompt",
5
6
  "Message",
6
7
  "Prompt",
7
- "PromptManager",
8
+ "PromptArgument",
8
9
  "PromptMessage",
10
+ "PromptResult",
11
+ "prompt",
9
12
  ]