fastmcp 2.12.3__py3-none-any.whl → 2.12.5__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 (34) hide show
  1. fastmcp/cli/install/gemini_cli.py +0 -1
  2. fastmcp/cli/run.py +2 -2
  3. fastmcp/client/auth/oauth.py +49 -36
  4. fastmcp/client/client.py +12 -2
  5. fastmcp/contrib/mcp_mixin/README.md +2 -2
  6. fastmcp/experimental/utilities/openapi/schemas.py +31 -5
  7. fastmcp/server/auth/auth.py +3 -3
  8. fastmcp/server/auth/oauth_proxy.py +42 -12
  9. fastmcp/server/auth/oidc_proxy.py +348 -0
  10. fastmcp/server/auth/providers/auth0.py +174 -0
  11. fastmcp/server/auth/providers/aws.py +237 -0
  12. fastmcp/server/auth/providers/azure.py +6 -2
  13. fastmcp/server/auth/providers/descope.py +172 -0
  14. fastmcp/server/auth/providers/github.py +6 -2
  15. fastmcp/server/auth/providers/google.py +6 -2
  16. fastmcp/server/auth/providers/workos.py +6 -2
  17. fastmcp/server/context.py +7 -6
  18. fastmcp/server/http.py +1 -1
  19. fastmcp/server/middleware/logging.py +147 -116
  20. fastmcp/server/middleware/middleware.py +3 -2
  21. fastmcp/server/openapi.py +5 -1
  22. fastmcp/server/server.py +36 -31
  23. fastmcp/settings.py +27 -5
  24. fastmcp/tools/tool.py +4 -2
  25. fastmcp/utilities/json_schema.py +18 -1
  26. fastmcp/utilities/logging.py +66 -4
  27. fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +2 -1
  28. fastmcp/utilities/storage.py +204 -0
  29. fastmcp/utilities/tests.py +8 -6
  30. {fastmcp-2.12.3.dist-info → fastmcp-2.12.5.dist-info}/METADATA +121 -48
  31. {fastmcp-2.12.3.dist-info → fastmcp-2.12.5.dist-info}/RECORD +34 -29
  32. {fastmcp-2.12.3.dist-info → fastmcp-2.12.5.dist-info}/WHEEL +0 -0
  33. {fastmcp-2.12.3.dist-info → fastmcp-2.12.5.dist-info}/entry_points.txt +0 -0
  34. {fastmcp-2.12.3.dist-info → fastmcp-2.12.5.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,14 @@
1
1
  """Logging utilities for FastMCP."""
2
2
 
3
+ import contextlib
3
4
  import logging
4
- from typing import Any, Literal
5
+ from typing import Any, Literal, cast
5
6
 
6
7
  from rich.console import Console
7
8
  from rich.logging import RichHandler
8
9
 
10
+ import fastmcp
11
+
9
12
 
10
13
  def get_logger(name: str) -> logging.Logger:
11
14
  """Get a logger nested under FastMCP namespace.
@@ -16,13 +19,13 @@ def get_logger(name: str) -> logging.Logger:
16
19
  Returns:
17
20
  a configured logger instance
18
21
  """
19
- return logging.getLogger(f"FastMCP.{name}")
22
+ return logging.getLogger(f"fastmcp.{name}")
20
23
 
21
24
 
22
25
  def configure_logging(
23
26
  level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | int = "INFO",
24
27
  logger: logging.Logger | None = None,
25
- enable_rich_tracebacks: bool = True,
28
+ enable_rich_tracebacks: bool | None = None,
26
29
  **rich_kwargs: Any,
27
30
  ) -> None:
28
31
  """
@@ -33,9 +36,16 @@ def configure_logging(
33
36
  level: the log level to use
34
37
  rich_kwargs: the parameters to use for creating RichHandler
35
38
  """
39
+ # Check if logging is disabled in settings
40
+ if not fastmcp.settings.log_enabled:
41
+ return
42
+
43
+ # Use settings default if not specified
44
+ if enable_rich_tracebacks is None:
45
+ enable_rich_tracebacks = fastmcp.settings.enable_rich_tracebacks
36
46
 
37
47
  if logger is None:
38
- logger = logging.getLogger("FastMCP")
48
+ logger = logging.getLogger("fastmcp")
39
49
 
40
50
  # Only configure the FastMCP logger namespace
41
51
  handler = RichHandler(
@@ -56,3 +66,55 @@ def configure_logging(
56
66
 
57
67
  # Don't propagate to the root logger
58
68
  logger.propagate = False
69
+
70
+
71
+ @contextlib.contextmanager
72
+ def temporary_log_level(
73
+ level: str | None,
74
+ logger: logging.Logger | None = None,
75
+ enable_rich_tracebacks: bool | None = None,
76
+ **rich_kwargs: Any,
77
+ ):
78
+ """Context manager to temporarily set log level and restore it afterwards.
79
+
80
+ Args:
81
+ level: The temporary log level to set (e.g., "DEBUG", "INFO")
82
+ logger: Optional logger to configure (defaults to FastMCP logger)
83
+ enable_rich_tracebacks: Whether to enable rich tracebacks
84
+ **rich_kwargs: Additional parameters for RichHandler
85
+
86
+ Usage:
87
+ with temporary_log_level("DEBUG"):
88
+ # Code that runs with DEBUG logging
89
+ pass
90
+ # Original log level is restored here
91
+ """
92
+ if level:
93
+ # Get the original log level from settings
94
+ original_level = fastmcp.settings.log_level
95
+
96
+ # Configure with new level
97
+ # Cast to proper type for type checker
98
+ log_level_literal = cast(
99
+ Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
100
+ level.upper(),
101
+ )
102
+ configure_logging(
103
+ level=log_level_literal,
104
+ logger=logger,
105
+ enable_rich_tracebacks=enable_rich_tracebacks,
106
+ **rich_kwargs,
107
+ )
108
+ try:
109
+ yield
110
+ finally:
111
+ # Restore original configuration using configure_logging
112
+ # This will respect the log_enabled setting
113
+ configure_logging(
114
+ level=original_level,
115
+ logger=logger,
116
+ enable_rich_tracebacks=enable_rich_tracebacks,
117
+ **rich_kwargs,
118
+ )
119
+ else:
120
+ yield
@@ -403,7 +403,8 @@ class MCPServerConfig(BaseModel):
403
403
  run_args["port"] = self.deployment.port
404
404
  if self.deployment.path:
405
405
  run_args["path"] = self.deployment.path
406
- # Note: log_level not currently supported by run_async
406
+ if self.deployment.log_level:
407
+ run_args["log_level"] = self.deployment.log_level
407
408
 
408
409
  # Override with any provided kwargs
409
410
  run_args.update(kwargs)
@@ -0,0 +1,204 @@
1
+ """Key-value storage utilities for persistent data management."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any, Protocol
8
+
9
+ import pydantic_core
10
+
11
+ from fastmcp.utilities.logging import get_logger
12
+
13
+ logger = get_logger(__name__)
14
+
15
+
16
+ class KVStorage(Protocol):
17
+ """Protocol for key-value storage of JSON data."""
18
+
19
+ async def get(self, key: str) -> dict[str, Any] | None:
20
+ """Get a JSON dict by key."""
21
+ ...
22
+
23
+ async def set(self, key: str, value: dict[str, Any]) -> None:
24
+ """Store a JSON dict by key."""
25
+ ...
26
+
27
+ async def delete(self, key: str) -> None:
28
+ """Delete a value by key."""
29
+ ...
30
+
31
+
32
+ class JSONFileStorage:
33
+ """File-based key-value storage for JSON data with automatic metadata tracking.
34
+
35
+ Each key-value pair is stored as a separate JSON file on disk.
36
+ Keys are sanitized to be filesystem-safe.
37
+
38
+ The storage automatically wraps all data with metadata:
39
+ - timestamp: Timestamp when the entry was last written
40
+
41
+ Args:
42
+ cache_dir: Directory for storing JSON files
43
+ """
44
+
45
+ def __init__(self, cache_dir: Path):
46
+ """Initialize JSON file storage."""
47
+ self.cache_dir = cache_dir
48
+ self.cache_dir.mkdir(exist_ok=True, parents=True)
49
+
50
+ def _get_safe_key(self, key: str) -> str:
51
+ """Convert key to filesystem-safe string."""
52
+ safe_key = key
53
+
54
+ # Replace problematic characters with underscores
55
+ for char in [".", "/", "\\", ":", "*", "?", '"', "<", ">", "|", " "]:
56
+ safe_key = safe_key.replace(char, "_")
57
+
58
+ # Compress multiple underscores into one
59
+ while "__" in safe_key:
60
+ safe_key = safe_key.replace("__", "_")
61
+
62
+ # Strip leading and trailing underscores
63
+ safe_key = safe_key.strip("_")
64
+
65
+ return safe_key
66
+
67
+ def _get_file_path(self, key: str) -> Path:
68
+ """Get the file path for a given key."""
69
+ safe_key = self._get_safe_key(key)
70
+ return self.cache_dir / f"{safe_key}.json"
71
+
72
+ async def get(self, key: str) -> dict[str, Any] | None:
73
+ """Get a JSON dict from storage by key.
74
+
75
+ Args:
76
+ key: The key to retrieve
77
+
78
+ Returns:
79
+ The stored dict or None if not found
80
+ """
81
+ path = self._get_file_path(key)
82
+ try:
83
+ wrapper = json.loads(path.read_text())
84
+
85
+ # Expect wrapped format with metadata
86
+ if not isinstance(wrapper, dict) or "data" not in wrapper:
87
+ logger.warning(f"Invalid storage format for key '{key}'")
88
+ return None
89
+
90
+ logger.debug(f"Loaded data for key '{key}'")
91
+ return wrapper["data"]
92
+
93
+ except FileNotFoundError:
94
+ logger.debug(f"No data found for key '{key}'")
95
+ return None
96
+ except json.JSONDecodeError as e:
97
+ logger.warning(f"Failed to load data for key '{key}': {e}")
98
+ return None
99
+
100
+ async def set(self, key: str, value: dict[str, Any]) -> None:
101
+ """Store a JSON dict with metadata.
102
+
103
+ Args:
104
+ key: The key to store under
105
+ value: The dict to store
106
+ """
107
+ import time
108
+
109
+ path = self._get_file_path(key)
110
+ current_time = time.time()
111
+
112
+ # Create wrapper with metadata
113
+ wrapper = {
114
+ "data": value,
115
+ "timestamp": current_time,
116
+ }
117
+
118
+ # Use pydantic_core for consistent JSON serialization
119
+ json_data = pydantic_core.to_json(wrapper, fallback=str)
120
+ path.write_bytes(json_data)
121
+ logger.debug(f"Saved data for key '{key}'")
122
+
123
+ async def delete(self, key: str) -> None:
124
+ """Delete a value from storage.
125
+
126
+ Args:
127
+ key: The key to delete
128
+ """
129
+ path = self._get_file_path(key)
130
+ if path.exists():
131
+ path.unlink()
132
+ logger.debug(f"Deleted data for key '{key}'")
133
+
134
+ async def cleanup_old_entries(
135
+ self,
136
+ max_age_seconds: int = 30 * 24 * 60 * 60, # 30 days default
137
+ ) -> int:
138
+ """Remove entries older than the specified age.
139
+
140
+ Uses the timestamp field to determine age.
141
+
142
+ Args:
143
+ max_age_seconds: Maximum age in seconds (default 30 days)
144
+
145
+ Returns:
146
+ Number of entries removed
147
+ """
148
+ import time
149
+
150
+ current_time = time.time()
151
+ removed_count = 0
152
+
153
+ for json_file in self.cache_dir.glob("*.json"):
154
+ try:
155
+ # Read the file and check timestamp
156
+ wrapper = json.loads(json_file.read_text())
157
+
158
+ # Check wrapped format
159
+ if not isinstance(wrapper, dict) or "data" not in wrapper:
160
+ continue # Invalid format, skip
161
+
162
+ if "timestamp" not in wrapper:
163
+ continue # No timestamp field, skip
164
+
165
+ entry_age = current_time - wrapper["timestamp"]
166
+ if entry_age > max_age_seconds:
167
+ json_file.unlink()
168
+ removed_count += 1
169
+ logger.debug(
170
+ f"Removed old entry '{json_file.stem}' (age: {entry_age:.0f}s)"
171
+ )
172
+
173
+ except (json.JSONDecodeError, KeyError) as e:
174
+ logger.debug(f"Error reading {json_file.name}: {e}")
175
+ continue
176
+
177
+ if removed_count > 0:
178
+ logger.info(f"Cleaned up {removed_count} old entries from storage")
179
+
180
+ return removed_count
181
+
182
+
183
+ class InMemoryStorage:
184
+ """In-memory key-value storage for JSON data.
185
+
186
+ Simple dict-based storage that doesn't persist across restarts.
187
+ Useful for testing or environments where file storage isn't available.
188
+ """
189
+
190
+ def __init__(self):
191
+ """Initialize in-memory storage."""
192
+ self._data: dict[str, dict[str, Any]] = {}
193
+
194
+ async def get(self, key: str) -> dict[str, Any] | None:
195
+ """Get a JSON dict from memory by key."""
196
+ return self._data.get(key)
197
+
198
+ async def set(self, key: str, value: dict[str, Any]) -> None:
199
+ """Store a JSON dict in memory."""
200
+ self._data[key] = value
201
+
202
+ async def delete(self, key: str) -> None:
203
+ """Delete a value from memory."""
204
+ self._data.pop(key, None)
@@ -109,7 +109,7 @@ def run_server_in_process(
109
109
  proc.start()
110
110
 
111
111
  # Wait for server to be running
112
- max_attempts = 10
112
+ max_attempts = 30
113
113
  attempt = 0
114
114
  while attempt < max_attempts and proc.is_alive():
115
115
  try:
@@ -117,10 +117,12 @@ def run_server_in_process(
117
117
  s.connect((host, port))
118
118
  break
119
119
  except ConnectionRefusedError:
120
- if attempt < 3:
121
- time.sleep(0.01)
122
- else:
120
+ if attempt < 5:
121
+ time.sleep(0.05)
122
+ elif attempt < 15:
123
123
  time.sleep(0.1)
124
+ else:
125
+ time.sleep(0.2)
124
126
  attempt += 1
125
127
  else:
126
128
  raise RuntimeError(f"Server failed to start after {max_attempts} attempts")
@@ -141,10 +143,10 @@ def run_server_in_process(
141
143
  def caplog_for_fastmcp(caplog):
142
144
  """Context manager to capture logs from FastMCP loggers even when propagation is disabled."""
143
145
  caplog.clear()
144
- logger = logging.getLogger("FastMCP")
146
+ logger = logging.getLogger("fastmcp")
145
147
  logger.addHandler(caplog.handler)
146
148
  try:
147
- yield
149
+ yield caplog
148
150
  finally:
149
151
  logger.removeHandler(caplog.handler)
150
152
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastmcp
3
- Version: 2.12.3
3
+ Version: 2.12.5
4
4
  Summary: The fast, Pythonic way to build MCP servers and clients.
5
5
  Project-URL: Homepage, https://gofastmcp.com
6
6
  Project-URL: Repository, https://github.com/jlowin/fastmcp
@@ -21,7 +21,7 @@ Requires-Dist: authlib>=1.5.2
21
21
  Requires-Dist: cyclopts>=3.0.0
22
22
  Requires-Dist: exceptiongroup>=1.2.2
23
23
  Requires-Dist: httpx>=0.28.1
24
- Requires-Dist: mcp<2.0.0,>=1.12.4
24
+ Requires-Dist: mcp<1.17.0,>=1.12.4
25
25
  Requires-Dist: openapi-core>=0.19.5
26
26
  Requires-Dist: openapi-pydantic>=0.5.1
27
27
  Requires-Dist: pydantic[email]>=2.11.7
@@ -37,6 +37,13 @@ Description-Content-Type: text/markdown
37
37
  <div align="center">
38
38
 
39
39
  <!-- omit in toc -->
40
+
41
+ <picture>
42
+ <source width="550" media="(prefers-color-scheme: dark)" srcset="docs/assets/brand/wordmark-watercolor-waves-dark.png">
43
+ <source width="550" media="(prefers-color-scheme: light)" srcset="docs/assets/brand/wordmark-watercolor-waves.png">
44
+ <img width="550" alt="FastMCP Logo" src="docs/assets/brand/wordmark-watercolor-waves.png">
45
+ </picture>
46
+
40
47
  # FastMCP v2 🚀
41
48
 
42
49
  <strong>The fast, Pythonic way to build MCP servers and clients.</strong>
@@ -53,19 +60,19 @@ Description-Content-Type: text/markdown
53
60
 
54
61
  > [!Note]
55
62
  >
56
- > #### Beyond the Protocol
57
- >
58
- > FastMCP is the standard framework for working with the Model Context Protocol. FastMCP 1.0 was incorporated into the [official MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) in 2024.
63
+ > #### FastMCP 2.0: The Standard Framework
59
64
  >
60
- > This is FastMCP 2.0, the **actively maintained version** that provides a complete toolkit for working with the MCP ecosystem.
65
+ > FastMCP pioneered Python MCP development, and FastMCP 1.0 was incorporated into the [official MCP SDK](https://github.com/modelcontextprotocol/python-sdk) in 2024.
61
66
  >
62
- > FastMCP 2.0 has a comprehensive set of features that go far beyond the core MCP specification, all in service of providing **the simplest path to production**. These include deployment, auth, clients, server proxying and composition, generating servers from REST APIs, dynamic tool rewriting, built-in testing tools, integrations, and more.
67
+ > **This is FastMCP 2.0** the actively maintained, production-ready framework that extends far beyond basic protocol implementation. While the SDK provides core functionality, FastMCP 2.0 delivers everything needed for production: advanced MCP patterns (server composition, proxying, OpenAPI/FastAPI generation, tool transformation), enterprise auth (Google, GitHub, WorkOS, Azure, Auth0, and more), deployment tools, testing utilities, and comprehensive client libraries.
63
68
  >
64
- > Ready to upgrade or get started? Follow the [installation instructions](https://gofastmcp.com/getting-started/installation), which include steps for upgrading from the official MCP SDK.
69
+ > **For production MCP applications, install FastMCP:** `pip install fastmcp`
65
70
 
66
71
  ---
67
72
 
68
- The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) is a new, standardized way to provide context and tools to your LLMs, and FastMCP makes building MCP servers and clients simple and intuitive. Create tools, expose resources, define prompts, and connect components with clean, Pythonic code.
73
+ **FastMCP is the standard framework for building MCP applications**, providing the fastest path from idea to production.
74
+
75
+ The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) is a standardized way to provide context and tools to LLMs. FastMCP makes building production-ready MCP servers simple, with enterprise auth, deployment tools, and a complete ecosystem built in.
69
76
 
70
77
  ```python
71
78
  # server.py
@@ -104,28 +111,33 @@ There are two ways to access the LLM-friendly documentation:
104
111
  <!-- omit in toc -->
105
112
  ## Table of Contents
106
113
 
107
- - [What is MCP?](#what-is-mcp)
108
- - [Why FastMCP?](#why-fastmcp)
109
- - [Installation](#installation)
110
- - [Core Concepts](#core-concepts)
111
- - [The `FastMCP` Server](#the-fastmcp-server)
112
- - [Tools](#tools)
113
- - [Resources \& Templates](#resources--templates)
114
- - [Prompts](#prompts)
115
- - [Context](#context)
116
- - [MCP Clients](#mcp-clients)
117
- - [Advanced Features](#advanced-features)
118
- - [Proxy Servers](#proxy-servers)
119
- - [Composing MCP Servers](#composing-mcp-servers)
120
- - [OpenAPI \& FastAPI Generation](#openapi--fastapi-generation)
121
- - [Authentication \& Security](#authentication--security)
122
- - [Running Your Server](#running-your-server)
123
- - [Contributing](#contributing)
124
- - [Prerequisites](#prerequisites)
125
- - [Setup](#setup)
126
- - [Unit Tests](#unit-tests)
127
- - [Static Checks](#static-checks)
128
- - [Pull Requests](#pull-requests)
114
+ - [FastMCP v2 🚀](#fastmcp-v2-)
115
+ - [📚 Documentation](#-documentation)
116
+ - [What is MCP?](#what-is-mcp)
117
+ - [Why FastMCP?](#why-fastmcp)
118
+ - [Installation](#installation)
119
+ - [Core Concepts](#core-concepts)
120
+ - [The `FastMCP` Server](#the-fastmcp-server)
121
+ - [Tools](#tools)
122
+ - [Resources \& Templates](#resources--templates)
123
+ - [Prompts](#prompts)
124
+ - [Context](#context)
125
+ - [MCP Clients](#mcp-clients)
126
+ - [Authentication](#authentication)
127
+ - [Enterprise Authentication, Zero Configuration](#enterprise-authentication-zero-configuration)
128
+ - [Deployment](#deployment)
129
+ - [From Development to Production](#from-development-to-production)
130
+ - [Advanced Features](#advanced-features)
131
+ - [Proxy Servers](#proxy-servers)
132
+ - [Composing MCP Servers](#composing-mcp-servers)
133
+ - [OpenAPI \& FastAPI Generation](#openapi--fastapi-generation)
134
+ - [Running Your Server](#running-your-server)
135
+ - [Contributing](#contributing)
136
+ - [Prerequisites](#prerequisites)
137
+ - [Setup](#setup)
138
+ - [Unit Tests](#unit-tests)
139
+ - [Static Checks](#static-checks)
140
+ - [Pull Requests](#pull-requests)
129
141
 
130
142
  ---
131
143
 
@@ -142,11 +154,7 @@ FastMCP provides a high-level, Pythonic interface for building, managing, and in
142
154
 
143
155
  ## Why FastMCP?
144
156
 
145
- 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.
146
-
147
- 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.
148
-
149
- FastMCP aims to be:
157
+ FastMCP handles all the complex protocol details so you can focus on building. In most cases, decorating a Python function is all you need — FastMCP handles the rest.
150
158
 
151
159
  🚀 **Fast:** High-level interface means less code and faster development
152
160
 
@@ -154,7 +162,9 @@ FastMCP aims to be:
154
162
 
155
163
  🐍 **Pythonic:** Feels natural to Python developers
156
164
 
157
- 🔍 **Complete:** A comprehensive platform for all MCP use cases, from dev to prod
165
+ 🔍 **Complete:** Everything for production enterprise auth (Google, GitHub, Azure, Auth0, WorkOS), deployment tools, testing frameworks, client libraries, and more
166
+
167
+ FastMCP provides the shortest path from idea to production. Deploy locally, to the cloud with [FastMCP Cloud](https://fastmcp.cloud), or to your own infrastructure.
158
168
 
159
169
  ## Installation
160
170
 
@@ -324,9 +334,82 @@ async def main():
324
334
 
325
335
  Learn more in the [**Client Documentation**](https://gofastmcp.com/clients/client) and [**Transports Documentation**](https://gofastmcp.com/clients/transports).
326
336
 
337
+ ## Authentication
338
+
339
+ ### Enterprise Authentication, Zero Configuration
340
+
341
+ FastMCP provides comprehensive authentication support that sets it apart from basic MCP implementations. Secure your servers and authenticate your clients with the same enterprise-grade providers used by major corporations.
342
+
343
+ **Built-in OAuth Providers:**
344
+
345
+ - **Google**
346
+ - **GitHub**
347
+ - **Microsoft Azure**
348
+ - **Auth0**
349
+ - **WorkOS**
350
+ - **Descope**
351
+ - **JWT/Custom**
352
+ - **API Keys**
353
+
354
+ Protecting a server takes just two lines:
355
+
356
+ ```python
357
+ from fastmcp.server.auth import GoogleProvider
358
+
359
+ auth = GoogleProvider(client_id="...", client_secret="...", base_url="https://myserver.com")
360
+ mcp = FastMCP("Protected Server", auth=auth)
361
+ ```
362
+
363
+ Connecting to protected servers is even simpler:
364
+
365
+ ```python
366
+ async with Client("https://protected-server.com/mcp", auth="oauth") as client:
367
+ # Automatic browser-based OAuth flow
368
+ result = await client.call_tool("protected_tool")
369
+ ```
370
+
371
+ **Why FastMCP Auth Matters:**
372
+
373
+ - **Production-Ready:** Persistent storage, token refresh, comprehensive error handling
374
+ - **Zero-Config OAuth:** Just pass `auth="oauth"` for automatic setup
375
+ - **Enterprise Integration:** WorkOS SSO, Azure Active Directory, Auth0 tenants
376
+ - **Developer Experience:** Automatic browser launch, local callback server, environment variable support
377
+ - **Advanced Architecture:** Full OIDC support, Dynamic Client Registration (DCR), and unique OAuth proxy pattern that enables DCR with any provider
378
+
379
+ *Authentication this comprehensive is unique to FastMCP 2.0.*
380
+
381
+ Learn more in the **Authentication Documentation** for [servers](https://gofastmcp.com/servers/auth) and [clients](https://gofastmcp.com/clients/auth).
382
+
383
+ ## Deployment
384
+
385
+ ### From Development to Production
386
+
387
+ FastMCP supports every deployment scenario from local development to global scale:
388
+
389
+ **Development:** Run locally with a single command
390
+
391
+ ```bash
392
+ fastmcp run server.py
393
+ ```
394
+
395
+ **Production:** Deploy to [**FastMCP Cloud**](https://fastmcp.cloud) — Remote MCP that just works
396
+
397
+ - Instant HTTPS endpoints
398
+ - Built-in authentication
399
+ - Zero configuration
400
+ - Free for personal servers
401
+
402
+ **Self-Hosted:** Use HTTP or SSE transports for your own infrastructure
403
+
404
+ ```python
405
+ mcp.run(transport="http", host="0.0.0.0", port=8000)
406
+ ```
407
+
408
+ Learn more in the [**Deployment Documentation**](https://gofastmcp.com/deployment).
409
+
327
410
  ## Advanced Features
328
411
 
329
- FastMCP introduces powerful ways to structure and deploy your MCP applications.
412
+ FastMCP introduces powerful ways to structure and compose your MCP applications.
330
413
 
331
414
  ### Proxy Servers
332
415
 
@@ -346,16 +429,6 @@ Automatically generate FastMCP servers from existing OpenAPI specifications (`Fa
346
429
 
347
430
  Learn more: [**OpenAPI Integration**](https://gofastmcp.com/integrations/openapi) | [**FastAPI Integration**](https://gofastmcp.com/integrations/fastapi).
348
431
 
349
- ### Authentication & Security
350
-
351
- 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.
352
-
353
- - **Server Protection**: Secure your FastMCP server endpoints with configurable authentication providers
354
- - **Client Authentication**: Connect to authenticated MCP servers with automatic credential management
355
- - **Production Ready**: Support for common authentication patterns used in enterprise environments
356
-
357
- Learn more in the **Authentication Documentation** for [servers](https://gofastmcp.com/servers/auth) and [clients](https://gofastmcp.com/clients/auth).
358
-
359
432
  ## Running Your Server
360
433
 
361
434
  The main way to run a FastMCP server is by calling the `run()` method on your server instance: