fastmcp 2.6.0__py3-none-any.whl → 2.7.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.
fastmcp/tools/tool.py CHANGED
@@ -2,19 +2,21 @@ from __future__ import annotations
2
2
 
3
3
  import inspect
4
4
  import json
5
+ from abc import ABC, abstractmethod
5
6
  from collections.abc import Callable
6
7
  from typing import TYPE_CHECKING, Annotated, Any
7
8
 
8
9
  import pydantic_core
9
10
  from mcp.types import EmbeddedResource, ImageContent, TextContent, ToolAnnotations
10
11
  from mcp.types import Tool as MCPTool
11
- from pydantic import BaseModel, BeforeValidator, Field
12
+ from pydantic import BeforeValidator, Field
12
13
 
13
14
  import fastmcp
14
15
  from fastmcp.server.dependencies import get_context
15
16
  from fastmcp.utilities.json_schema import compress_schema
16
17
  from fastmcp.utilities.logging import get_logger
17
18
  from fastmcp.utilities.types import (
19
+ FastMCPBaseModel,
18
20
  Image,
19
21
  _convert_set_defaults,
20
22
  find_kwarg_by_type,
@@ -31,10 +33,9 @@ def default_serializer(data: Any) -> str:
31
33
  return pydantic_core.to_json(data, fallback=str, indent=2).decode()
32
34
 
33
35
 
34
- class Tool(BaseModel):
36
+ class Tool(FastMCPBaseModel, ABC):
35
37
  """Internal tool registration info."""
36
38
 
37
- fn: Callable[..., Any]
38
39
  name: str = Field(description="Name of the tool")
39
40
  description: str | None = Field(
40
41
  default=None, description="Description of what the tool does"
@@ -54,6 +55,53 @@ class Tool(BaseModel):
54
55
  None, description="Optional custom serializer for tool results"
55
56
  )
56
57
 
58
+ def to_mcp_tool(self, **overrides: Any) -> MCPTool:
59
+ kwargs = {
60
+ "name": self.name,
61
+ "description": self.description,
62
+ "inputSchema": self.parameters,
63
+ "annotations": self.annotations,
64
+ }
65
+ return MCPTool(**kwargs | overrides)
66
+
67
+ @staticmethod
68
+ def from_function(
69
+ fn: Callable[..., Any],
70
+ name: str | None = None,
71
+ description: str | None = None,
72
+ tags: set[str] | None = None,
73
+ annotations: ToolAnnotations | None = None,
74
+ exclude_args: list[str] | None = None,
75
+ serializer: Callable[[Any], str] | None = None,
76
+ ) -> FunctionTool:
77
+ """Create a Tool from a function."""
78
+ return FunctionTool.from_function(
79
+ fn=fn,
80
+ name=name,
81
+ description=description,
82
+ tags=tags,
83
+ annotations=annotations,
84
+ exclude_args=exclude_args,
85
+ serializer=serializer,
86
+ )
87
+
88
+ def __eq__(self, other: object) -> bool:
89
+ if type(self) is not type(other):
90
+ return False
91
+ assert isinstance(other, type(self))
92
+ return self.model_dump() == other.model_dump()
93
+
94
+ @abstractmethod
95
+ async def run(
96
+ self, arguments: dict[str, Any]
97
+ ) -> list[TextContent | ImageContent | EmbeddedResource]:
98
+ """Run the tool with arguments."""
99
+ raise NotImplementedError("Subclasses must implement run()")
100
+
101
+
102
+ class FunctionTool(Tool):
103
+ fn: Callable[..., Any]
104
+
57
105
  @classmethod
58
106
  def from_function(
59
107
  cls,
@@ -64,7 +112,7 @@ class Tool(BaseModel):
64
112
  annotations: ToolAnnotations | None = None,
65
113
  exclude_args: list[str] | None = None,
66
114
  serializer: Callable[[Any], str] | None = None,
67
- ) -> Tool:
115
+ ) -> FunctionTool:
68
116
  """Create a Tool from a function."""
69
117
  from fastmcp.server.context import Context
70
118
 
@@ -98,6 +146,9 @@ class Tool(BaseModel):
98
146
  # if the fn is a callable class, we need to get the __call__ method from here out
99
147
  if not inspect.isroutine(fn):
100
148
  fn = fn.__call__
149
+ # if the fn is a staticmethod, we need to work with the underlying function
150
+ if isinstance(fn, staticmethod):
151
+ fn = fn.__func__
101
152
 
102
153
  type_adapter = get_cached_typeadapter(fn)
103
154
  schema = type_adapter.json_schema()
@@ -170,20 +221,6 @@ class Tool(BaseModel):
170
221
 
171
222
  return _convert_to_content(result, serializer=self.serializer)
172
223
 
173
- def to_mcp_tool(self, **overrides: Any) -> MCPTool:
174
- kwargs = {
175
- "name": self.name,
176
- "description": self.description,
177
- "inputSchema": self.parameters,
178
- "annotations": self.annotations,
179
- }
180
- return MCPTool(**kwargs | overrides)
181
-
182
- def __eq__(self, other: object) -> bool:
183
- if not isinstance(other, Tool):
184
- return False
185
- return self.model_dump() == other.model_dump()
186
-
187
224
 
188
225
  def _convert_to_content(
189
226
  result: Any,
@@ -215,9 +252,12 @@ def _convert_to_content(
215
252
  mcp_types.append(_convert_to_content(item)[0])
216
253
  else:
217
254
  other_content.append(item)
255
+
218
256
  if other_content:
219
257
  other_content = _convert_to_content(
220
- other_content, serializer=serializer, _process_as_single_item=True
258
+ other_content[0] if len(other_content) == 1 else other_content,
259
+ serializer=serializer,
260
+ _process_as_single_item=True,
221
261
  )
222
262
 
223
263
  return other_content + mcp_types
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations as _annotations
2
2
 
3
+ import warnings
3
4
  from collections.abc import Callable
4
5
  from typing import TYPE_CHECKING, Any
5
6
 
@@ -22,11 +23,9 @@ class ToolManager:
22
23
  def __init__(
23
24
  self,
24
25
  duplicate_behavior: DuplicateBehavior | None = None,
25
- serializer: Callable[[Any], str] | None = None,
26
26
  mask_error_details: bool = False,
27
27
  ):
28
28
  self._tools: dict[str, Tool] = {}
29
- self._serializer = serializer
30
29
  self.mask_error_details = mask_error_details
31
30
 
32
31
  # Default to "warn" if None is provided
@@ -66,17 +65,24 @@ class ToolManager:
66
65
  description: str | None = None,
67
66
  tags: set[str] | None = None,
68
67
  annotations: ToolAnnotations | None = None,
68
+ serializer: Callable[[Any], str] | None = None,
69
69
  exclude_args: list[str] | None = None,
70
70
  ) -> Tool:
71
71
  """Add a tool to the server."""
72
+ # deprecated in 2.7.0
73
+ warnings.warn(
74
+ "ToolManager.add_tool_from_fn() is deprecated. Use Tool.from_function() and call add_tool() instead.",
75
+ DeprecationWarning,
76
+ stacklevel=2,
77
+ )
72
78
  tool = Tool.from_function(
73
79
  fn,
74
80
  name=name,
75
81
  description=description,
76
82
  tags=tags,
77
83
  annotations=annotations,
78
- serializer=self._serializer,
79
84
  exclude_args=exclude_args,
85
+ serializer=serializer,
80
86
  )
81
87
  return self.add_tool(tool)
82
88
 
@@ -3,7 +3,9 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Any, Literal
4
4
  from urllib.parse import urlparse
5
5
 
6
- from pydantic import AnyUrl, BaseModel, Field
6
+ from pydantic import AnyUrl, Field
7
+
8
+ from fastmcp.utilities.types import FastMCPBaseModel
7
9
 
8
10
  if TYPE_CHECKING:
9
11
  from fastmcp.client.transports import (
@@ -32,7 +34,7 @@ def infer_transport_type_from_url(
32
34
  return "streamable-http"
33
35
 
34
36
 
35
- class StdioMCPServer(BaseModel):
37
+ class StdioMCPServer(FastMCPBaseModel):
36
38
  command: str
37
39
  args: list[str] = Field(default_factory=list)
38
40
  env: dict[str, Any] = Field(default_factory=dict)
@@ -50,7 +52,7 @@ class StdioMCPServer(BaseModel):
50
52
  )
51
53
 
52
54
 
53
- class RemoteMCPServer(BaseModel):
55
+ class RemoteMCPServer(FastMCPBaseModel):
54
56
  url: str
55
57
  headers: dict[str, str] = Field(default_factory=dict)
56
58
  transport: Literal["streamable-http", "sse", "http"] | None = None
@@ -69,7 +71,7 @@ class RemoteMCPServer(BaseModel):
69
71
  return StreamableHttpTransport(self.url, headers=self.headers)
70
72
 
71
73
 
72
- class MCPConfig(BaseModel):
74
+ class MCPConfig(FastMCPBaseModel):
73
75
  mcpServers: dict[str, StdioMCPServer | RemoteMCPServer]
74
76
 
75
77
  @classmethod
@@ -25,6 +25,7 @@ from openapi_pydantic.v3.v3_0 import Schema as Schema_30
25
25
  from pydantic import BaseModel, Field, ValidationError
26
26
 
27
27
  from fastmcp.utilities.json_schema import compress_schema
28
+ from fastmcp.utilities.types import FastMCPBaseModel
28
29
 
29
30
  logger = logging.getLogger(__name__)
30
31
 
@@ -38,7 +39,7 @@ ParameterLocation = Literal["path", "query", "header", "cookie"]
38
39
  JsonSchema = dict[str, Any]
39
40
 
40
41
 
41
- class ParameterInfo(BaseModel):
42
+ class ParameterInfo(FastMCPBaseModel):
42
43
  """Represents a single parameter for an HTTP operation in our IR."""
43
44
 
44
45
  name: str
@@ -48,7 +49,7 @@ class ParameterInfo(BaseModel):
48
49
  description: str | None = None
49
50
 
50
51
 
51
- class RequestBodyInfo(BaseModel):
52
+ class RequestBodyInfo(FastMCPBaseModel):
52
53
  """Represents the request body for an HTTP operation in our IR."""
53
54
 
54
55
  required: bool = False
@@ -58,7 +59,7 @@ class RequestBodyInfo(BaseModel):
58
59
  description: str | None = None
59
60
 
60
61
 
61
- class ResponseInfo(BaseModel):
62
+ class ResponseInfo(FastMCPBaseModel):
62
63
  """Represents response information in our IR."""
63
64
 
64
65
  description: str | None = None
@@ -66,7 +67,7 @@ class ResponseInfo(BaseModel):
66
67
  content_schema: dict[str, JsonSchema] = Field(default_factory=dict)
67
68
 
68
69
 
69
- class HTTPRoute(BaseModel):
70
+ class HTTPRoute(FastMCPBaseModel):
70
71
  """Intermediate Representation for a single OpenAPI operation."""
71
72
 
72
73
  path: str
@@ -872,6 +873,50 @@ def format_description_with_responses(
872
873
  return "\n".join(desc_parts)
873
874
 
874
875
 
876
+ def _replace_ref_with_defs(
877
+ info: dict[str, Any], description: str | None = None
878
+ ) -> dict[str, Any]:
879
+ """
880
+ Replace openapi $ref with jsonschema $defs
881
+
882
+ Examples:
883
+ - {"type": "object", "properties": {"$ref": "#/components/schemas/..."}}
884
+ - {"$ref": "#/components/schemas/..."}
885
+ - {"items": {"$ref": "#/components/schemas/..."}}
886
+ - {"anyOf": [{"$ref": "#/components/schemas/..."}]}
887
+ - {"allOf": [{"$ref": "#/components/schemas/..."}]}
888
+ - {"oneOf": [{"$ref": "#/components/schemas/..."}]}
889
+
890
+ Args:
891
+ info: dict[str, Any]
892
+ description: str | None
893
+
894
+ Returns:
895
+ dict[str, Any]
896
+ """
897
+ schema = info.copy()
898
+ if ref_path := schema.get("$ref"):
899
+ if ref_path.startswith("#/components/schemas/"):
900
+ schema_name = ref_path.split("/")[-1]
901
+ schema["$ref"] = f"#/$defs/{schema_name}"
902
+ elif properties := schema.get("properties"):
903
+ if "$ref" in properties:
904
+ schema["properties"] = _replace_ref_with_defs(properties)
905
+ else:
906
+ schema["properties"] = {
907
+ prop_name: _replace_ref_with_defs(prop_schema)
908
+ for prop_name, prop_schema in properties.items()
909
+ }
910
+ elif item_schema := schema.get("items"):
911
+ schema["items"] = _replace_ref_with_defs(item_schema)
912
+ for section in ["anyOf", "allOf", "oneOf"]:
913
+ for i, item in enumerate(schema.get(section, [])):
914
+ schema[section][i] = _replace_ref_with_defs(item)
915
+ if info.get("description", description) and not schema.get("description"):
916
+ schema["description"] = description
917
+ return schema
918
+
919
+
875
920
  def _combine_schemas(route: HTTPRoute) -> dict[str, Any]:
876
921
  """
877
922
  Combines parameter and request body schemas into a single schema.
@@ -889,38 +934,18 @@ def _combine_schemas(route: HTTPRoute) -> dict[str, Any]:
889
934
  for param in route.parameters:
890
935
  if param.required:
891
936
  required.append(param.name)
892
-
893
- # Copy the schema and add description if available
894
- param_schema = param.schema_.copy() if isinstance(param.schema_, dict) else {}
895
-
896
- # Convert #/components/schemas references to #/$defs references
897
- if isinstance(param_schema, dict) and "$ref" in param_schema:
898
- ref_path = param_schema["$ref"]
899
- if ref_path.startswith("#/components/schemas/"):
900
- schema_name = ref_path.split("/")[-1]
901
- param_schema["$ref"] = f"#/$defs/{schema_name}"
902
-
903
- # Also handle anyOf, allOf, oneOf references
904
- for section in ["anyOf", "allOf", "oneOf"]:
905
- if section in param_schema and isinstance(param_schema[section], list):
906
- for i, item in enumerate(param_schema[section]):
907
- if isinstance(item, dict) and "$ref" in item:
908
- ref_path = item["$ref"]
909
- if ref_path.startswith("#/components/schemas/"):
910
- schema_name = ref_path.split("/")[-1]
911
- param_schema[section][i]["$ref"] = f"#/$defs/{schema_name}"
912
-
913
- # Add parameter description to schema if available and not already present
914
- if param.description and not param_schema.get("description"):
915
- param_schema["description"] = param.description
916
-
917
- properties[param.name] = param_schema
937
+ properties[param.name] = _replace_ref_with_defs(
938
+ param.schema_.copy(), param.description
939
+ )
918
940
 
919
941
  # Add request body if it exists
920
942
  if route.request_body and route.request_body.content_schema:
921
943
  # For now, just use the first content type's schema
922
944
  content_type = next(iter(route.request_body.content_schema))
923
- body_schema = route.request_body.content_schema[content_type]
945
+ body_schema = _replace_ref_with_defs(
946
+ route.request_body.content_schema[content_type].copy(),
947
+ route.request_body.description,
948
+ )
924
949
  body_props = body_schema.get("properties", {})
925
950
 
926
951
  # Add request body properties
@@ -935,7 +960,6 @@ def _combine_schemas(route: HTTPRoute) -> dict[str, Any]:
935
960
  "properties": properties,
936
961
  "required": required,
937
962
  }
938
-
939
963
  # Add schema definitions if available
940
964
  if route.schema_definitions:
941
965
  result["$defs"] = route.schema_definitions
@@ -9,11 +9,17 @@ from types import UnionType
9
9
  from typing import Annotated, TypeVar, Union, get_args, get_origin
10
10
 
11
11
  from mcp.types import ImageContent
12
- from pydantic import TypeAdapter
12
+ from pydantic import BaseModel, ConfigDict, TypeAdapter
13
13
 
14
14
  T = TypeVar("T")
15
15
 
16
16
 
17
+ class FastMCPBaseModel(BaseModel):
18
+ """Base model for FastMCP models."""
19
+
20
+ model_config = ConfigDict(extra="forbid")
21
+
22
+
17
23
  @lru_cache(maxsize=5000)
18
24
  def get_cached_typeadapter(cls: T) -> TypeAdapter[T]:
19
25
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastmcp
3
- Version: 2.6.0
3
+ Version: 2.7.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
@@ -25,7 +25,8 @@ Requires-Dist: openapi-pydantic>=0.5.1
25
25
  Requires-Dist: python-dotenv>=1.1.0
26
26
  Requires-Dist: rich>=13.9.4
27
27
  Requires-Dist: typer>=0.15.2
28
- Requires-Dist: websockets>=14.0
28
+ Provides-Extra: websockets
29
+ Requires-Dist: websockets>=15.0.1; extra == 'websockets'
29
30
  Description-Content-Type: text/markdown
30
31
 
31
32
  <div align="center">
@@ -61,7 +62,7 @@ from fastmcp import FastMCP
61
62
 
62
63
  mcp = FastMCP("Demo 🚀")
63
64
 
64
- @mcp.tool()
65
+ @mcp.tool
65
66
  def add(a: int, b: int) -> int:
66
67
  """Add two numbers"""
67
68
  return a + b
@@ -104,6 +105,7 @@ There are two ways to access the LLM-friendly documentation:
104
105
  - [Proxy Servers](#proxy-servers)
105
106
  - [Composing MCP Servers](#composing-mcp-servers)
106
107
  - [OpenAPI \& FastAPI Generation](#openapi--fastapi-generation)
108
+ - [Authentication \& Security](#authentication--security)
107
109
  - [Running Your Server](#running-your-server)
108
110
  - [Contributing](#contributing)
109
111
  - [Prerequisites](#prerequisites)
@@ -116,20 +118,20 @@ There are two ways to access the LLM-friendly documentation:
116
118
 
117
119
  ## What is MCP?
118
120
 
119
- The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
121
+ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. It is often described as "the USB-C port for AI", providing a uniform way to connect LLMs to resources they can use. It may be easier to think of it as an API, but specifically designed for LLM interactions. MCP servers can:
120
122
 
121
- - Expose data through **Resources** (similar to `GET` requests; load info into context)
122
- - Provide functionality through **Tools** (similar to `POST`/`PUT` requests; execute actions)
123
- - Define interaction patterns through **Prompts** (reusable templates)
123
+ - Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
124
+ - Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
125
+ - Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
124
126
  - And more!
125
127
 
126
- FastMCP provides a high-level, Pythonic interface for building and interacting with these servers.
128
+ FastMCP provides a high-level, Pythonic interface for building, managing, and interacting with these servers.
127
129
 
128
130
  ## Why FastMCP?
129
131
 
130
132
  The MCP protocol is powerful but implementing it involves a lot of boilerplate - server setup, protocol handlers, content types, error management. FastMCP handles all the complex protocol details and server management, so you can focus on building great tools. It's designed to be high-level and Pythonic; in most cases, decorating a function is all you need.
131
133
 
132
- While the core server concepts of FastMCP 1.0 laid the groundwork and were contributed to the official MCP SDK, **FastMCP 2.0 (this project) is the actively developed successor**, adding significant enhancements and entirely new capabilities like a powerful **client library**, server **proxying**, **composition** patterns, **OpenAPI/FastAPI integration**, and much more.
134
+ FastMCP 2.0 has evolved into a comprehensive platform that goes far beyond basic protocol implementation. While 1.0 provided server-building capabilities (and is now part of the official MCP SDK), 2.0 offers a complete ecosystem including client libraries, authentication systems, deployment tools, integrations with major AI platforms, testing frameworks, and production-ready infrastructure patterns.
133
135
 
134
136
  FastMCP aims to be:
135
137
 
@@ -139,7 +141,7 @@ FastMCP aims to be:
139
141
 
140
142
  🐍 **Pythonic:** Feels natural to Python developers
141
143
 
142
- 🔍 **Complete:** FastMCP aims to provide a full implementation of the core MCP specification for both servers and clients
144
+ 🔍 **Complete:** A comprehensive platform for all MCP use cases, from dev to prod
143
145
 
144
146
  ## Installation
145
147
 
@@ -157,7 +159,7 @@ These are the building blocks for creating MCP servers and clients with FastMCP.
157
159
 
158
160
  ### The `FastMCP` Server
159
161
 
160
- The central object representing your MCP application. It holds your tools, resources, and prompts, manages connections, and can be configured with settings like [authentication providers](https://gofastmcp.com/servers/fastmcp#authentication).
162
+ The central object representing your MCP application. It holds your tools, resources, and prompts, manages connections, and can be configured with settings like authentication.
161
163
 
162
164
  ```python
163
165
  from fastmcp import FastMCP
@@ -173,7 +175,7 @@ Learn more in the [**FastMCP Server Documentation**](https://gofastmcp.com/serve
173
175
  Tools allow LLMs to perform actions by executing your Python functions (sync or async). Ideal for computations, API calls, or side effects (like `POST`/`PUT`). FastMCP handles schema generation from type hints and docstrings. Tools can return various types, including text, JSON-serializable objects, and even images using the [`fastmcp.Image`](https://gofastmcp.com/servers/tools#return-values) helper.
174
176
 
175
177
  ```python
176
- @mcp.tool()
178
+ @mcp.tool
177
179
  def multiply(a: float, b: float) -> float:
178
180
  """Multiplies two numbers."""
179
181
  return a * b
@@ -202,10 +204,10 @@ Learn more in the [**Resources & Templates Documentation**](https://gofastmcp.co
202
204
 
203
205
  ### Prompts
204
206
 
205
- Prompts define reusable message templates to guide LLM interactions. Decorate functions with `@mcp.prompt()`. Return strings or `Message` objects.
207
+ Prompts define reusable message templates to guide LLM interactions. Decorate functions with `@mcp.prompt`. Return strings or `Message` objects.
206
208
 
207
209
  ```python
208
- @mcp.prompt()
210
+ @mcp.prompt
209
211
  def summarize_request(text: str) -> str:
210
212
  """Generate a prompt asking for a summary."""
211
213
  return f"Please summarize the following text:\n\n{text}"
@@ -230,7 +232,7 @@ from fastmcp import FastMCP, Context
230
232
 
231
233
  mcp = FastMCP("My MCP Server")
232
234
 
233
- @mcp.tool()
235
+ @mcp.tool
234
236
  async def process_data(uri: str, ctx: Context):
235
237
  # Log a message to the client
236
238
  await ctx.info(f"Processing {uri}...")
@@ -328,7 +330,17 @@ Learn more in the [**Composition Documentation**](https://gofastmcp.com/patterns
328
330
 
329
331
  Automatically generate FastMCP servers from existing OpenAPI specifications (`FastMCP.from_openapi()`) or FastAPI applications (`FastMCP.from_fastapi()`), instantly bringing your web APIs to the MCP ecosystem.
330
332
 
331
- Learn more: [**OpenAPI Integration**](https://gofastmcp.com/patterns/openapi) | [**FastAPI Integration**](https://gofastmcp.com/patterns/fastapi).
333
+ Learn more: [**OpenAPI Integration**](https://gofastmcp.com/servers/openapi#openapi-integration) | [**FastAPI Integration**](https://gofastmcp.com/deployment/asgi#fastapi-integration).
334
+
335
+ ### Authentication & Security
336
+
337
+ FastMCP provides built-in authentication support to secure both your MCP servers and clients in production environments. Protect your server endpoints from unauthorized access and authenticate your clients against secured MCP servers using industry-standard protocols.
338
+
339
+ - **Server Protection**: Secure your FastMCP server endpoints with configurable authentication providers
340
+ - **Client Authentication**: Connect to authenticated MCP servers with automatic credential management
341
+ - **Production Ready**: Support for common authentication patterns used in enterprise environments
342
+
343
+ Learn more in the **Authentication Documentation** for [servers](https://gofastmcp.com/servers/auth) and [clients](https://gofastmcp.com/clients/auth).
332
344
 
333
345
  ## Running Your Server
334
346
 
@@ -340,7 +352,7 @@ from fastmcp import FastMCP
340
352
 
341
353
  mcp = FastMCP("Demo 🚀")
342
354
 
343
- @mcp.tool()
355
+ @mcp.tool
344
356
  def hello(name: str) -> str:
345
357
  return f"Hello, {name}!"
346
358
 
@@ -1,10 +1,11 @@
1
1
  fastmcp/__init__.py,sha256=yTAqLZORsPqbr7AE0ayw6zIYBeMlxQlI-3HE2WqbvHk,435
2
2
  fastmcp/exceptions.py,sha256=YvaKqOT3w0boXF9ylIoaSIzW9XiQ1qLFG1LZq6B60H8,680
3
+ fastmcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
4
  fastmcp/settings.py,sha256=DbFdWx4EVHhJZF6e2GB0pBMCSjc425kXIVY8mqfOVX8,6175
4
5
  fastmcp/cli/__init__.py,sha256=Ii284TNoG5lxTP40ETMGhHEq3lQZWxu9m9JuU57kUpQ,87
5
6
  fastmcp/cli/claude.py,sha256=IAlcZ4qZKBBj09jZUMEx7EANZE_IR3vcu7zOBJmMOuU,4567
6
- fastmcp/cli/cli.py,sha256=CQxpRTXgnQQynGJLEV5g1FnLMaiWoiUgefnMZ7VxS4o,12367
7
- fastmcp/cli/run.py,sha256=o7Ge6JZKXYwlY2vYdMNoVX8agBchAaeU_73iPndojIM,5351
7
+ fastmcp/cli/cli.py,sha256=zoHJ8DjUBLISVb4VHaVP-fCJP4Y8zG6-UhhNqSvczqY,12667
8
+ fastmcp/cli/run.py,sha256=sGH7M3Yi8HGju4sPypKGk3P2cdZq1n3l-_CpJmdGvDc,6277
8
9
  fastmcp/client/__init__.py,sha256=kd2hhSuD8rZuF87c9zlPJP_icJ-Rx3exyNoK0EzfOtE,617
9
10
  fastmcp/client/client.py,sha256=vQk0l6htoD6CyO0le8q23iYd5hX1l8NIbxchedbWqgE,24872
10
11
  fastmcp/client/logging.py,sha256=hOPRailZUp89RUck6V4HPaWVZinVrNY8HD4hD0dd-fE,822
@@ -12,56 +13,55 @@ fastmcp/client/oauth_callback.py,sha256=ODAnVX-ettL82RuI5KpfkKf8iDtYMDue3Tnab5sj
12
13
  fastmcp/client/progress.py,sha256=WjLLDbUKMsx8DK-fqO7AGsXb83ak-6BMrLvzzznGmcI,1043
13
14
  fastmcp/client/roots.py,sha256=IxI_bHwHTmg6c2H-s1av1ZgrRnNDieHtYwdGFbzXT5c,2471
14
15
  fastmcp/client/sampling.py,sha256=UlDHxnd6k_HoU8RA3ob0g8-e6haJBc9u27N_v291QoI,1698
15
- fastmcp/client/transports.py,sha256=XBbw5nDzDQffeWmfDgWgXZUOX0hJqk3fdusnqqUge9c,31822
16
+ fastmcp/client/transports.py,sha256=Pi4g2B9lKbgvey-7lTLkjsSVxE2DoT2yMq82D7xktK0,32091
16
17
  fastmcp/client/auth/__init__.py,sha256=4DNsfp4iaQeBcpds0JDdMn6Mmfud44stWLsret0sVKY,91
17
18
  fastmcp/client/auth/bearer.py,sha256=MFEFqcH6u_V86msYiOsEFKN5ks1V9BnBNiPsPLHUTqo,399
18
- fastmcp/client/auth/oauth.py,sha256=qznXKVnoTHpmhUzRgIcQ-44l-_FMBZ4Vmn4wG5njXOM,14865
19
+ fastmcp/client/auth/oauth.py,sha256=LJHCB-34EC-sL9GC97XFQkyanK8Cc5skAp6GkH0tKzE,14709
19
20
  fastmcp/contrib/README.md,sha256=rKknYSI1T192UvSszqwwDlQ2eYQpxywrNTLoj177SYU,878
20
21
  fastmcp/contrib/bulk_tool_caller/README.md,sha256=5aUUY1TSFKtz1pvTLSDqkUCkGkuqMfMZNsLeaNqEgAc,1960
21
22
  fastmcp/contrib/bulk_tool_caller/__init__.py,sha256=xvGSSaUXTQrc31erBoi1Gh7BikgOliETDiYVTP3rLxY,75
22
23
  fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py,sha256=2NcrGS59qvHo1lfbRaT8NSWfCxN66knciLxFvnGwCLY,4165
23
- fastmcp/contrib/bulk_tool_caller/example.py,sha256=3RdsU2KrRwYZHEdVAmHOGJsO3ZJBxSaqz8BTznkPg7Y,321
24
+ fastmcp/contrib/bulk_tool_caller/example.py,sha256=6og_8pCJN_CabworC5R82zPAwwwM-W7HNJLQQSnS3lU,319
24
25
  fastmcp/contrib/mcp_mixin/README.md,sha256=9DDTJXWkA3yv1fp5V58gofmARPQ2xWDhblYGvUhKpDQ,1689
25
26
  fastmcp/contrib/mcp_mixin/__init__.py,sha256=aw9IQ1ssNjCgws4ZNt8bkdpossAAGVAwwjBpMp9O5ZQ,153
26
27
  fastmcp/contrib/mcp_mixin/example.py,sha256=GnunkXmtG5hLLTUsM8aW5ZURU52Z8vI4tNLl-fK7Dg0,1228
27
- fastmcp/contrib/mcp_mixin/mcp_mixin.py,sha256=cfIRbnSxsVzglTD-auyTE0izVQeHP7Oz18qzYoBZJgg,7899
28
+ fastmcp/contrib/mcp_mixin/mcp_mixin.py,sha256=3e0wHlKI9OF12t-SbpRTL-TWjBBLw7T8ATjCdoDtX6k,8173
28
29
  fastmcp/prompts/__init__.py,sha256=An8uMBUh9Hrb7qqcn_5_Hent7IOeSh7EA2IUVsIrtHc,179
29
- fastmcp/prompts/prompt.py,sha256=_bMuLMSnkH_vJpPcf_b8HOUnMOsQJXZdtjZBoebzNjI,8249
30
- fastmcp/prompts/prompt_manager.py,sha256=qptEhZHMwc8XxQd5lTQg8iIb5MiTZVsNaux_XLvQ0mw,3871
31
- fastmcp/resources/__init__.py,sha256=t0x1j8lc74rjUKtXe9H5Gs4fpQt82K4NgBK6Y7A0xTg,467
32
- fastmcp/resources/resource.py,sha256=Rx1My_fi1f-oqnQ9R_v7ejopAk4BJDfbB75-s4d31dM,2492
33
- fastmcp/resources/resource_manager.py,sha256=nsgCR3lo9t4Q0QR6txPfAas2upqIb8P8ZlqWAfV9Qc0,11344
34
- fastmcp/resources/template.py,sha256=u0_-yNMmZfnl5DqtSRndGbGBrm7JgbzBU8IUd0hrEWE,7523
35
- fastmcp/resources/types.py,sha256=5fUFvzRlekNjtfihtq8S-fT0alKoNfclzrugqeM5JRE,6366
30
+ fastmcp/prompts/prompt.py,sha256=FMvDO3491LJkdPSorKKwr_2KtDJx_C54iYDbGtBzH5M,9474
31
+ fastmcp/prompts/prompt_manager.py,sha256=zAxlMzNHt8z5tD6lHl60aETvCBq6FNfE_1I4p5juKRE,4161
32
+ fastmcp/resources/__init__.py,sha256=y1iAuqx-GIrS1NqIYzKezIDiYyjNEzzHD35epHpMnXE,463
33
+ fastmcp/resources/resource.py,sha256=pvyeuUJvBGyudvxEKiBsof8B5X1EfYpCNwC4wO3-rZA,5139
34
+ fastmcp/resources/resource_manager.py,sha256=AZO05oYJ6DmFst7hWedT6Jx7WfhISodw4K-HdQpY5iI,11761
35
+ fastmcp/resources/template.py,sha256=EDoPOMFRwCNHugEtmlcuTuWx2O1qe5_nUOLrGNYvsXM,8749
36
+ fastmcp/resources/types.py,sha256=SiYNLnpXT-mHgNUrzqKUvXYUsY-V3gwJIrYdJfFwDDo,4868
36
37
  fastmcp/server/__init__.py,sha256=bMD4aQD4yJqLz7-mudoNsyeV8UgQfRAg3PRwPvwTEds,119
37
- fastmcp/server/context.py,sha256=yN1e0LsnCl7cEpr9WlbvFhSf8oE56kKb-20m8h2SsBY,10171
38
+ fastmcp/server/context.py,sha256=7r-gxMiCgDpd9AStTk0hwfme540H7S1dEcU0bjoerxU,10169
38
39
  fastmcp/server/dependencies.py,sha256=DfN40fz4UkmdzvVg3QesuHKUVJ07iQU5ookkWawAoH4,2336
39
40
  fastmcp/server/http.py,sha256=RbUnqqKsiThOGZwJH-BIzC5_V1EXQh9tBlN4S-JJhbY,11624
40
- fastmcp/server/openapi.py,sha256=yYO-_9QQhi6IUGW-TsSHkhZFLll4wt5ysbtl0VHaHZM,39239
41
- fastmcp/server/proxy.py,sha256=mt3eM6TQWfnZD5XehmTXisskZ4CBbsWyjRPjprlTjBY,9653
42
- fastmcp/server/server.py,sha256=l1kD2MBTEiZTB6pYXBSB7T3cYMRe1Fk6tQvOhLJZQyM,58210
41
+ fastmcp/server/openapi.py,sha256=heLQA3B57nCOLNsbOYLVFbZGI8XQaVeXL6ST5L55vuo,38596
42
+ fastmcp/server/proxy.py,sha256=EVup0L4gGMnxkG2SJHE09ugKvfhPyJ_3AnkhAS-Dc3E,9562
43
+ fastmcp/server/server.py,sha256=pupGTlXcbindBILxYQoFYqQomQcDMK5QS04vTngYIdk,65399
43
44
  fastmcp/server/auth/__init__.py,sha256=doHCLwOIElvH1NrTdpeP9JKfnNf3MDYPSpQfdsQ-uI0,84
44
45
  fastmcp/server/auth/auth.py,sha256=kz02HGwXYU0N0clURZDjFNWdKSpTYmgmCnGJN-jSG3Y,1640
45
46
  fastmcp/server/auth/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
47
  fastmcp/server/auth/providers/bearer.py,sha256=3pTKL3tEU7FlCD5yI81LTa2n0dBsM7GRpIIn30WCWsA,12679
47
48
  fastmcp/server/auth/providers/bearer_env.py,sha256=MXsr4rjRm8DDmbdNd7IEXT6naCq48fkC1LlpoFAjt7c,1971
48
- fastmcp/server/auth/providers/in_memory.py,sha256=PmHc6qnnPB2DDY9ybokvp0JL536llwCTmcd1B7-RTpo,13909
49
- fastmcp/tools/__init__.py,sha256=ocw-SFTtN6vQ8fgnlF8iNAOflRmh79xS1xdO0Bc3QPE,96
50
- fastmcp/tools/tool.py,sha256=Lj0PZYNKbqZRBouqn17ayz2gDgU2-bEfHOC75r4GOB8,8687
51
- fastmcp/tools/tool_manager.py,sha256=HVT1-8Sdir5yY45oOUedMWnD8HJUkVkLUy0U-eAayoQ,4516
49
+ fastmcp/server/auth/providers/in_memory.py,sha256=sCRJambxXFZLg_EbJ5ma-aUZvtxuuKbGy7lTxIbzVb0,13772
50
+ fastmcp/tools/__init__.py,sha256=G-XFAr0RhVFj_crAZFaWZDUqcBPCTCyzAndpKXtpIFc,126
51
+ fastmcp/tools/tool.py,sha256=J5VDyQE85IyZPXEq8x0n1V2qdNJ5zVlgB7FkzxJwW9E,9994
52
+ fastmcp/tools/tool_manager.py,sha256=C3mB0lgQU-vmcrUltqck-Yx7zrnIHXthHijS-dJliU8,4724
52
53
  fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31
53
54
  fastmcp/utilities/cache.py,sha256=aV3oZ-ZhMgLSM9iAotlUlEy5jFvGXrVo0Y5Bj4PBtqY,707
54
- fastmcp/utilities/decorators.py,sha256=AjhjsetQZF4YOPV5MTZmIxO21iFp_4fDIS3O2_KNCEg,2990
55
55
  fastmcp/utilities/exceptions.py,sha256=Aax9K0larjzrrgJBS6o_PQwoIrvBvVwck2suZvgafXE,1359
56
56
  fastmcp/utilities/http.py,sha256=1ns1ymBS-WSxbZjGP6JYjSO52Wa_ls4j4WbnXiupoa4,245
57
57
  fastmcp/utilities/json_schema.py,sha256=m65XU9lPq7pCxJ9vvCeGRl0HOFr6ArezvYpMBR6-gAg,3777
58
58
  fastmcp/utilities/logging.py,sha256=B1WNO-ZWFjd9wiFSh13YtW1hAKaNmbpscDZleIAhr-g,1317
59
- fastmcp/utilities/mcp_config.py,sha256=_wY3peaFDEgyOBkJ_Tb8sETk3mtdwtw1053q7ry0za0,2169
60
- fastmcp/utilities/openapi.py,sha256=QQos4vP59HQ8vPDTKftWOIVv_zmW30mNxYSXVU7JUbY,38441
59
+ fastmcp/utilities/mcp_config.py,sha256=Htux1dKyDaeK6-gT_fZwpJ_yj0MxUjGfPFAY3Dnnxsk,2233
60
+ fastmcp/utilities/openapi.py,sha256=ctceiGb4jYgzZGSseMb-yZccEEXf41P-dhB3ae9lGdk,38992
61
61
  fastmcp/utilities/tests.py,sha256=4Vuua6nVgbE5uQspEK0fk4tBuJ0rO4GTBmnyD0kXJPA,3930
62
- fastmcp/utilities/types.py,sha256=6CcqAQ1QqCO2HGSFlPS6FO5JRWnacjCcO2-EhyEnZV0,4400
63
- fastmcp-2.6.0.dist-info/METADATA,sha256=vKeS0OYYNKKjJLcXi6jLtnb9TIsBo9niw38QTfwruxg,16605
64
- fastmcp-2.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
65
- fastmcp-2.6.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
66
- fastmcp-2.6.0.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
67
- fastmcp-2.6.0.dist-info/RECORD,,
62
+ fastmcp/utilities/types.py,sha256=HX1y4JrDC3sZA2ENRqsyxMyLQepr5-JiS9StXhIX8TE,4548
63
+ fastmcp-2.7.0.dist-info/METADATA,sha256=kXjE9Y1-qt0-OP2PVR2b1Gjdp6QKb68olWBNxM5xQmc,17687
64
+ fastmcp-2.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
65
+ fastmcp-2.7.0.dist-info/entry_points.txt,sha256=ff8bMtKX1JvXyurMibAacMSKbJEPmac9ffAKU9mLnM8,44
66
+ fastmcp-2.7.0.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
67
+ fastmcp-2.7.0.dist-info/RECORD,,