fastmcp 2.11.3__py3-none-any.whl → 2.12.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/__init__.py +5 -4
- fastmcp/cli/claude.py +22 -18
- fastmcp/cli/cli.py +472 -136
- fastmcp/cli/install/claude_code.py +37 -40
- fastmcp/cli/install/claude_desktop.py +37 -42
- fastmcp/cli/install/cursor.py +148 -38
- fastmcp/cli/install/mcp_json.py +38 -43
- fastmcp/cli/install/shared.py +64 -7
- fastmcp/cli/run.py +122 -215
- fastmcp/client/auth/oauth.py +69 -13
- fastmcp/client/client.py +46 -9
- fastmcp/client/oauth_callback.py +91 -91
- fastmcp/client/sampling.py +12 -4
- fastmcp/client/transports.py +139 -64
- fastmcp/experimental/sampling/__init__.py +0 -0
- fastmcp/experimental/sampling/handlers/__init__.py +3 -0
- fastmcp/experimental/sampling/handlers/base.py +21 -0
- fastmcp/experimental/sampling/handlers/openai.py +163 -0
- fastmcp/experimental/server/openapi/routing.py +0 -2
- fastmcp/experimental/server/openapi/server.py +0 -2
- fastmcp/experimental/utilities/openapi/parser.py +5 -1
- fastmcp/mcp_config.py +40 -20
- fastmcp/prompts/prompt_manager.py +2 -0
- fastmcp/resources/resource_manager.py +4 -0
- fastmcp/server/auth/__init__.py +2 -0
- fastmcp/server/auth/auth.py +2 -1
- fastmcp/server/auth/oauth_proxy.py +1047 -0
- fastmcp/server/auth/providers/azure.py +270 -0
- fastmcp/server/auth/providers/github.py +287 -0
- fastmcp/server/auth/providers/google.py +305 -0
- fastmcp/server/auth/providers/jwt.py +24 -12
- fastmcp/server/auth/providers/workos.py +256 -2
- fastmcp/server/auth/redirect_validation.py +65 -0
- fastmcp/server/context.py +91 -41
- fastmcp/server/elicitation.py +60 -1
- fastmcp/server/http.py +3 -3
- fastmcp/server/middleware/logging.py +66 -28
- fastmcp/server/proxy.py +2 -0
- fastmcp/server/sampling/handler.py +19 -0
- fastmcp/server/server.py +76 -15
- fastmcp/settings.py +16 -1
- fastmcp/tools/tool.py +22 -9
- fastmcp/tools/tool_manager.py +2 -0
- fastmcp/tools/tool_transform.py +39 -10
- fastmcp/utilities/auth.py +34 -0
- fastmcp/utilities/cli.py +148 -15
- fastmcp/utilities/components.py +2 -1
- fastmcp/utilities/inspect.py +166 -37
- fastmcp/utilities/json_schema_type.py +4 -2
- fastmcp/utilities/logging.py +4 -1
- fastmcp/utilities/mcp_config.py +47 -18
- fastmcp/utilities/mcp_server_config/__init__.py +25 -0
- fastmcp/utilities/mcp_server_config/v1/__init__.py +0 -0
- fastmcp/utilities/mcp_server_config/v1/environments/__init__.py +6 -0
- fastmcp/utilities/mcp_server_config/v1/environments/base.py +30 -0
- fastmcp/utilities/mcp_server_config/v1/environments/uv.py +306 -0
- fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +446 -0
- fastmcp/utilities/mcp_server_config/v1/schema.json +361 -0
- fastmcp/utilities/mcp_server_config/v1/sources/__init__.py +0 -0
- fastmcp/utilities/mcp_server_config/v1/sources/base.py +30 -0
- fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py +216 -0
- fastmcp/utilities/tests.py +7 -2
- fastmcp/utilities/types.py +15 -2
- {fastmcp-2.11.3.dist-info → fastmcp-2.12.0.dist-info}/METADATA +2 -1
- fastmcp-2.12.0.dist-info/RECORD +129 -0
- fastmcp-2.11.3.dist-info/RECORD +0 -108
- {fastmcp-2.11.3.dist-info → fastmcp-2.12.0.dist-info}/WHEEL +0 -0
- {fastmcp-2.11.3.dist-info → fastmcp-2.12.0.dist-info}/entry_points.txt +0 -0
- {fastmcp-2.11.3.dist-info → fastmcp-2.12.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
"""FastMCP Configuration File Support.
|
|
2
|
+
|
|
3
|
+
This module provides support for fastmcp.json configuration files that allow
|
|
4
|
+
users to specify server settings in a declarative format instead of using
|
|
5
|
+
command-line arguments.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import TYPE_CHECKING, Any, Literal, TypeAlias, cast, overload
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel, Field, field_validator
|
|
17
|
+
|
|
18
|
+
from fastmcp.utilities.logging import get_logger
|
|
19
|
+
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment
|
|
20
|
+
from fastmcp.utilities.mcp_server_config.v1.sources.base import Source
|
|
21
|
+
from fastmcp.utilities.mcp_server_config.v1.sources.filesystem import FileSystemSource
|
|
22
|
+
|
|
23
|
+
logger = get_logger("cli.config")
|
|
24
|
+
|
|
25
|
+
# JSON Schema for IDE support
|
|
26
|
+
FASTMCP_JSON_SCHEMA = "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Type alias for source union (will expand with GitSource, etc in future)
|
|
30
|
+
SourceType: TypeAlias = FileSystemSource
|
|
31
|
+
|
|
32
|
+
# Type alias for environment union (will expand with other environments in future)
|
|
33
|
+
EnvironmentType: TypeAlias = UVEnvironment
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Deployment(BaseModel):
|
|
37
|
+
"""Configuration for server deployment and runtime settings."""
|
|
38
|
+
|
|
39
|
+
transport: Literal["stdio", "http", "sse"] | None = Field(
|
|
40
|
+
default=None,
|
|
41
|
+
description="Transport protocol to use",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
host: str | None = Field(
|
|
45
|
+
default=None,
|
|
46
|
+
description="Host to bind to when using HTTP transport",
|
|
47
|
+
examples=["127.0.0.1", "0.0.0.0", "localhost"],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
port: int | None = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description="Port to bind to when using HTTP transport",
|
|
53
|
+
examples=[8000, 3000, 5000],
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
path: str | None = Field(
|
|
57
|
+
default=None,
|
|
58
|
+
description="URL path for the server endpoint",
|
|
59
|
+
examples=["/mcp/", "/api/mcp/", "/sse/"],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = Field(
|
|
63
|
+
default=None,
|
|
64
|
+
description="Log level for the server",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
cwd: str | None = Field(
|
|
68
|
+
default=None,
|
|
69
|
+
description="Working directory for the server process",
|
|
70
|
+
examples=[".", "./src", "/app"],
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
env: dict[str, str] | None = Field(
|
|
74
|
+
default=None,
|
|
75
|
+
description="Environment variables to set when running the server",
|
|
76
|
+
examples=[{"API_KEY": "secret", "DEBUG": "true"}],
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
args: list[str] | None = Field(
|
|
80
|
+
default=None,
|
|
81
|
+
description="Arguments to pass to the server (after --)",
|
|
82
|
+
examples=[["--config", "config.json", "--debug"]],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def apply_runtime_settings(self, config_path: Path | None = None) -> None:
|
|
86
|
+
"""Apply runtime settings like environment variables and working directory.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
config_path: Path to config file for resolving relative paths
|
|
90
|
+
|
|
91
|
+
Environment variables support interpolation with ${VAR_NAME} syntax.
|
|
92
|
+
For example: "API_URL": "https://api.${ENVIRONMENT}.example.com"
|
|
93
|
+
will substitute the value of the ENVIRONMENT variable at runtime.
|
|
94
|
+
"""
|
|
95
|
+
import os
|
|
96
|
+
from pathlib import Path
|
|
97
|
+
|
|
98
|
+
# Set environment variables with interpolation support
|
|
99
|
+
if self.env:
|
|
100
|
+
for key, value in self.env.items():
|
|
101
|
+
# Interpolate environment variables in the value
|
|
102
|
+
interpolated_value = self._interpolate_env_vars(value)
|
|
103
|
+
os.environ[key] = interpolated_value
|
|
104
|
+
|
|
105
|
+
# Change working directory
|
|
106
|
+
if self.cwd:
|
|
107
|
+
cwd_path = Path(self.cwd)
|
|
108
|
+
if not cwd_path.is_absolute() and config_path:
|
|
109
|
+
cwd_path = (config_path.parent / cwd_path).resolve()
|
|
110
|
+
os.chdir(cwd_path)
|
|
111
|
+
|
|
112
|
+
def _interpolate_env_vars(self, value: str) -> str:
|
|
113
|
+
"""Interpolate environment variables in a string.
|
|
114
|
+
|
|
115
|
+
Replaces ${VAR_NAME} with the value of VAR_NAME from the environment.
|
|
116
|
+
If the variable is not set, the placeholder is left unchanged.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
value: String potentially containing ${VAR_NAME} placeholders
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
String with environment variables interpolated
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def replace_var(match: re.Match) -> str:
|
|
126
|
+
var_name = match.group(1)
|
|
127
|
+
# Return the environment variable value if it exists, otherwise keep the placeholder
|
|
128
|
+
return os.environ.get(var_name, match.group(0))
|
|
129
|
+
|
|
130
|
+
# Match ${VAR_NAME} pattern and replace with environment variable values
|
|
131
|
+
return re.sub(r"\$\{([^}]+)\}", replace_var, value)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class MCPServerConfig(BaseModel):
|
|
135
|
+
"""Configuration for a FastMCP server.
|
|
136
|
+
|
|
137
|
+
This configuration file allows you to specify all settings needed to run
|
|
138
|
+
a FastMCP server in a declarative format.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
# Schema field for IDE support
|
|
142
|
+
schema_: str | None = Field(
|
|
143
|
+
default="https://gofastmcp.com/public/schemas/fastmcp.json/v1.json",
|
|
144
|
+
alias="$schema",
|
|
145
|
+
description="JSON schema for IDE support and validation",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Server source - defines where and how to load the server
|
|
149
|
+
source: SourceType = Field(
|
|
150
|
+
description="Source configuration for the server",
|
|
151
|
+
examples=[
|
|
152
|
+
{"path": "server.py"},
|
|
153
|
+
{"path": "server.py", "entrypoint": "app"},
|
|
154
|
+
{"type": "filesystem", "path": "src/server.py", "entrypoint": "mcp"},
|
|
155
|
+
],
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Environment configuration
|
|
159
|
+
environment: EnvironmentType = Field(
|
|
160
|
+
default_factory=lambda: UVEnvironment(),
|
|
161
|
+
description="Python environment setup configuration",
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Deployment configuration
|
|
165
|
+
deployment: Deployment = Field(
|
|
166
|
+
default_factory=lambda: Deployment(),
|
|
167
|
+
description="Server deployment and runtime settings",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# purely for static type checkers to avoid issues with providing dict source
|
|
171
|
+
if TYPE_CHECKING:
|
|
172
|
+
|
|
173
|
+
@overload
|
|
174
|
+
def __init__(self, *, source: dict | FileSystemSource, **data) -> None: ...
|
|
175
|
+
@overload
|
|
176
|
+
def __init__(self, *, environment: dict | UVEnvironment, **data) -> None: ...
|
|
177
|
+
@overload
|
|
178
|
+
def __init__(self, *, deployment: dict | Deployment, **data) -> None: ...
|
|
179
|
+
def __init__(self, **data) -> None: ...
|
|
180
|
+
|
|
181
|
+
@field_validator("source", mode="before")
|
|
182
|
+
@classmethod
|
|
183
|
+
def validate_source(cls, v: dict | Source) -> SourceType:
|
|
184
|
+
"""Validate and convert source to proper format.
|
|
185
|
+
|
|
186
|
+
Supports:
|
|
187
|
+
- Dict format: {"path": "server.py", "entrypoint": "app"}
|
|
188
|
+
- FileSystemSource instance (passed through)
|
|
189
|
+
|
|
190
|
+
No string parsing happens here - that's only at CLI boundaries.
|
|
191
|
+
MCPServerConfig works only with properly typed objects.
|
|
192
|
+
"""
|
|
193
|
+
if isinstance(v, dict):
|
|
194
|
+
return FileSystemSource(**v)
|
|
195
|
+
return v
|
|
196
|
+
|
|
197
|
+
@field_validator("environment", mode="before")
|
|
198
|
+
@classmethod
|
|
199
|
+
def validate_environment(cls, v: dict | Any) -> EnvironmentType:
|
|
200
|
+
"""Ensure environment has a type field for discrimination.
|
|
201
|
+
|
|
202
|
+
For backward compatibility, if no type is specified, default to "uv".
|
|
203
|
+
"""
|
|
204
|
+
if isinstance(v, dict):
|
|
205
|
+
return UVEnvironment(**v)
|
|
206
|
+
return v
|
|
207
|
+
|
|
208
|
+
@field_validator("deployment", mode="before")
|
|
209
|
+
@classmethod
|
|
210
|
+
def validate_deployment(cls, v: dict | Deployment) -> Deployment:
|
|
211
|
+
"""Validate and convert deployment to Deployment.
|
|
212
|
+
|
|
213
|
+
Accepts:
|
|
214
|
+
- Deployment instance
|
|
215
|
+
- dict that can be converted to Deployment
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
if isinstance(v, dict):
|
|
219
|
+
return Deployment(**v) # type: ignore[arg-type]
|
|
220
|
+
return cast(Deployment, v)
|
|
221
|
+
|
|
222
|
+
@classmethod
|
|
223
|
+
def from_file(cls, file_path: Path) -> MCPServerConfig:
|
|
224
|
+
"""Load configuration from a JSON file.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
file_path: Path to the configuration file
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
MCPServerConfig instance
|
|
231
|
+
|
|
232
|
+
Raises:
|
|
233
|
+
FileNotFoundError: If the file doesn't exist
|
|
234
|
+
json.JSONDecodeError: If the file is not valid JSON
|
|
235
|
+
pydantic.ValidationError: If the configuration is invalid
|
|
236
|
+
"""
|
|
237
|
+
if not file_path.exists():
|
|
238
|
+
raise FileNotFoundError(f"Configuration file not found: {file_path}")
|
|
239
|
+
|
|
240
|
+
with file_path.open("r", encoding="utf-8") as f:
|
|
241
|
+
data = json.load(f)
|
|
242
|
+
|
|
243
|
+
return cls.model_validate(data)
|
|
244
|
+
|
|
245
|
+
@classmethod
|
|
246
|
+
def from_cli_args(
|
|
247
|
+
cls,
|
|
248
|
+
source: FileSystemSource,
|
|
249
|
+
transport: Literal["stdio", "http", "sse", "streamable-http"] | None = None,
|
|
250
|
+
host: str | None = None,
|
|
251
|
+
port: int | None = None,
|
|
252
|
+
path: str | None = None,
|
|
253
|
+
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
|
254
|
+
| None = None,
|
|
255
|
+
python: str | None = None,
|
|
256
|
+
dependencies: list[str] | None = None,
|
|
257
|
+
requirements: str | None = None,
|
|
258
|
+
project: str | None = None,
|
|
259
|
+
editable: str | None = None,
|
|
260
|
+
env: dict[str, str] | None = None,
|
|
261
|
+
cwd: str | None = None,
|
|
262
|
+
args: list[str] | None = None,
|
|
263
|
+
) -> MCPServerConfig:
|
|
264
|
+
"""Create a config from CLI arguments.
|
|
265
|
+
|
|
266
|
+
This allows us to have a single code path where everything
|
|
267
|
+
goes through a config object.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
source: Server source (FileSystemSource instance)
|
|
271
|
+
transport: Transport protocol
|
|
272
|
+
host: Host for HTTP transport
|
|
273
|
+
port: Port for HTTP transport
|
|
274
|
+
path: URL path for server
|
|
275
|
+
log_level: Logging level
|
|
276
|
+
python: Python version
|
|
277
|
+
dependencies: Python packages to install
|
|
278
|
+
requirements: Path to requirements file
|
|
279
|
+
project: Path to project directory
|
|
280
|
+
editable: Path to install in editable mode
|
|
281
|
+
env: Environment variables
|
|
282
|
+
cwd: Working directory
|
|
283
|
+
args: Server arguments
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
MCPServerConfig instance
|
|
287
|
+
"""
|
|
288
|
+
# Build environment config if any env args provided
|
|
289
|
+
environment = None
|
|
290
|
+
if any([python, dependencies, requirements, project, editable]):
|
|
291
|
+
environment = UVEnvironment(
|
|
292
|
+
python=python,
|
|
293
|
+
dependencies=dependencies,
|
|
294
|
+
requirements=requirements,
|
|
295
|
+
project=project,
|
|
296
|
+
editable=[editable] if editable else None,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# Build deployment config if any deployment args provided
|
|
300
|
+
deployment = None
|
|
301
|
+
if any([transport, host, port, path, log_level, env, cwd, args]):
|
|
302
|
+
# Convert streamable-http to http for backward compatibility
|
|
303
|
+
if transport == "streamable-http":
|
|
304
|
+
transport = "http" # type: ignore[assignment]
|
|
305
|
+
deployment = Deployment(
|
|
306
|
+
transport=transport, # type: ignore[arg-type]
|
|
307
|
+
host=host,
|
|
308
|
+
port=port,
|
|
309
|
+
path=path,
|
|
310
|
+
log_level=log_level,
|
|
311
|
+
env=env,
|
|
312
|
+
cwd=cwd,
|
|
313
|
+
args=args,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
return cls(
|
|
317
|
+
source=source,
|
|
318
|
+
environment=environment,
|
|
319
|
+
deployment=deployment,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
@classmethod
|
|
323
|
+
def find_config(cls, start_path: Path | None = None) -> Path | None:
|
|
324
|
+
"""Find a fastmcp.json file in the specified directory.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
start_path: Directory to look in (defaults to current directory)
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Path to the configuration file, or None if not found
|
|
331
|
+
"""
|
|
332
|
+
if start_path is None:
|
|
333
|
+
start_path = Path.cwd()
|
|
334
|
+
|
|
335
|
+
config_path = start_path / "fastmcp.json"
|
|
336
|
+
if config_path.exists():
|
|
337
|
+
logger.debug(f"Found configuration file: {config_path}")
|
|
338
|
+
return config_path
|
|
339
|
+
|
|
340
|
+
return None
|
|
341
|
+
|
|
342
|
+
async def prepare(
|
|
343
|
+
self,
|
|
344
|
+
skip_source: bool = False,
|
|
345
|
+
output_dir: Path | None = None,
|
|
346
|
+
) -> None:
|
|
347
|
+
"""Prepare environment and source for execution.
|
|
348
|
+
|
|
349
|
+
When output_dir is provided, creates a persistent uv project.
|
|
350
|
+
When output_dir is None, does ephemeral caching (for backwards compatibility).
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
skip_source: Skip source preparation if True
|
|
354
|
+
output_dir: Directory to create the persistent uv project in (optional)
|
|
355
|
+
"""
|
|
356
|
+
# Prepare environment (persistent if output_dir provided, ephemeral otherwise)
|
|
357
|
+
if self.environment:
|
|
358
|
+
await self.prepare_environment(output_dir=output_dir)
|
|
359
|
+
|
|
360
|
+
if not skip_source:
|
|
361
|
+
await self.prepare_source()
|
|
362
|
+
|
|
363
|
+
async def prepare_environment(self, output_dir: Path | None = None) -> None:
|
|
364
|
+
"""Prepare the Python environment.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
output_dir: If provided, creates a persistent uv project in this directory.
|
|
368
|
+
If None, just populates uv's cache for ephemeral use.
|
|
369
|
+
|
|
370
|
+
Delegates to the environment's prepare() method
|
|
371
|
+
"""
|
|
372
|
+
await self.environment.prepare(output_dir=output_dir)
|
|
373
|
+
|
|
374
|
+
async def prepare_source(self) -> None:
|
|
375
|
+
"""Prepare the source for loading.
|
|
376
|
+
|
|
377
|
+
Delegates to the source's prepare() method.
|
|
378
|
+
"""
|
|
379
|
+
await self.source.prepare()
|
|
380
|
+
|
|
381
|
+
async def run_server(self, **kwargs: Any) -> None:
|
|
382
|
+
"""Load and run the server with this configuration.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
**kwargs: Additional arguments to pass to server.run_async()
|
|
386
|
+
These override config settings
|
|
387
|
+
"""
|
|
388
|
+
# Apply deployment settings (env vars, cwd)
|
|
389
|
+
if self.deployment:
|
|
390
|
+
self.deployment.apply_runtime_settings()
|
|
391
|
+
|
|
392
|
+
# Load the server
|
|
393
|
+
server = await self.source.load_server()
|
|
394
|
+
|
|
395
|
+
# Build run arguments from config
|
|
396
|
+
run_args = {}
|
|
397
|
+
if self.deployment:
|
|
398
|
+
if self.deployment.transport:
|
|
399
|
+
run_args["transport"] = self.deployment.transport
|
|
400
|
+
if self.deployment.host:
|
|
401
|
+
run_args["host"] = self.deployment.host
|
|
402
|
+
if self.deployment.port:
|
|
403
|
+
run_args["port"] = self.deployment.port
|
|
404
|
+
if self.deployment.path:
|
|
405
|
+
run_args["path"] = self.deployment.path
|
|
406
|
+
# Note: log_level not currently supported by run_async
|
|
407
|
+
|
|
408
|
+
# Override with any provided kwargs
|
|
409
|
+
run_args.update(kwargs)
|
|
410
|
+
|
|
411
|
+
# Run the server
|
|
412
|
+
await server.run_async(**run_args)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def generate_schema(output_path: Path | str | None = None) -> dict[str, Any] | None:
|
|
416
|
+
"""Generate JSON schema for fastmcp.json files.
|
|
417
|
+
|
|
418
|
+
This is used to create the schema file that IDEs can use for
|
|
419
|
+
validation and auto-completion.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
output_path: Optional path to write the schema to. If provided,
|
|
423
|
+
writes the schema and returns None. If not provided,
|
|
424
|
+
returns the schema as a dictionary.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
JSON schema as a dictionary if output_path is None, otherwise None
|
|
428
|
+
"""
|
|
429
|
+
schema = MCPServerConfig.model_json_schema()
|
|
430
|
+
|
|
431
|
+
# Add some metadata
|
|
432
|
+
schema["$id"] = FASTMCP_JSON_SCHEMA
|
|
433
|
+
schema["title"] = "FastMCP Configuration"
|
|
434
|
+
schema["description"] = "Configuration file for FastMCP servers"
|
|
435
|
+
|
|
436
|
+
if output_path:
|
|
437
|
+
import json
|
|
438
|
+
|
|
439
|
+
output = Path(output_path)
|
|
440
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
441
|
+
with open(output, "w") as f:
|
|
442
|
+
json.dump(schema, f, indent=2)
|
|
443
|
+
f.write("\n") # Add trailing newline
|
|
444
|
+
return None
|
|
445
|
+
|
|
446
|
+
return schema
|