fastmcp 2.11.3__py3-none-any.whl → 2.12.0rc1__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.0rc1.dist-info}/METADATA +2 -1
- fastmcp-2.12.0rc1.dist-info/RECORD +129 -0
- fastmcp-2.11.3.dist-info/RECORD +0 -108
- {fastmcp-2.11.3.dist-info → fastmcp-2.12.0rc1.dist-info}/WHEEL +0 -0
- {fastmcp-2.11.3.dist-info → fastmcp-2.12.0rc1.dist-info}/entry_points.txt +0 -0
- {fastmcp-2.11.3.dist-info → fastmcp-2.12.0rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,6 +10,7 @@ import cyclopts
|
|
|
10
10
|
from rich import print
|
|
11
11
|
|
|
12
12
|
from fastmcp.utilities.logging import get_logger
|
|
13
|
+
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment
|
|
13
14
|
|
|
14
15
|
from .shared import process_common_args
|
|
15
16
|
|
|
@@ -74,7 +75,7 @@ def install_claude_code(
|
|
|
74
75
|
server_object: str | None,
|
|
75
76
|
name: str,
|
|
76
77
|
*,
|
|
77
|
-
with_editable: Path | None = None,
|
|
78
|
+
with_editable: list[Path] | None = None,
|
|
78
79
|
with_packages: list[str] | None = None,
|
|
79
80
|
env_vars: dict[str, str] | None = None,
|
|
80
81
|
python_version: str | None = None,
|
|
@@ -87,7 +88,7 @@ def install_claude_code(
|
|
|
87
88
|
file: Path to the server file
|
|
88
89
|
server_object: Optional server object name (for :object suffix)
|
|
89
90
|
name: Name for the server in Claude Code
|
|
90
|
-
with_editable: Optional
|
|
91
|
+
with_editable: Optional list of directories to install in editable mode
|
|
91
92
|
with_packages: Optional list of additional packages to install
|
|
92
93
|
env_vars: Optional dictionary of environment variables
|
|
93
94
|
python_version: Optional Python version to use
|
|
@@ -106,31 +107,22 @@ def install_claude_code(
|
|
|
106
107
|
)
|
|
107
108
|
return False
|
|
108
109
|
|
|
109
|
-
#
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# Add Python version if specified
|
|
113
|
-
if python_version:
|
|
114
|
-
args.extend(["--python", python_version])
|
|
115
|
-
|
|
116
|
-
# Add project if specified
|
|
117
|
-
if project:
|
|
118
|
-
args.extend(["--project", str(project)])
|
|
119
|
-
|
|
120
|
-
# Collect all packages in a set to deduplicate
|
|
121
|
-
packages = {"fastmcp"}
|
|
110
|
+
# Deduplicate packages and exclude 'fastmcp' since Environment adds it automatically
|
|
111
|
+
deduplicated_packages = None
|
|
122
112
|
if with_packages:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
113
|
+
deduplicated = list(dict.fromkeys(with_packages))
|
|
114
|
+
deduplicated_packages = [pkg for pkg in deduplicated if pkg != "fastmcp"]
|
|
115
|
+
if not deduplicated_packages:
|
|
116
|
+
deduplicated_packages = None
|
|
117
|
+
|
|
118
|
+
# Build uv run command using Environment.build_uv_run_command()
|
|
119
|
+
env_config = UVEnvironment(
|
|
120
|
+
python=python_version,
|
|
121
|
+
dependencies=deduplicated_packages,
|
|
122
|
+
requirements=str(with_requirements) if with_requirements else None,
|
|
123
|
+
project=str(project) if project else None,
|
|
124
|
+
editable=[str(p) for p in with_editable] if with_editable else None,
|
|
125
|
+
)
|
|
134
126
|
|
|
135
127
|
# Build server spec from parsed components
|
|
136
128
|
if server_object:
|
|
@@ -138,8 +130,8 @@ def install_claude_code(
|
|
|
138
130
|
else:
|
|
139
131
|
server_spec = str(file.resolve())
|
|
140
132
|
|
|
141
|
-
#
|
|
142
|
-
|
|
133
|
+
# Build the full command
|
|
134
|
+
full_command = env_config.build_command(["fastmcp", "run", server_spec])
|
|
143
135
|
|
|
144
136
|
# Build claude mcp add command
|
|
145
137
|
cmd_parts = [claude_cmd, "mcp", "add"]
|
|
@@ -151,7 +143,7 @@ def install_claude_code(
|
|
|
151
143
|
|
|
152
144
|
# Add server name and command
|
|
153
145
|
cmd_parts.extend([name, "--"])
|
|
154
|
-
cmd_parts.extend(
|
|
146
|
+
cmd_parts.extend(full_command)
|
|
155
147
|
|
|
156
148
|
try:
|
|
157
149
|
# Run the claude mcp add command
|
|
@@ -178,28 +170,29 @@ async def claude_code_command(
|
|
|
178
170
|
),
|
|
179
171
|
] = None,
|
|
180
172
|
with_editable: Annotated[
|
|
181
|
-
Path | None,
|
|
173
|
+
list[Path] | None,
|
|
182
174
|
cyclopts.Parameter(
|
|
183
|
-
|
|
184
|
-
help="Directory with pyproject.toml to install in editable mode",
|
|
175
|
+
"--with-editable",
|
|
176
|
+
help="Directory with pyproject.toml to install in editable mode (can be used multiple times)",
|
|
177
|
+
negative="",
|
|
185
178
|
),
|
|
186
179
|
] = None,
|
|
187
180
|
with_packages: Annotated[
|
|
188
|
-
list[str],
|
|
181
|
+
list[str] | None,
|
|
189
182
|
cyclopts.Parameter(
|
|
190
183
|
"--with",
|
|
191
|
-
help="Additional packages to install",
|
|
192
|
-
negative=
|
|
184
|
+
help="Additional packages to install (can be used multiple times)",
|
|
185
|
+
negative="",
|
|
193
186
|
),
|
|
194
|
-
] =
|
|
187
|
+
] = None,
|
|
195
188
|
env_vars: Annotated[
|
|
196
|
-
list[str],
|
|
189
|
+
list[str] | None,
|
|
197
190
|
cyclopts.Parameter(
|
|
198
191
|
"--env",
|
|
199
|
-
help="Environment variables in KEY=VALUE format",
|
|
200
|
-
negative=
|
|
192
|
+
help="Environment variables in KEY=VALUE format (can be used multiple times)",
|
|
193
|
+
negative="",
|
|
201
194
|
),
|
|
202
|
-
] =
|
|
195
|
+
] = None,
|
|
203
196
|
env_file: Annotated[
|
|
204
197
|
Path | None,
|
|
205
198
|
cyclopts.Parameter(
|
|
@@ -234,6 +227,10 @@ async def claude_code_command(
|
|
|
234
227
|
Args:
|
|
235
228
|
server_spec: Python file to install, optionally with :object suffix
|
|
236
229
|
"""
|
|
230
|
+
# Convert None to empty lists for list parameters
|
|
231
|
+
with_editable = with_editable or []
|
|
232
|
+
with_packages = with_packages or []
|
|
233
|
+
env_vars = env_vars or []
|
|
237
234
|
file, server_object, name, packages, env_dict = await process_common_args(
|
|
238
235
|
server_spec, server_name, with_packages, env_vars, env_file
|
|
239
236
|
)
|
|
@@ -10,6 +10,7 @@ from rich import print
|
|
|
10
10
|
|
|
11
11
|
from fastmcp.mcp_config import StdioMCPServer, update_config_file
|
|
12
12
|
from fastmcp.utilities.logging import get_logger
|
|
13
|
+
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment
|
|
13
14
|
|
|
14
15
|
from .shared import process_common_args
|
|
15
16
|
|
|
@@ -39,7 +40,7 @@ def install_claude_desktop(
|
|
|
39
40
|
server_object: str | None,
|
|
40
41
|
name: str,
|
|
41
42
|
*,
|
|
42
|
-
with_editable: Path | None = None,
|
|
43
|
+
with_editable: list[Path] | None = None,
|
|
43
44
|
with_packages: list[str] | None = None,
|
|
44
45
|
env_vars: dict[str, str] | None = None,
|
|
45
46
|
python_version: str | None = None,
|
|
@@ -52,7 +53,7 @@ def install_claude_desktop(
|
|
|
52
53
|
file: Path to the server file
|
|
53
54
|
server_object: Optional server object name (for :object suffix)
|
|
54
55
|
name: Name for the server in Claude's config
|
|
55
|
-
with_editable: Optional
|
|
56
|
+
with_editable: Optional list of directories to install in editable mode
|
|
56
57
|
with_packages: Optional list of additional packages to install
|
|
57
58
|
env_vars: Optional dictionary of environment variables
|
|
58
59
|
python_version: Optional Python version to use
|
|
@@ -72,45 +73,34 @@ def install_claude_desktop(
|
|
|
72
73
|
|
|
73
74
|
config_file = config_dir / "claude_desktop_config.json"
|
|
74
75
|
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Add Python version if specified
|
|
79
|
-
if python_version:
|
|
80
|
-
args.extend(["--python", python_version])
|
|
81
|
-
|
|
82
|
-
# Add project if specified
|
|
83
|
-
if project:
|
|
84
|
-
args.extend(["--project", str(project)])
|
|
85
|
-
|
|
86
|
-
# Collect all packages in a set to deduplicate
|
|
87
|
-
packages = {"fastmcp"}
|
|
76
|
+
# Deduplicate packages and exclude 'fastmcp' since Environment adds it automatically
|
|
77
|
+
deduplicated_packages = None
|
|
88
78
|
if with_packages:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
79
|
+
deduplicated = list(dict.fromkeys(with_packages))
|
|
80
|
+
deduplicated_packages = [pkg for pkg in deduplicated if pkg != "fastmcp"]
|
|
81
|
+
if not deduplicated_packages:
|
|
82
|
+
deduplicated_packages = None
|
|
83
|
+
|
|
84
|
+
env_config = UVEnvironment(
|
|
85
|
+
python=python_version,
|
|
86
|
+
dependencies=deduplicated_packages,
|
|
87
|
+
requirements=str(with_requirements) if with_requirements else None,
|
|
88
|
+
project=str(project) if project else None,
|
|
89
|
+
editable=[str(p) for p in with_editable] if with_editable else None,
|
|
90
|
+
)
|
|
101
91
|
# Build server spec from parsed components
|
|
102
92
|
if server_object:
|
|
103
93
|
server_spec = f"{file.resolve()}:{server_object}"
|
|
104
94
|
else:
|
|
105
95
|
server_spec = str(file.resolve())
|
|
106
96
|
|
|
107
|
-
#
|
|
108
|
-
|
|
97
|
+
# Build the full command
|
|
98
|
+
full_command = env_config.build_command(["fastmcp", "run", server_spec])
|
|
109
99
|
|
|
110
100
|
# Create server configuration
|
|
111
101
|
server_config = StdioMCPServer(
|
|
112
|
-
command=
|
|
113
|
-
args=
|
|
102
|
+
command=full_command[0],
|
|
103
|
+
args=full_command[1:],
|
|
114
104
|
env=env_vars or {},
|
|
115
105
|
)
|
|
116
106
|
|
|
@@ -151,28 +141,29 @@ async def claude_desktop_command(
|
|
|
151
141
|
),
|
|
152
142
|
] = None,
|
|
153
143
|
with_editable: Annotated[
|
|
154
|
-
Path | None,
|
|
144
|
+
list[Path] | None,
|
|
155
145
|
cyclopts.Parameter(
|
|
156
|
-
|
|
157
|
-
help="Directory with pyproject.toml to install in editable mode",
|
|
146
|
+
"--with-editable",
|
|
147
|
+
help="Directory with pyproject.toml to install in editable mode (can be used multiple times)",
|
|
148
|
+
negative="",
|
|
158
149
|
),
|
|
159
150
|
] = None,
|
|
160
151
|
with_packages: Annotated[
|
|
161
|
-
list[str],
|
|
152
|
+
list[str] | None,
|
|
162
153
|
cyclopts.Parameter(
|
|
163
154
|
"--with",
|
|
164
|
-
help="Additional packages to install",
|
|
165
|
-
negative=
|
|
155
|
+
help="Additional packages to install (can be used multiple times)",
|
|
156
|
+
negative="",
|
|
166
157
|
),
|
|
167
|
-
] =
|
|
158
|
+
] = None,
|
|
168
159
|
env_vars: Annotated[
|
|
169
|
-
list[str],
|
|
160
|
+
list[str] | None,
|
|
170
161
|
cyclopts.Parameter(
|
|
171
162
|
"--env",
|
|
172
|
-
help="Environment variables in KEY=VALUE format",
|
|
173
|
-
negative=
|
|
163
|
+
help="Environment variables in KEY=VALUE format (can be used multiple times)",
|
|
164
|
+
negative="",
|
|
174
165
|
),
|
|
175
|
-
] =
|
|
166
|
+
] = None,
|
|
176
167
|
env_file: Annotated[
|
|
177
168
|
Path | None,
|
|
178
169
|
cyclopts.Parameter(
|
|
@@ -207,6 +198,10 @@ async def claude_desktop_command(
|
|
|
207
198
|
Args:
|
|
208
199
|
server_spec: Python file to install, optionally with :object suffix
|
|
209
200
|
"""
|
|
201
|
+
# Convert None to empty lists for list parameters
|
|
202
|
+
with_editable = with_editable or []
|
|
203
|
+
with_packages = with_packages or []
|
|
204
|
+
env_vars = env_vars or []
|
|
210
205
|
file, server_object, name, with_packages, env_dict = await process_common_args(
|
|
211
206
|
server_spec, server_name, with_packages, env_vars, env_file
|
|
212
207
|
)
|
fastmcp/cli/install/cursor.py
CHANGED
|
@@ -9,8 +9,9 @@ from typing import Annotated
|
|
|
9
9
|
import cyclopts
|
|
10
10
|
from rich import print
|
|
11
11
|
|
|
12
|
-
from fastmcp.mcp_config import StdioMCPServer
|
|
12
|
+
from fastmcp.mcp_config import StdioMCPServer, update_config_file
|
|
13
13
|
from fastmcp.utilities.logging import get_logger
|
|
14
|
+
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment
|
|
14
15
|
|
|
15
16
|
from .shared import process_common_args
|
|
16
17
|
|
|
@@ -64,25 +65,27 @@ def open_deeplink(deeplink: str) -> bool:
|
|
|
64
65
|
return False
|
|
65
66
|
|
|
66
67
|
|
|
67
|
-
def
|
|
68
|
+
def install_cursor_workspace(
|
|
68
69
|
file: Path,
|
|
69
70
|
server_object: str | None,
|
|
70
71
|
name: str,
|
|
72
|
+
workspace_path: Path,
|
|
71
73
|
*,
|
|
72
|
-
with_editable: Path | None = None,
|
|
74
|
+
with_editable: list[Path] | None = None,
|
|
73
75
|
with_packages: list[str] | None = None,
|
|
74
76
|
env_vars: dict[str, str] | None = None,
|
|
75
77
|
python_version: str | None = None,
|
|
76
78
|
with_requirements: Path | None = None,
|
|
77
79
|
project: Path | None = None,
|
|
78
80
|
) -> bool:
|
|
79
|
-
"""Install FastMCP server
|
|
81
|
+
"""Install FastMCP server to workspace-specific Cursor configuration.
|
|
80
82
|
|
|
81
83
|
Args:
|
|
82
84
|
file: Path to the server file
|
|
83
85
|
server_object: Optional server object name (for :object suffix)
|
|
84
86
|
name: Name for the server in Cursor
|
|
85
|
-
|
|
87
|
+
workspace_path: Path to the workspace directory
|
|
88
|
+
with_editable: Optional list of directories to install in editable mode
|
|
86
89
|
with_packages: Optional list of additional packages to install
|
|
87
90
|
env_vars: Optional dictionary of environment variables
|
|
88
91
|
python_version: Optional Python version to use
|
|
@@ -92,45 +95,139 @@ def install_cursor(
|
|
|
92
95
|
Returns:
|
|
93
96
|
True if installation was successful, False otherwise
|
|
94
97
|
"""
|
|
95
|
-
#
|
|
96
|
-
|
|
98
|
+
# Ensure workspace path is absolute and exists
|
|
99
|
+
workspace_path = workspace_path.resolve()
|
|
100
|
+
if not workspace_path.exists():
|
|
101
|
+
print(f"[red]Workspace directory does not exist: {workspace_path}[/red]")
|
|
102
|
+
return False
|
|
97
103
|
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
104
|
+
# Create .cursor directory in workspace
|
|
105
|
+
cursor_dir = workspace_path / ".cursor"
|
|
106
|
+
cursor_dir.mkdir(exist_ok=True)
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
if project:
|
|
104
|
-
args.extend(["--project", str(project)])
|
|
108
|
+
config_file = cursor_dir / "mcp.json"
|
|
105
109
|
|
|
106
|
-
#
|
|
107
|
-
|
|
110
|
+
# Deduplicate packages and exclude 'fastmcp' since Environment adds it automatically
|
|
111
|
+
deduplicated_packages = None
|
|
108
112
|
if with_packages:
|
|
109
|
-
|
|
113
|
+
deduplicated = list(dict.fromkeys(with_packages))
|
|
114
|
+
deduplicated_packages = [pkg for pkg in deduplicated if pkg != "fastmcp"]
|
|
115
|
+
if not deduplicated_packages:
|
|
116
|
+
deduplicated_packages = None
|
|
117
|
+
|
|
118
|
+
env_config = UVEnvironment(
|
|
119
|
+
python=python_version,
|
|
120
|
+
dependencies=deduplicated_packages,
|
|
121
|
+
requirements=str(with_requirements.resolve()) if with_requirements else None,
|
|
122
|
+
project=str(project.resolve()) if project else None,
|
|
123
|
+
editable=[str(p.resolve()) for p in with_editable] if with_editable else None,
|
|
124
|
+
)
|
|
125
|
+
# Build server spec from parsed components
|
|
126
|
+
if server_object:
|
|
127
|
+
server_spec = f"{file.resolve()}:{server_object}"
|
|
128
|
+
else:
|
|
129
|
+
server_spec = str(file.resolve())
|
|
110
130
|
|
|
111
|
-
#
|
|
112
|
-
|
|
113
|
-
args.extend(["--with", pkg])
|
|
131
|
+
# Build the full command
|
|
132
|
+
full_command = env_config.build_command(["fastmcp", "run", server_spec])
|
|
114
133
|
|
|
115
|
-
|
|
116
|
-
|
|
134
|
+
# Create server configuration
|
|
135
|
+
server_config = StdioMCPServer(
|
|
136
|
+
command=full_command[0],
|
|
137
|
+
args=full_command[1:],
|
|
138
|
+
env=env_vars or {},
|
|
139
|
+
)
|
|
117
140
|
|
|
118
|
-
|
|
119
|
-
|
|
141
|
+
try:
|
|
142
|
+
# Create the config file if it doesn't exist
|
|
143
|
+
if not config_file.exists():
|
|
144
|
+
config_file.write_text('{"mcpServers": {}}')
|
|
120
145
|
|
|
146
|
+
# Update configuration with the new server
|
|
147
|
+
update_config_file(config_file, name, server_config)
|
|
148
|
+
print(
|
|
149
|
+
f"[green]Successfully installed '{name}' to workspace at {workspace_path}[/green]"
|
|
150
|
+
)
|
|
151
|
+
return True
|
|
152
|
+
except Exception as e:
|
|
153
|
+
print(f"[red]Failed to install server to workspace: {e}[/red]")
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def install_cursor(
|
|
158
|
+
file: Path,
|
|
159
|
+
server_object: str | None,
|
|
160
|
+
name: str,
|
|
161
|
+
*,
|
|
162
|
+
with_editable: list[Path] | None = None,
|
|
163
|
+
with_packages: list[str] | None = None,
|
|
164
|
+
env_vars: dict[str, str] | None = None,
|
|
165
|
+
python_version: str | None = None,
|
|
166
|
+
with_requirements: Path | None = None,
|
|
167
|
+
project: Path | None = None,
|
|
168
|
+
workspace: Path | None = None,
|
|
169
|
+
) -> bool:
|
|
170
|
+
"""Install FastMCP server in Cursor.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
file: Path to the server file
|
|
174
|
+
server_object: Optional server object name (for :object suffix)
|
|
175
|
+
name: Name for the server in Cursor
|
|
176
|
+
with_editable: Optional list of directories to install in editable mode
|
|
177
|
+
with_packages: Optional list of additional packages to install
|
|
178
|
+
env_vars: Optional dictionary of environment variables
|
|
179
|
+
python_version: Optional Python version to use
|
|
180
|
+
with_requirements: Optional requirements file to install from
|
|
181
|
+
project: Optional project directory to run within
|
|
182
|
+
workspace: Optional workspace directory for project-specific installation
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
True if installation was successful, False otherwise
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
# Deduplicate packages and exclude 'fastmcp' since Environment adds it automatically
|
|
189
|
+
deduplicated_packages = None
|
|
190
|
+
if with_packages:
|
|
191
|
+
deduplicated = list(dict.fromkeys(with_packages))
|
|
192
|
+
deduplicated_packages = [pkg for pkg in deduplicated if pkg != "fastmcp"]
|
|
193
|
+
if not deduplicated_packages:
|
|
194
|
+
deduplicated_packages = None
|
|
195
|
+
|
|
196
|
+
env_config = UVEnvironment(
|
|
197
|
+
python=python_version,
|
|
198
|
+
dependencies=deduplicated_packages,
|
|
199
|
+
requirements=str(with_requirements.resolve()) if with_requirements else None,
|
|
200
|
+
project=str(project.resolve()) if project else None,
|
|
201
|
+
editable=[str(p.resolve()) for p in with_editable] if with_editable else None,
|
|
202
|
+
)
|
|
121
203
|
# Build server spec from parsed components
|
|
122
204
|
if server_object:
|
|
123
205
|
server_spec = f"{file.resolve()}:{server_object}"
|
|
124
206
|
else:
|
|
125
207
|
server_spec = str(file.resolve())
|
|
126
208
|
|
|
127
|
-
#
|
|
128
|
-
|
|
209
|
+
# Build the full command
|
|
210
|
+
full_command = env_config.build_command(["fastmcp", "run", server_spec])
|
|
211
|
+
|
|
212
|
+
# If workspace is specified, install to workspace-specific config
|
|
213
|
+
if workspace:
|
|
214
|
+
return install_cursor_workspace(
|
|
215
|
+
file=file,
|
|
216
|
+
server_object=server_object,
|
|
217
|
+
name=name,
|
|
218
|
+
workspace_path=workspace,
|
|
219
|
+
with_editable=with_editable,
|
|
220
|
+
with_packages=with_packages,
|
|
221
|
+
env_vars=env_vars,
|
|
222
|
+
python_version=python_version,
|
|
223
|
+
with_requirements=with_requirements,
|
|
224
|
+
project=project,
|
|
225
|
+
)
|
|
129
226
|
|
|
130
227
|
# Create server configuration
|
|
131
228
|
server_config = StdioMCPServer(
|
|
132
|
-
command=
|
|
133
|
-
args=
|
|
229
|
+
command=full_command[0],
|
|
230
|
+
args=full_command[1:],
|
|
134
231
|
env=env_vars or {},
|
|
135
232
|
)
|
|
136
233
|
|
|
@@ -161,28 +258,29 @@ async def cursor_command(
|
|
|
161
258
|
),
|
|
162
259
|
] = None,
|
|
163
260
|
with_editable: Annotated[
|
|
164
|
-
Path | None,
|
|
261
|
+
list[Path] | None,
|
|
165
262
|
cyclopts.Parameter(
|
|
166
|
-
|
|
167
|
-
help="Directory with pyproject.toml to install in editable mode",
|
|
263
|
+
"--with-editable",
|
|
264
|
+
help="Directory with pyproject.toml to install in editable mode (can be used multiple times)",
|
|
265
|
+
negative="",
|
|
168
266
|
),
|
|
169
267
|
] = None,
|
|
170
268
|
with_packages: Annotated[
|
|
171
|
-
list[str],
|
|
269
|
+
list[str] | None,
|
|
172
270
|
cyclopts.Parameter(
|
|
173
271
|
"--with",
|
|
174
|
-
help="Additional packages to install",
|
|
175
|
-
negative=
|
|
272
|
+
help="Additional packages to install (can be used multiple times)",
|
|
273
|
+
negative="",
|
|
176
274
|
),
|
|
177
|
-
] =
|
|
275
|
+
] = None,
|
|
178
276
|
env_vars: Annotated[
|
|
179
|
-
list[str],
|
|
277
|
+
list[str] | None,
|
|
180
278
|
cyclopts.Parameter(
|
|
181
279
|
"--env",
|
|
182
|
-
help="Environment variables in KEY=VALUE format",
|
|
183
|
-
negative=
|
|
280
|
+
help="Environment variables in KEY=VALUE format (can be used multiple times)",
|
|
281
|
+
negative="",
|
|
184
282
|
),
|
|
185
|
-
] =
|
|
283
|
+
] = None,
|
|
186
284
|
env_file: Annotated[
|
|
187
285
|
Path | None,
|
|
188
286
|
cyclopts.Parameter(
|
|
@@ -211,12 +309,23 @@ async def cursor_command(
|
|
|
211
309
|
help="Run the command within the given project directory",
|
|
212
310
|
),
|
|
213
311
|
] = None,
|
|
312
|
+
workspace: Annotated[
|
|
313
|
+
Path | None,
|
|
314
|
+
cyclopts.Parameter(
|
|
315
|
+
"--workspace",
|
|
316
|
+
help="Install to workspace directory (will create .cursor/ inside it) instead of using deeplink",
|
|
317
|
+
),
|
|
318
|
+
] = None,
|
|
214
319
|
) -> None:
|
|
215
320
|
"""Install an MCP server in Cursor.
|
|
216
321
|
|
|
217
322
|
Args:
|
|
218
323
|
server_spec: Python file to install, optionally with :object suffix
|
|
219
324
|
"""
|
|
325
|
+
# Convert None to empty lists for list parameters
|
|
326
|
+
with_editable = with_editable or []
|
|
327
|
+
with_packages = with_packages or []
|
|
328
|
+
env_vars = env_vars or []
|
|
220
329
|
file, server_object, name, with_packages, env_dict = await process_common_args(
|
|
221
330
|
server_spec, server_name, with_packages, env_vars, env_file
|
|
222
331
|
)
|
|
@@ -231,6 +340,7 @@ async def cursor_command(
|
|
|
231
340
|
python_version=python,
|
|
232
341
|
with_requirements=with_requirements,
|
|
233
342
|
project=project,
|
|
343
|
+
workspace=workspace,
|
|
234
344
|
)
|
|
235
345
|
|
|
236
346
|
if not success:
|