Jeremiah Lowin commited on
Commit
dd7600a
·
unverified ·
1 Parent(s): bacf327

Add --python, --project, and --with-requirements options to CLI commands (#1190)

Browse files
docs/deployment/running-server.mdx CHANGED
@@ -53,12 +53,48 @@ You can specify transport options and other configuration:
53
  fastmcp run server.py --transport sse --port 9000
54
  ```
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  For development and testing, you can use the `dev` command to run your server with the MCP Inspector:
57
 
58
  ```bash
59
  fastmcp dev server.py
60
  ```
61
 
 
 
 
 
 
 
 
62
  See the [CLI documentation](/patterns/cli) for detailed information about all available commands and options.
63
 
64
  ### Passing Arguments to Servers
 
53
  fastmcp run server.py --transport sse --port 9000
54
  ```
55
 
56
+ ### Dependency Management with CLI
57
+
58
+ When using the FastMCP CLI, you can pass additional options to configure how `uv` runs your server:
59
+
60
+ ```bash
61
+ # Run with a specific Python version
62
+ fastmcp run server.py --python 3.11
63
+
64
+ # Run with additional packages
65
+ fastmcp run server.py --with pandas --with numpy
66
+
67
+ # Run with dependencies from a requirements file
68
+ fastmcp run server.py --with-requirements requirements.txt
69
+
70
+ # Combine multiple options
71
+ fastmcp run server.py --python 3.10 --with httpx --transport http
72
+
73
+ # Run within a specific project directory
74
+ fastmcp run server.py --project /path/to/project
75
+ ```
76
+
77
+ <Note>
78
+ When using `--python`, `--with`, `--project`, or `--with-requirements`, the server runs via `uv run` subprocess instead of using your local environment. The `uv` command will manage dependencies based on your project configuration.
79
+ </Note>
80
+
81
+ <Tip>
82
+ The `--python` option is particularly useful when you need to run a server with a specific Python version that differs from your system's default. This addresses common compatibility issues where servers require a particular Python version to function correctly.
83
+ </Tip>
84
+
85
  For development and testing, you can use the `dev` command to run your server with the MCP Inspector:
86
 
87
  ```bash
88
  fastmcp dev server.py
89
  ```
90
 
91
+ The `dev` command also supports the same dependency management options:
92
+
93
+ ```bash
94
+ # Dev server with specific Python version and packages
95
+ fastmcp dev server.py --python 3.11 --with pandas
96
+ ```
97
+
98
  See the [CLI documentation](/patterns/cli) for detailed information about all available commands and options.
99
 
100
  ### Passing Arguments to Servers
docs/integrations/claude-code.mdx CHANGED
@@ -62,12 +62,26 @@ The command will automatically configure the server with Claude Code's `claude m
62
 
63
  #### Dependencies
64
 
65
- If your server has dependencies, include them with the `--with` flag:
 
 
66
 
67
  ```bash
68
  fastmcp install claude-code server.py --with pandas --with requests
69
  ```
70
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  Alternatively, you can specify dependencies directly in your server code:
72
 
73
  ```python server.py
@@ -79,14 +93,30 @@ mcp = FastMCP(
79
  )
80
  ```
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  #### Environment Variables
83
 
84
  If your server needs environment variables (like API keys), you must include them:
85
 
86
  ```bash
87
  fastmcp install claude-code server.py --name "Weather Server" \
88
- --env-var API_KEY=your-api-key \
89
- --env-var DEBUG=true
90
  ```
91
 
92
  Or load them from a `.env` file:
@@ -101,7 +131,7 @@ fastmcp install claude-code server.py --name "Weather Server" --env-file .env
101
 
102
  ### Manual Configuration
103
 
104
- For more control over the configuration, you can manually use Claude Code's built-in MCP management commands:
105
 
106
  ```bash
107
  # Add a server with custom configuration
@@ -114,6 +144,16 @@ claude mcp add weather-server -e API_KEY=secret -e DEBUG=true -- uv run --with f
114
  claude mcp add my-server --scope user -- uv run --with fastmcp fastmcp run server.py
115
  ```
116
 
 
 
 
 
 
 
 
 
 
 
117
  ## Using the Server
118
 
119
  Once your server is installed, you can start using your FastMCP server with Claude Code.
 
62
 
63
  #### Dependencies
64
 
65
+ FastMCP provides flexible dependency management options for your Claude Code servers:
66
+
67
+ **Individual packages**: Use the `--with` flag to specify packages your server needs. You can use this flag multiple times:
68
 
69
  ```bash
70
  fastmcp install claude-code server.py --with pandas --with requests
71
  ```
72
 
73
+ **Requirements file**: If you maintain a `requirements.txt` file with all your dependencies, use `--with-requirements` to install them:
74
+
75
+ ```bash
76
+ fastmcp install claude-code server.py --with-requirements requirements.txt
77
+ ```
78
+
79
+ **Editable packages**: For local packages under development, use `--with-editable` to install them in editable mode:
80
+
81
+ ```bash
82
+ fastmcp install claude-code server.py --with-editable ./my-local-package
83
+ ```
84
+
85
  Alternatively, you can specify dependencies directly in your server code:
86
 
87
  ```python server.py
 
93
  )
94
  ```
95
 
96
+ #### Python Version and Project Configuration
97
+
98
+ Control the Python environment for your server with these options:
99
+
100
+ **Python version**: Use `--python` to specify which Python version your server requires. This ensures compatibility when your server needs specific Python features:
101
+
102
+ ```bash
103
+ fastmcp install claude-code server.py --python 3.11
104
+ ```
105
+
106
+ **Project directory**: Use `--project` to run your server within a specific project context. This tells `uv` to use the project's configuration files and virtual environment:
107
+
108
+ ```bash
109
+ fastmcp install claude-code server.py --project /path/to/my-project
110
+ ```
111
+
112
  #### Environment Variables
113
 
114
  If your server needs environment variables (like API keys), you must include them:
115
 
116
  ```bash
117
  fastmcp install claude-code server.py --name "Weather Server" \
118
+ --env API_KEY=your-api-key \
119
+ --env DEBUG=true
120
  ```
121
 
122
  Or load them from a `.env` file:
 
131
 
132
  ### Manual Configuration
133
 
134
+ For more control over the configuration, you can manually use Claude Code's built-in MCP management commands. This gives you direct control over how your server is launched:
135
 
136
  ```bash
137
  # Add a server with custom configuration
 
144
  claude mcp add my-server --scope user -- uv run --with fastmcp fastmcp run server.py
145
  ```
146
 
147
+ You can also manually specify Python versions and project directories in your Claude Code commands:
148
+
149
+ ```bash
150
+ # With specific Python version
151
+ claude mcp add ml-server -- uv run --python 3.11 --with fastmcp fastmcp run server.py
152
+
153
+ # Within a project directory
154
+ claude mcp add project-server -- uv run --project /path/to/project --with fastmcp fastmcp run server.py
155
+ ```
156
+
157
  ## Using the Server
158
 
159
  Once your server is installed, you can start using your FastMCP server with Claude Code.
docs/integrations/claude-desktop.mdx CHANGED
@@ -78,12 +78,26 @@ After installation, restart Claude Desktop completely. You should see a hammer i
78
 
79
  #### Dependencies
80
 
81
- If your server has dependencies, include them with the `--with` flag:
 
 
82
 
83
  ```bash
84
  fastmcp install claude-desktop server.py --with pandas --with requests
85
  ```
86
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  Alternatively, you can specify dependencies directly in your server code:
88
 
89
  ```python server.py
@@ -95,6 +109,24 @@ mcp = FastMCP(
95
  )
96
  ```
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  #### Environment Variables
99
 
100
  <Warning>
@@ -105,8 +137,8 @@ If your server needs environment variables (like API keys), you must include the
105
 
106
  ```bash
107
  fastmcp install claude-desktop server.py --name "Weather Server" \
108
- --env-var API_KEY=your-api-key \
109
- --env-var DEBUG=true
110
  ```
111
 
112
  Or load them from a `.env` file:
@@ -146,6 +178,8 @@ After updating the configuration file, restart Claude Desktop completely. Look f
146
  If your server has dependencies, you can use `uv` or another package manager to set up the environment.
147
 
148
 
 
 
149
  ```json
150
  {
151
  "mcpServers": {
@@ -153,9 +187,11 @@ If your server has dependencies, you can use `uv` or another package manager to
153
  "command": "uv",
154
  "args": [
155
  "run",
 
156
  "--with", "pandas",
157
  "--with", "requests",
158
- "python",
 
159
  "path/to/your/server.py"
160
  ]
161
  }
@@ -163,6 +199,29 @@ If your server has dependencies, you can use `uv` or another package manager to
163
  }
164
  ```
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  <Warning>
167
  - **`uv` must be installed and available in your system PATH**. Claude Desktop runs in its own isolated environment and needs `uv` to manage dependencies.
168
  - **On macOS, it is recommended to install `uv` globally with Homebrew** so that Claude Desktop will detect it: `brew install uv`. Installing `uv` with other methods may not make it accessible to Claude Desktop.
 
78
 
79
  #### Dependencies
80
 
81
+ FastMCP provides several ways to manage your server's dependencies when installing in Claude Desktop:
82
+
83
+ **Individual packages**: Use the `--with` flag to specify packages your server needs. You can use this flag multiple times:
84
 
85
  ```bash
86
  fastmcp install claude-desktop server.py --with pandas --with requests
87
  ```
88
 
89
+ **Requirements file**: If you have a `requirements.txt` file listing all your dependencies, use `--with-requirements` to install them all at once:
90
+
91
+ ```bash
92
+ fastmcp install claude-desktop server.py --with-requirements requirements.txt
93
+ ```
94
+
95
+ **Editable packages**: For local packages in development, use `--with-editable` to install them in editable mode:
96
+
97
+ ```bash
98
+ fastmcp install claude-desktop server.py --with-editable ./my-local-package
99
+ ```
100
+
101
  Alternatively, you can specify dependencies directly in your server code:
102
 
103
  ```python server.py
 
109
  )
110
  ```
111
 
112
+ #### Python Version and Project Directory
113
+
114
+ FastMCP allows you to control the Python environment for your server:
115
+
116
+ **Python version**: Use `--python` to specify which Python version your server should run with. This is particularly useful when your server requires a specific Python version:
117
+
118
+ ```bash
119
+ fastmcp install claude-desktop server.py --python 3.11
120
+ ```
121
+
122
+ **Project directory**: Use `--project` to run your server within a specific project directory. This ensures that `uv` will discover all `pyproject.toml`, `uv.toml`, and `.python-version` files from that project:
123
+
124
+ ```bash
125
+ fastmcp install claude-desktop server.py --project /path/to/my-project
126
+ ```
127
+
128
+ When you specify a project directory, all relative paths in your server will be resolved from that directory, and the project's virtual environment will be used.
129
+
130
  #### Environment Variables
131
 
132
  <Warning>
 
137
 
138
  ```bash
139
  fastmcp install claude-desktop server.py --name "Weather Server" \
140
+ --env API_KEY=your-api-key \
141
+ --env DEBUG=true
142
  ```
143
 
144
  Or load them from a `.env` file:
 
178
  If your server has dependencies, you can use `uv` or another package manager to set up the environment.
179
 
180
 
181
+ When manually configuring dependencies, the recommended approach is to use `uv` with FastMCP. The configuration uses `uv run` to create an isolated environment with your specified packages:
182
+
183
  ```json
184
  {
185
  "mcpServers": {
 
187
  "command": "uv",
188
  "args": [
189
  "run",
190
+ "--with", "fastmcp",
191
  "--with", "pandas",
192
  "--with", "requests",
193
+ "fastmcp",
194
+ "run",
195
  "path/to/your/server.py"
196
  ]
197
  }
 
199
  }
200
  ```
201
 
202
+ You can also manually specify Python versions and project directories in your configuration. Add `--python` to use a specific Python version, or `--project` to run within a project directory:
203
+
204
+ ```json
205
+ {
206
+ "mcpServers": {
207
+ "dice-roller": {
208
+ "command": "uv",
209
+ "args": [
210
+ "run",
211
+ "--python", "3.11",
212
+ "--project", "/path/to/project",
213
+ "--with", "fastmcp",
214
+ "fastmcp",
215
+ "run",
216
+ "path/to/your/server.py"
217
+ ]
218
+ }
219
+ }
220
+ }
221
+ ```
222
+
223
+ The order of arguments matters: Python version and project settings come before package specifications, which come before the actual command to run.
224
+
225
  <Warning>
226
  - **`uv` must be installed and available in your system PATH**. Claude Desktop runs in its own isolated environment and needs `uv` to manage dependencies.
227
  - **On macOS, it is recommended to install `uv` globally with Homebrew** so that Claude Desktop will detect it: `brew install uv`. Installing `uv` with other methods may not make it accessible to Claude Desktop.
docs/integrations/cursor.mdx CHANGED
@@ -64,12 +64,26 @@ After running the command, Cursor will open automatically and prompt you to inst
64
 
65
  #### Dependencies
66
 
67
- If your server has dependencies, include them with the `--with` flag:
 
 
68
 
69
  ```bash
70
  fastmcp install cursor server.py --with pandas --with requests
71
  ```
72
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  Alternatively, you can specify dependencies directly in your server code:
74
 
75
  ```python server.py
@@ -81,6 +95,22 @@ mcp = FastMCP(
81
  )
82
  ```
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  #### Environment Variables
85
 
86
  <Warning>
@@ -91,8 +121,8 @@ If your server needs environment variables (like API keys), you must include the
91
 
92
  ```bash
93
  fastmcp install cursor server.py --name "Weather Server" \
94
- --env-var API_KEY=your-api-key \
95
- --env-var DEBUG=true
96
  ```
97
 
98
  Or load them from a `.env` file:
@@ -147,6 +177,8 @@ After updating the configuration file, your server should be available in Cursor
147
 
148
  If your server has dependencies, you can use `uv` or another package manager to set up the environment.
149
 
 
 
150
  ```json
151
  {
152
  "mcpServers": {
@@ -154,9 +186,11 @@ If your server has dependencies, you can use `uv` or another package manager to
154
  "command": "uv",
155
  "args": [
156
  "run",
 
157
  "--with", "pandas",
158
  "--with", "requests",
159
- "python",
 
160
  "path/to/your/server.py"
161
  ]
162
  }
@@ -164,6 +198,29 @@ If your server has dependencies, you can use `uv` or another package manager to
164
  }
165
  ```
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  <Warning>
168
  **`uv` must be installed and available in your system PATH**. Cursor runs in its own isolated environment and needs `uv` to manage dependencies.
169
  </Warning>
 
64
 
65
  #### Dependencies
66
 
67
+ FastMCP offers multiple ways to manage dependencies for your Cursor servers:
68
+
69
+ **Individual packages**: Use the `--with` flag to specify packages your server needs. You can use this flag multiple times:
70
 
71
  ```bash
72
  fastmcp install cursor server.py --with pandas --with requests
73
  ```
74
 
75
+ **Requirements file**: For projects with a `requirements.txt` file, use `--with-requirements` to install all dependencies at once:
76
+
77
+ ```bash
78
+ fastmcp install cursor server.py --with-requirements requirements.txt
79
+ ```
80
+
81
+ **Editable packages**: When developing local packages, use `--with-editable` to install them in editable mode:
82
+
83
+ ```bash
84
+ fastmcp install cursor server.py --with-editable ./my-local-package
85
+ ```
86
+
87
  Alternatively, you can specify dependencies directly in your server code:
88
 
89
  ```python server.py
 
95
  )
96
  ```
97
 
98
+ #### Python Version and Project Configuration
99
+
100
+ Control your server's Python environment with these options:
101
+
102
+ **Python version**: Use `--python` to specify which Python version your server should use. This is essential when your server requires specific Python features:
103
+
104
+ ```bash
105
+ fastmcp install cursor server.py --python 3.11
106
+ ```
107
+
108
+ **Project directory**: Use `--project` to run your server within a specific project context. This ensures `uv` discovers all project configuration files and uses the correct virtual environment:
109
+
110
+ ```bash
111
+ fastmcp install cursor server.py --project /path/to/my-project
112
+ ```
113
+
114
  #### Environment Variables
115
 
116
  <Warning>
 
121
 
122
  ```bash
123
  fastmcp install cursor server.py --name "Weather Server" \
124
+ --env API_KEY=your-api-key \
125
+ --env DEBUG=true
126
  ```
127
 
128
  Or load them from a `.env` file:
 
177
 
178
  If your server has dependencies, you can use `uv` or another package manager to set up the environment.
179
 
180
+ When manually configuring dependencies, the recommended approach is to use `uv` with FastMCP. The configuration should use `uv run` to create an isolated environment with your specified packages:
181
+
182
  ```json
183
  {
184
  "mcpServers": {
 
186
  "command": "uv",
187
  "args": [
188
  "run",
189
+ "--with", "fastmcp",
190
  "--with", "pandas",
191
  "--with", "requests",
192
+ "fastmcp",
193
+ "run",
194
  "path/to/your/server.py"
195
  ]
196
  }
 
198
  }
199
  ```
200
 
201
+ You can also manually specify Python versions and project directories in your configuration:
202
+
203
+ ```json
204
+ {
205
+ "mcpServers": {
206
+ "dice-roller": {
207
+ "command": "uv",
208
+ "args": [
209
+ "run",
210
+ "--python", "3.11",
211
+ "--project", "/path/to/project",
212
+ "--with", "fastmcp",
213
+ "fastmcp",
214
+ "run",
215
+ "path/to/your/server.py"
216
+ ]
217
+ }
218
+ }
219
+ }
220
+ ```
221
+
222
+ Note that the order of arguments is important: Python version and project settings should come before package specifications.
223
+
224
  <Warning>
225
  **`uv` must be installed and available in your system PATH**. Cursor runs in its own isolated environment and needs `uv` to manage dependencies.
226
  </Warning>
docs/integrations/mcp-json-configuration.mdx CHANGED
@@ -136,6 +136,10 @@ To use this in a client configuration file, add it to the `mcpServers` object in
136
  }
137
  ```
138
 
 
 
 
 
139
  <Note>
140
  Different MCP clients may have specific configuration requirements or formatting needs. Always consult your client's documentation to ensure proper integration.
141
  </Note>
@@ -165,6 +169,9 @@ fastmcp install mcp-json server.py --with pandas --with requests --with httpx
165
 
166
  # Editable local package
167
  fastmcp install mcp-json server.py --with-editable ./my-package
 
 
 
168
  ```
169
 
170
  You can also specify dependencies directly in your server code:
@@ -190,6 +197,18 @@ fastmcp install mcp-json server.py \
190
  fastmcp install mcp-json server.py --env-file .env
191
  ```
192
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  ### Server Object Selection
194
 
195
  Use the same `file.py:object` notation as other FastMCP commands:
@@ -250,6 +269,17 @@ fastmcp install mcp-json api_server.py \
250
  --env TIMEOUT=30
251
  ```
252
 
 
 
 
 
 
 
 
 
 
 
 
253
  Output:
254
  ```json
255
  {
@@ -275,6 +305,32 @@ Output:
275
  }
276
  ```
277
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  ### Pipeline Usage
279
 
280
  Save configuration to file:
 
136
  }
137
  ```
138
 
139
+ <Note>
140
+ When using `--python`, `--project`, or `--with-requirements`, the generated configuration will include these options in the `uv run` command, ensuring your server runs with the correct Python version and dependencies.
141
+ </Note>
142
+
143
  <Note>
144
  Different MCP clients may have specific configuration requirements or formatting needs. Always consult your client's documentation to ensure proper integration.
145
  </Note>
 
169
 
170
  # Editable local package
171
  fastmcp install mcp-json server.py --with-editable ./my-package
172
+
173
+ # From requirements file
174
+ fastmcp install mcp-json server.py --with-requirements requirements.txt
175
  ```
176
 
177
  You can also specify dependencies directly in your server code:
 
197
  fastmcp install mcp-json server.py --env-file .env
198
  ```
199
 
200
+ ### Python Version and Project Directory
201
+
202
+ Specify Python version or run within a specific project:
203
+
204
+ ```bash
205
+ # Use specific Python version
206
+ fastmcp install mcp-json server.py --python 3.11
207
+
208
+ # Run within a project directory
209
+ fastmcp install mcp-json server.py --project /path/to/project
210
+ ```
211
+
212
  ### Server Object Selection
213
 
214
  Use the same `file.py:object` notation as other FastMCP commands:
 
269
  --env TIMEOUT=30
270
  ```
271
 
272
+ ### Advanced Configuration
273
+
274
+ ```bash
275
+ fastmcp install mcp-json ml_server.py \
276
+ --name "ML Analysis Server" \
277
+ --python 3.11 \
278
+ --with-requirements requirements.txt \
279
+ --project /home/user/ml-project \
280
+ --env GPU_DEVICE=0
281
+ ```
282
+
283
  Output:
284
  ```json
285
  {
 
305
  }
306
  ```
307
 
308
+ The advanced configuration example generates:
309
+ ```json
310
+ {
311
+ "ML Analysis Server": {
312
+ "command": "uv",
313
+ "args": [
314
+ "run",
315
+ "--python",
316
+ "3.11",
317
+ "--project",
318
+ "/home/user/ml-project",
319
+ "--with",
320
+ "fastmcp",
321
+ "--with-requirements",
322
+ "requirements.txt",
323
+ "fastmcp",
324
+ "run",
325
+ "/home/user/ml_server.py"
326
+ ],
327
+ "env": {
328
+ "GPU_DEVICE": "0"
329
+ }
330
+ }
331
+ }
332
+ ```
333
+
334
  ### Pipeline Usage
335
 
336
  Save configuration to file:
docs/patterns/cli.mdx CHANGED
@@ -18,8 +18,8 @@ fastmcp --help
18
 
19
  | Command | Purpose | Dependency Management |
20
  | ------- | ------- | --------------------- |
21
- | `run` | Run a FastMCP server directly | Uses your current environment; you are responsible for ensuring all dependencies are available |
22
- | `dev` | Run a server with the MCP Inspector for testing | Creates an isolated environment; dependencies must be explicitly specified with `--with` and/or `--with-editable` |
23
  | `install` | Install a server in MCP client applications | Creates an isolated environment; dependencies must be explicitly specified with `--with` and/or `--with-editable` |
24
  | `inspect` | Generate a JSON report about a FastMCP server | Uses your current environment; you are responsible for ensuring all dependencies are available |
25
  | `version` | Display version information | N/A |
@@ -35,7 +35,7 @@ fastmcp run server.py
35
  ```
36
 
37
  <Tip>
38
- This command runs the server directly in your current Python environment. You are responsible for ensuring all dependencies are available.
39
  </Tip>
40
 
41
  #### Options
@@ -48,6 +48,10 @@ This command runs the server directly in your current Python environment. You ar
48
  | Path | `--path` | Path to bind to when using http transport (default: `/mcp/` or `/sse/` for SSE) |
49
  | Log Level | `--log-level`, `-l` | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
50
  | No Banner | `--no-banner` | Disable the startup banner display |
 
 
 
 
51
 
52
 
53
  #### Server Specification
@@ -96,6 +100,18 @@ fastmcp run https://example.com/mcp-server
96
 
97
  # Connect to a remote server with specified log level
98
  fastmcp run https://example.com/mcp-server --log-level DEBUG
 
 
 
 
 
 
 
 
 
 
 
 
99
  ```
100
 
101
  ### `dev`
@@ -107,7 +123,7 @@ fastmcp dev server.py
107
  ```
108
 
109
  <Tip>
110
- This command runs your server in an isolated environment. All dependencies must be explicitly specified using the `--with` and/or `--with-editable` options.
111
  </Tip>
112
 
113
  <Warning>
@@ -136,12 +152,24 @@ This command does not support HTTP testing. To test a server over Streamable HTT
136
  | Inspector Version | `--inspector-version` | Version of the MCP Inspector to use |
137
  | UI Port | `--ui-port` | Port for the MCP Inspector UI |
138
  | Server Port | `--server-port` | Port for the MCP Inspector Proxy server |
 
 
 
139
 
140
- **Example**
141
 
142
  ```bash
143
  # Run dev server with editable mode and additional packages
144
  fastmcp dev server.py -e . --with pandas --with matplotlib
 
 
 
 
 
 
 
 
 
145
  ```
146
 
147
  ### `install`
@@ -167,6 +195,10 @@ Note that for security reasons, MCP clients usually run every server in a comple
167
  **`uv` must be installed and available in your system PATH**. Both Claude Desktop and Cursor run in isolated environments and need `uv` to manage dependencies. On macOS, install `uv` globally with Homebrew for Claude Desktop compatibility: `brew install uv`.
168
  </Warning>
169
 
 
 
 
 
170
  <Tip>
171
  **FastMCP `install` commands focus on local server files with STDIO transport.** For remote servers running with HTTP or SSE transport, use your client's native configuration - FastMCP's value is simplifying the complex local setup with dependencies and `uv` commands.
172
  </Tip>
@@ -187,6 +219,9 @@ The `install` command supports the same `file.py:object` notation as the `run` c
187
  | Additional Packages | `--with` | Additional packages to install (can be used multiple times) |
188
  | Environment Variables | `--env` | Environment variables in KEY=VALUE format (can be used multiple times) |
189
  | Environment File | `--env-file`, `-f` | Load environment variables from a .env file |
 
 
 
190
 
191
  **Examples**
192
 
@@ -209,6 +244,15 @@ fastmcp install cursor server.py --env API_KEY=secret --env DEBUG=true
209
  # Install with environment file
210
  fastmcp install cursor server.py --env-file .env
211
 
 
 
 
 
 
 
 
 
 
212
  # Generate MCP JSON configuration
213
  fastmcp install mcp-json server.py --name "My Server" --with pandas
214
 
 
18
 
19
  | Command | Purpose | Dependency Management |
20
  | ------- | ------- | --------------------- |
21
+ | `run` | Run a FastMCP server directly | Default: Uses your local environment directly. With `--python`, `--with`, `--project`, or `--with-requirements`: Runs via `uv run` subprocess |
22
+ | `dev` | Run a server with the MCP Inspector for testing | Always runs via `uv run` subprocess (never uses your local environment); dependencies must be specified or available in a uv-managed project |
23
  | `install` | Install a server in MCP client applications | Creates an isolated environment; dependencies must be explicitly specified with `--with` and/or `--with-editable` |
24
  | `inspect` | Generate a JSON report about a FastMCP server | Uses your current environment; you are responsible for ensuring all dependencies are available |
25
  | `version` | Display version information | N/A |
 
35
  ```
36
 
37
  <Tip>
38
+ By default, this command runs the server directly in your current Python environment. You are responsible for ensuring all dependencies are available. When using `--python`, `--with`, `--project`, or `--with-requirements` options, it runs the server via `uv run` subprocess instead.
39
  </Tip>
40
 
41
  #### Options
 
48
  | Path | `--path` | Path to bind to when using http transport (default: `/mcp/` or `/sse/` for SSE) |
49
  | Log Level | `--log-level`, `-l` | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
50
  | No Banner | `--no-banner` | Disable the startup banner display |
51
+ | Python Version | `--python` | Python version to use (e.g., 3.10, 3.11) |
52
+ | Additional Packages | `--with` | Additional packages to install (can be used multiple times) |
53
+ | Project Directory | `--project` | Run the command within the given project directory |
54
+ | Requirements File | `--with-requirements` | Requirements file to install dependencies from |
55
 
56
 
57
  #### Server Specification
 
100
 
101
  # Connect to a remote server with specified log level
102
  fastmcp run https://example.com/mcp-server --log-level DEBUG
103
+
104
+ # Run with a specific Python version
105
+ fastmcp run server.py --python 3.11
106
+
107
+ # Run with additional packages
108
+ fastmcp run server.py --with pandas --with numpy
109
+
110
+ # Run within a specific project directory
111
+ fastmcp run server.py --project /path/to/project
112
+
113
+ # Run with dependencies from a requirements file
114
+ fastmcp run server.py --with-requirements requirements.txt
115
  ```
116
 
117
  ### `dev`
 
123
  ```
124
 
125
  <Tip>
126
+ This command always runs your server via `uv run` subprocess (never your local environment) to work with the MCP Inspector. All dependencies must be explicitly specified using the `--with` and/or `--with-editable` options, or be available in a uv-managed project.
127
  </Tip>
128
 
129
  <Warning>
 
152
  | Inspector Version | `--inspector-version` | Version of the MCP Inspector to use |
153
  | UI Port | `--ui-port` | Port for the MCP Inspector UI |
154
  | Server Port | `--server-port` | Port for the MCP Inspector Proxy server |
155
+ | Python Version | `--python` | Python version to use (e.g., 3.10, 3.11) |
156
+ | Project Directory | `--project` | Run the command within the given project directory |
157
+ | Requirements File | `--with-requirements` | Requirements file to install dependencies from |
158
 
159
+ **Examples**
160
 
161
  ```bash
162
  # Run dev server with editable mode and additional packages
163
  fastmcp dev server.py -e . --with pandas --with matplotlib
164
+
165
+ # Run dev server with specific Python version
166
+ fastmcp dev server.py --python 3.11
167
+
168
+ # Run dev server with requirements file
169
+ fastmcp dev server.py --with-requirements requirements.txt
170
+
171
+ # Run dev server within a specific project directory
172
+ fastmcp dev server.py --project /path/to/project
173
  ```
174
 
175
  ### `install`
 
195
  **`uv` must be installed and available in your system PATH**. Both Claude Desktop and Cursor run in isolated environments and need `uv` to manage dependencies. On macOS, install `uv` globally with Homebrew for Claude Desktop compatibility: `brew install uv`.
196
  </Warning>
197
 
198
+ <Note>
199
+ **Python Version Considerations**: The install commands now support the `--python` option to specify a Python version directly. You can also use `--project` to run within a specific project directory or `--with-requirements` to install dependencies from a requirements file.
200
+ </Note>
201
+
202
  <Tip>
203
  **FastMCP `install` commands focus on local server files with STDIO transport.** For remote servers running with HTTP or SSE transport, use your client's native configuration - FastMCP's value is simplifying the complex local setup with dependencies and `uv` commands.
204
  </Tip>
 
219
  | Additional Packages | `--with` | Additional packages to install (can be used multiple times) |
220
  | Environment Variables | `--env` | Environment variables in KEY=VALUE format (can be used multiple times) |
221
  | Environment File | `--env-file`, `-f` | Load environment variables from a .env file |
222
+ | Python Version | `--python` | Python version to use (e.g., 3.10, 3.11) |
223
+ | Project Directory | `--project` | Run the command within the given project directory |
224
+ | Requirements File | `--with-requirements` | Requirements file to install dependencies from |
225
 
226
  **Examples**
227
 
 
244
  # Install with environment file
245
  fastmcp install cursor server.py --env-file .env
246
 
247
+ # Install with specific Python version
248
+ fastmcp install claude-desktop server.py --python 3.11
249
+
250
+ # Install with requirements file
251
+ fastmcp install claude-code server.py --with-requirements requirements.txt
252
+
253
+ # Install within a project directory
254
+ fastmcp install cursor server.py --project /path/to/project
255
+
256
  # Generate MCP JSON configuration
257
  fastmcp install mcp-json server.py --name "My Server" --with pandas
258
 
src/fastmcp/cli/cli.py CHANGED
@@ -62,11 +62,22 @@ def _build_uv_command(
62
  with_editable: Path | None = None,
63
  with_packages: list[str] | None = None,
64
  no_banner: bool = False,
 
 
 
65
  ) -> list[str]:
66
  """Build the uv run command that runs a MCP server through mcp run."""
67
- cmd = ["uv"]
68
 
69
- cmd.extend(["run", "--with", "fastmcp"])
 
 
 
 
 
 
 
 
70
 
71
  if with_editable:
72
  cmd.extend(["--with-editable", str(with_editable)])
@@ -76,6 +87,9 @@ def _build_uv_command(
76
  if pkg:
77
  cmd.extend(["--with", pkg])
78
 
 
 
 
79
  # Add mcp run command
80
  cmd.extend(["fastmcp", "run", server_spec])
81
 
@@ -163,6 +177,27 @@ def dev(
163
  help="Port for the MCP Inspector Proxy server",
164
  ),
165
  ] = None,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  ) -> None:
167
  """Run an MCP server with the MCP Inspector for development.
168
 
@@ -209,7 +244,13 @@ def dev(
209
  inspector_cmd += f"@{inspector_version}"
210
 
211
  uv_cmd = _build_uv_command(
212
- server_spec, with_editable, with_packages, no_banner=True
 
 
 
 
 
 
213
  )
214
 
215
  # Run the MCP Inspector command with shell=True on Windows
@@ -288,6 +329,35 @@ def run(
288
  negative=False,
289
  ),
290
  ] = False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  ) -> None:
292
  """Run an MCP server or connect to a remote one.
293
 
@@ -318,26 +388,53 @@ def run(
318
  },
319
  )
320
 
321
- try:
322
- run_module.run_command(
323
- server_spec=server_spec,
324
- transport=transport,
325
- host=host,
326
- port=port,
327
- path=path,
328
- log_level=log_level,
329
- server_args=server_args,
330
- show_banner=not no_banner,
331
- )
332
- except Exception as e:
333
- logger.error(
334
- f"Failed to run: {e}",
335
- extra={
336
- "server_spec": server_spec,
337
- "error": str(e),
338
- },
339
- )
340
- sys.exit(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
 
343
  @app.command
 
62
  with_editable: Path | None = None,
63
  with_packages: list[str] | None = None,
64
  no_banner: bool = False,
65
+ python_version: str | None = None,
66
+ with_requirements: Path | None = None,
67
+ project: Path | None = None,
68
  ) -> list[str]:
69
  """Build the uv run command that runs a MCP server through mcp run."""
70
+ cmd = ["uv", "run"]
71
 
72
+ # Add Python version if specified
73
+ if python_version:
74
+ cmd.extend(["--python", python_version])
75
+
76
+ # Add project if specified
77
+ if project:
78
+ cmd.extend(["--project", str(project)])
79
+
80
+ cmd.extend(["--with", "fastmcp"])
81
 
82
  if with_editable:
83
  cmd.extend(["--with-editable", str(with_editable)])
 
87
  if pkg:
88
  cmd.extend(["--with", pkg])
89
 
90
+ if with_requirements:
91
+ cmd.extend(["--with-requirements", str(with_requirements)])
92
+
93
  # Add mcp run command
94
  cmd.extend(["fastmcp", "run", server_spec])
95
 
 
177
  help="Port for the MCP Inspector Proxy server",
178
  ),
179
  ] = None,
180
+ python: Annotated[
181
+ str | None,
182
+ cyclopts.Parameter(
183
+ "--python",
184
+ help="Python version to use (e.g., 3.10, 3.11)",
185
+ ),
186
+ ] = None,
187
+ with_requirements: Annotated[
188
+ Path | None,
189
+ cyclopts.Parameter(
190
+ "--with-requirements",
191
+ help="Requirements file to install dependencies from",
192
+ ),
193
+ ] = None,
194
+ project: Annotated[
195
+ Path | None,
196
+ cyclopts.Parameter(
197
+ "--project",
198
+ help="Run the command within the given project directory",
199
+ ),
200
+ ] = None,
201
  ) -> None:
202
  """Run an MCP server with the MCP Inspector for development.
203
 
 
244
  inspector_cmd += f"@{inspector_version}"
245
 
246
  uv_cmd = _build_uv_command(
247
+ server_spec,
248
+ with_editable,
249
+ with_packages,
250
+ no_banner=True,
251
+ python_version=python,
252
+ with_requirements=with_requirements,
253
+ project=project,
254
  )
255
 
256
  # Run the MCP Inspector command with shell=True on Windows
 
329
  negative=False,
330
  ),
331
  ] = False,
332
+ python: Annotated[
333
+ str | None,
334
+ cyclopts.Parameter(
335
+ "--python",
336
+ help="Python version to use (e.g., 3.10, 3.11)",
337
+ ),
338
+ ] = None,
339
+ with_packages: Annotated[
340
+ list[str],
341
+ cyclopts.Parameter(
342
+ "--with",
343
+ help="Additional packages to install (can be used multiple times)",
344
+ negative=False,
345
+ ),
346
+ ] = [],
347
+ project: Annotated[
348
+ Path | None,
349
+ cyclopts.Parameter(
350
+ "--project",
351
+ help="Run the command within the given project directory",
352
+ ),
353
+ ] = None,
354
+ with_requirements: Annotated[
355
+ Path | None,
356
+ cyclopts.Parameter(
357
+ "--with-requirements",
358
+ help="Requirements file to install dependencies from",
359
+ ),
360
+ ] = None,
361
  ) -> None:
362
  """Run an MCP server or connect to a remote one.
363
 
 
388
  },
389
  )
390
 
391
+ # If any uv-specific options are provided, use uv run
392
+ if python or with_packages or with_requirements or project:
393
+ try:
394
+ run_module.run_with_uv(
395
+ server_spec=server_spec,
396
+ python_version=python,
397
+ with_packages=with_packages,
398
+ with_requirements=with_requirements,
399
+ project=project,
400
+ transport=transport,
401
+ host=host,
402
+ port=port,
403
+ path=path,
404
+ log_level=log_level,
405
+ show_banner=not no_banner,
406
+ )
407
+ except Exception as e:
408
+ logger.error(
409
+ f"Failed to run: {e}",
410
+ extra={
411
+ "server_spec": server_spec,
412
+ "error": str(e),
413
+ },
414
+ )
415
+ sys.exit(1)
416
+ else:
417
+ # Use direct import for backwards compatibility
418
+ try:
419
+ run_module.run_command(
420
+ server_spec=server_spec,
421
+ transport=transport,
422
+ host=host,
423
+ port=port,
424
+ path=path,
425
+ log_level=log_level,
426
+ server_args=server_args,
427
+ show_banner=not no_banner,
428
+ )
429
+ except Exception as e:
430
+ logger.error(
431
+ f"Failed to run: {e}",
432
+ extra={
433
+ "server_spec": server_spec,
434
+ "error": str(e),
435
+ },
436
+ )
437
+ sys.exit(1)
438
 
439
 
440
  @app.command
src/fastmcp/cli/install/claude_code.py CHANGED
@@ -77,6 +77,9 @@ def install_claude_code(
77
  with_editable: Path | None = None,
78
  with_packages: list[str] | None = None,
79
  env_vars: dict[str, str] | None = None,
 
 
 
80
  ) -> bool:
81
  """Install FastMCP server in Claude Code.
82
 
@@ -87,6 +90,9 @@ def install_claude_code(
87
  with_editable: Optional directory to install in editable mode
88
  with_packages: Optional list of additional packages to install
89
  env_vars: Optional dictionary of environment variables
 
 
 
90
 
91
  Returns:
92
  True if installation was successful, False otherwise
@@ -103,6 +109,14 @@ def install_claude_code(
103
  # Build uv run command
104
  args = ["run"]
105
 
 
 
 
 
 
 
 
 
106
  # Collect all packages in a set to deduplicate
107
  packages = {"fastmcp"}
108
  if with_packages:
@@ -115,6 +129,9 @@ def install_claude_code(
115
  if with_editable:
116
  args.extend(["--with-editable", str(with_editable)])
117
 
 
 
 
118
  # Build server spec from parsed components
119
  if server_object:
120
  server_spec = f"{file.resolve()}:{server_object}"
@@ -190,6 +207,27 @@ def claude_code_command(
190
  help="Load environment variables from .env file",
191
  ),
192
  ] = None,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  ) -> None:
194
  """Install an MCP server in Claude Code.
195
 
@@ -207,6 +245,9 @@ def claude_code_command(
207
  with_editable=with_editable,
208
  with_packages=packages,
209
  env_vars=env_dict,
 
 
 
210
  )
211
 
212
  if success:
 
77
  with_editable: Path | None = None,
78
  with_packages: list[str] | None = None,
79
  env_vars: dict[str, str] | None = None,
80
+ python_version: str | None = None,
81
+ with_requirements: Path | None = None,
82
+ project: Path | None = None,
83
  ) -> bool:
84
  """Install FastMCP server in Claude Code.
85
 
 
90
  with_editable: Optional directory to install in editable mode
91
  with_packages: Optional list of additional packages to install
92
  env_vars: Optional dictionary of environment variables
93
+ python_version: Optional Python version to use
94
+ with_requirements: Optional requirements file to install from
95
+ project: Optional project directory to run within
96
 
97
  Returns:
98
  True if installation was successful, False otherwise
 
109
  # Build uv run command
110
  args = ["run"]
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"}
122
  if with_packages:
 
129
  if with_editable:
130
  args.extend(["--with-editable", str(with_editable)])
131
 
132
+ if with_requirements:
133
+ args.extend(["--with-requirements", str(with_requirements)])
134
+
135
  # Build server spec from parsed components
136
  if server_object:
137
  server_spec = f"{file.resolve()}:{server_object}"
 
207
  help="Load environment variables from .env file",
208
  ),
209
  ] = None,
210
+ python: Annotated[
211
+ str | None,
212
+ cyclopts.Parameter(
213
+ "--python",
214
+ help="Python version to use (e.g., 3.10, 3.11)",
215
+ ),
216
+ ] = None,
217
+ with_requirements: Annotated[
218
+ Path | None,
219
+ cyclopts.Parameter(
220
+ "--with-requirements",
221
+ help="Requirements file to install dependencies from",
222
+ ),
223
+ ] = None,
224
+ project: Annotated[
225
+ Path | None,
226
+ cyclopts.Parameter(
227
+ "--project",
228
+ help="Run the command within the given project directory",
229
+ ),
230
+ ] = None,
231
  ) -> None:
232
  """Install an MCP server in Claude Code.
233
 
 
245
  with_editable=with_editable,
246
  with_packages=packages,
247
  env_vars=env_dict,
248
+ python_version=python,
249
+ with_requirements=with_requirements,
250
+ project=project,
251
  )
252
 
253
  if success:
src/fastmcp/cli/install/claude_desktop.py CHANGED
@@ -42,6 +42,9 @@ def install_claude_desktop(
42
  with_editable: Path | None = None,
43
  with_packages: list[str] | None = None,
44
  env_vars: dict[str, str] | None = None,
 
 
 
45
  ) -> bool:
46
  """Install FastMCP server in Claude Desktop.
47
 
@@ -52,6 +55,9 @@ def install_claude_desktop(
52
  with_editable: Optional directory to install in editable mode
53
  with_packages: Optional list of additional packages to install
54
  env_vars: Optional dictionary of environment variables
 
 
 
55
 
56
  Returns:
57
  True if installation was successful, False otherwise
@@ -69,6 +75,14 @@ def install_claude_desktop(
69
  # Build uv run command
70
  args = ["run"]
71
 
 
 
 
 
 
 
 
 
72
  # Collect all packages in a set to deduplicate
73
  packages = {"fastmcp"}
74
  if with_packages:
@@ -81,6 +95,9 @@ def install_claude_desktop(
81
  if with_editable:
82
  args.extend(["--with-editable", str(with_editable)])
83
 
 
 
 
84
  # Build server spec from parsed components
85
  if server_object:
86
  server_spec = f"{file.resolve()}:{server_object}"
@@ -163,6 +180,27 @@ def claude_desktop_command(
163
  help="Load environment variables from .env file",
164
  ),
165
  ] = None,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  ) -> None:
167
  """Install an MCP server in Claude Desktop.
168
 
@@ -180,6 +218,9 @@ def claude_desktop_command(
180
  with_editable=with_editable,
181
  with_packages=with_packages,
182
  env_vars=env_dict,
 
 
 
183
  )
184
 
185
  if not success:
 
42
  with_editable: Path | None = None,
43
  with_packages: list[str] | None = None,
44
  env_vars: dict[str, str] | None = None,
45
+ python_version: str | None = None,
46
+ with_requirements: Path | None = None,
47
+ project: Path | None = None,
48
  ) -> bool:
49
  """Install FastMCP server in Claude Desktop.
50
 
 
55
  with_editable: Optional directory to install in editable mode
56
  with_packages: Optional list of additional packages to install
57
  env_vars: Optional dictionary of environment variables
58
+ python_version: Optional Python version to use
59
+ with_requirements: Optional requirements file to install from
60
+ project: Optional project directory to run within
61
 
62
  Returns:
63
  True if installation was successful, False otherwise
 
75
  # Build uv run command
76
  args = ["run"]
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"}
88
  if with_packages:
 
95
  if with_editable:
96
  args.extend(["--with-editable", str(with_editable)])
97
 
98
+ if with_requirements:
99
+ args.extend(["--with-requirements", str(with_requirements)])
100
+
101
  # Build server spec from parsed components
102
  if server_object:
103
  server_spec = f"{file.resolve()}:{server_object}"
 
180
  help="Load environment variables from .env file",
181
  ),
182
  ] = None,
183
+ python: Annotated[
184
+ str | None,
185
+ cyclopts.Parameter(
186
+ "--python",
187
+ help="Python version to use (e.g., 3.10, 3.11)",
188
+ ),
189
+ ] = None,
190
+ with_requirements: Annotated[
191
+ Path | None,
192
+ cyclopts.Parameter(
193
+ "--with-requirements",
194
+ help="Requirements file to install dependencies from",
195
+ ),
196
+ ] = None,
197
+ project: Annotated[
198
+ Path | None,
199
+ cyclopts.Parameter(
200
+ "--project",
201
+ help="Run the command within the given project directory",
202
+ ),
203
+ ] = None,
204
  ) -> None:
205
  """Install an MCP server in Claude Desktop.
206
 
 
218
  with_editable=with_editable,
219
  with_packages=with_packages,
220
  env_vars=env_dict,
221
+ python_version=python,
222
+ with_requirements=with_requirements,
223
+ project=project,
224
  )
225
 
226
  if not success:
src/fastmcp/cli/install/cursor.py CHANGED
@@ -72,6 +72,9 @@ def install_cursor(
72
  with_editable: Path | None = None,
73
  with_packages: list[str] | None = None,
74
  env_vars: dict[str, str] | None = None,
 
 
 
75
  ) -> bool:
76
  """Install FastMCP server in Cursor.
77
 
@@ -82,6 +85,9 @@ def install_cursor(
82
  with_editable: Optional directory to install in editable mode
83
  with_packages: Optional list of additional packages to install
84
  env_vars: Optional dictionary of environment variables
 
 
 
85
 
86
  Returns:
87
  True if installation was successful, False otherwise
@@ -89,6 +95,14 @@ def install_cursor(
89
  # Build uv run command
90
  args = ["run"]
91
 
 
 
 
 
 
 
 
 
92
  # Collect all packages in a set to deduplicate
93
  packages = {"fastmcp"}
94
  if with_packages:
@@ -101,6 +115,9 @@ def install_cursor(
101
  if with_editable:
102
  args.extend(["--with-editable", str(with_editable)])
103
 
 
 
 
104
  # Build server spec from parsed components
105
  if server_object:
106
  server_spec = f"{file.resolve()}:{server_object}"
@@ -173,6 +190,27 @@ def cursor_command(
173
  help="Load environment variables from .env file",
174
  ),
175
  ] = None,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  ) -> None:
177
  """Install an MCP server in Cursor.
178
 
@@ -190,6 +228,9 @@ def cursor_command(
190
  with_editable=with_editable,
191
  with_packages=with_packages,
192
  env_vars=env_dict,
 
 
 
193
  )
194
 
195
  if not success:
 
72
  with_editable: Path | None = None,
73
  with_packages: list[str] | None = None,
74
  env_vars: dict[str, str] | None = None,
75
+ python_version: str | None = None,
76
+ with_requirements: Path | None = None,
77
+ project: Path | None = None,
78
  ) -> bool:
79
  """Install FastMCP server in Cursor.
80
 
 
85
  with_editable: Optional directory to install in editable mode
86
  with_packages: Optional list of additional packages to install
87
  env_vars: Optional dictionary of environment variables
88
+ python_version: Optional Python version to use
89
+ with_requirements: Optional requirements file to install from
90
+ project: Optional project directory to run within
91
 
92
  Returns:
93
  True if installation was successful, False otherwise
 
95
  # Build uv run command
96
  args = ["run"]
97
 
98
+ # Add Python version if specified
99
+ if python_version:
100
+ args.extend(["--python", python_version])
101
+
102
+ # Add project if specified
103
+ if project:
104
+ args.extend(["--project", str(project)])
105
+
106
  # Collect all packages in a set to deduplicate
107
  packages = {"fastmcp"}
108
  if with_packages:
 
115
  if with_editable:
116
  args.extend(["--with-editable", str(with_editable)])
117
 
118
+ if with_requirements:
119
+ args.extend(["--with-requirements", str(with_requirements)])
120
+
121
  # Build server spec from parsed components
122
  if server_object:
123
  server_spec = f"{file.resolve()}:{server_object}"
 
190
  help="Load environment variables from .env file",
191
  ),
192
  ] = None,
193
+ python: Annotated[
194
+ str | None,
195
+ cyclopts.Parameter(
196
+ "--python",
197
+ help="Python version to use (e.g., 3.10, 3.11)",
198
+ ),
199
+ ] = None,
200
+ with_requirements: Annotated[
201
+ Path | None,
202
+ cyclopts.Parameter(
203
+ "--with-requirements",
204
+ help="Requirements file to install dependencies from",
205
+ ),
206
+ ] = None,
207
+ project: Annotated[
208
+ Path | None,
209
+ cyclopts.Parameter(
210
+ "--project",
211
+ help="Run the command within the given project directory",
212
+ ),
213
+ ] = None,
214
  ) -> None:
215
  """Install an MCP server in Cursor.
216
 
 
228
  with_editable=with_editable,
229
  with_packages=with_packages,
230
  env_vars=env_dict,
231
+ python_version=python,
232
+ with_requirements=with_requirements,
233
+ project=project,
234
  )
235
 
236
  if not success:
src/fastmcp/cli/install/mcp_json.py CHANGED
@@ -25,6 +25,9 @@ def install_mcp_json(
25
  with_packages: list[str] | None = None,
26
  env_vars: dict[str, str] | None = None,
27
  copy: bool = False,
 
 
 
28
  ) -> bool:
29
  """Generate MCP configuration JSON for manual installation.
30
 
@@ -36,6 +39,9 @@ def install_mcp_json(
36
  with_packages: Optional list of additional packages to install
37
  env_vars: Optional dictionary of environment variables
38
  copy: If True, copy to clipboard instead of printing to stdout
 
 
 
39
 
40
  Returns:
41
  True if generation was successful, False otherwise
@@ -44,6 +50,14 @@ def install_mcp_json(
44
  # Build uv run command
45
  args = ["run"]
46
 
 
 
 
 
 
 
 
 
47
  # Collect all packages in a set to deduplicate
48
  packages = {"fastmcp"}
49
  if with_packages:
@@ -56,6 +70,9 @@ def install_mcp_json(
56
  if with_editable:
57
  args.extend(["--with-editable", str(with_editable)])
58
 
 
 
 
59
  # Build server spec from parsed components
60
  if server_object:
61
  server_spec = f"{file.resolve()}:{server_object}"
@@ -144,6 +161,27 @@ def mcp_json_command(
144
  negative=False,
145
  ),
146
  ] = False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  ) -> None:
148
  """Generate MCP configuration JSON for manual installation.
149
 
@@ -162,6 +200,9 @@ def mcp_json_command(
162
  with_packages=packages,
163
  env_vars=env_dict,
164
  copy=copy,
 
 
 
165
  )
166
 
167
  if not success:
 
25
  with_packages: list[str] | None = None,
26
  env_vars: dict[str, str] | None = None,
27
  copy: bool = False,
28
+ python_version: str | None = None,
29
+ with_requirements: Path | None = None,
30
+ project: Path | None = None,
31
  ) -> bool:
32
  """Generate MCP configuration JSON for manual installation.
33
 
 
39
  with_packages: Optional list of additional packages to install
40
  env_vars: Optional dictionary of environment variables
41
  copy: If True, copy to clipboard instead of printing to stdout
42
+ python_version: Optional Python version to use
43
+ with_requirements: Optional requirements file to install from
44
+ project: Optional project directory to run within
45
 
46
  Returns:
47
  True if generation was successful, False otherwise
 
50
  # Build uv run command
51
  args = ["run"]
52
 
53
+ # Add Python version if specified
54
+ if python_version:
55
+ args.extend(["--python", python_version])
56
+
57
+ # Add project if specified
58
+ if project:
59
+ args.extend(["--project", str(project)])
60
+
61
  # Collect all packages in a set to deduplicate
62
  packages = {"fastmcp"}
63
  if with_packages:
 
70
  if with_editable:
71
  args.extend(["--with-editable", str(with_editable)])
72
 
73
+ if with_requirements:
74
+ args.extend(["--with-requirements", str(with_requirements)])
75
+
76
  # Build server spec from parsed components
77
  if server_object:
78
  server_spec = f"{file.resolve()}:{server_object}"
 
161
  negative=False,
162
  ),
163
  ] = False,
164
+ python: Annotated[
165
+ str | None,
166
+ cyclopts.Parameter(
167
+ "--python",
168
+ help="Python version to use (e.g., 3.10, 3.11)",
169
+ ),
170
+ ] = None,
171
+ with_requirements: Annotated[
172
+ Path | None,
173
+ cyclopts.Parameter(
174
+ "--with-requirements",
175
+ help="Requirements file to install dependencies from",
176
+ ),
177
+ ] = None,
178
+ project: Annotated[
179
+ Path | None,
180
+ cyclopts.Parameter(
181
+ "--project",
182
+ help="Run the command within the given project directory",
183
+ ),
184
+ ] = None,
185
  ) -> None:
186
  """Generate MCP configuration JSON for manual installation.
187
 
 
200
  with_packages=packages,
201
  env_vars=env_dict,
202
  copy=copy,
203
+ python_version=python,
204
+ with_requirements=with_requirements,
205
+ project=project,
206
  )
207
 
208
  if not success:
src/fastmcp/cli/run.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  import importlib.util
4
  import re
 
5
  import sys
6
  from pathlib import Path
7
  from typing import Any, Literal
@@ -122,6 +123,84 @@ def import_server(file: Path, server_object: str | None = None) -> Any:
122
  return server
123
 
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  def create_client_server(url: str) -> Any:
126
  """Create a FastMCP server from a client URL.
127
 
@@ -175,6 +254,7 @@ def run_command(
175
  log_level: LogLevelType | None = None,
176
  server_args: list[str] | None = None,
177
  show_banner: bool = True,
 
178
  ) -> None:
179
  """Run a MCP server or connect to a remote one.
180
 
@@ -187,6 +267,7 @@ def run_command(
187
  log_level: Log level
188
  server_args: Additional arguments to pass to the server
189
  show_banner: Whether to show the server banner
 
190
  """
191
  if is_url(server_spec):
192
  # Handle URL case
 
2
 
3
  import importlib.util
4
  import re
5
+ import subprocess
6
  import sys
7
  from pathlib import Path
8
  from typing import Any, Literal
 
123
  return server
124
 
125
 
126
+ def run_with_uv(
127
+ server_spec: str,
128
+ python_version: str | None = None,
129
+ with_packages: list[str] | None = None,
130
+ with_requirements: Path | None = None,
131
+ project: Path | None = None,
132
+ transport: TransportType | None = None,
133
+ host: str | None = None,
134
+ port: int | None = None,
135
+ path: str | None = None,
136
+ log_level: LogLevelType | None = None,
137
+ show_banner: bool = True,
138
+ ) -> None:
139
+ """Run a MCP server using uv run subprocess.
140
+
141
+ Args:
142
+ server_spec: Python file, object specification (file:obj), or URL
143
+ python_version: Python version to use (e.g. "3.10")
144
+ with_packages: Additional packages to install
145
+ with_requirements: Requirements file to use
146
+ project: Run the command within the given project directory
147
+ transport: Transport protocol to use
148
+ host: Host to bind to when using http transport
149
+ port: Port to bind to when using http transport
150
+ path: Path to bind to when using http transport
151
+ log_level: Log level
152
+ show_banner: Whether to show the server banner
153
+ """
154
+ cmd = ["uv", "run"]
155
+
156
+ # Add Python version if specified
157
+ if python_version:
158
+ cmd.extend(["--python", python_version])
159
+
160
+ # Add project if specified
161
+ if project:
162
+ cmd.extend(["--project", str(project)])
163
+
164
+ # Add fastmcp package
165
+ cmd.extend(["--with", "fastmcp"])
166
+
167
+ # Add additional packages
168
+ if with_packages:
169
+ for pkg in with_packages:
170
+ if pkg:
171
+ cmd.extend(["--with", pkg])
172
+
173
+ # Add requirements file
174
+ if with_requirements:
175
+ cmd.extend(["--with-requirements", str(with_requirements)])
176
+
177
+ # Add fastmcp run command
178
+ cmd.extend(["fastmcp", "run", server_spec])
179
+
180
+ # Add transport options
181
+ if transport:
182
+ cmd.extend(["--transport", transport])
183
+ if host:
184
+ cmd.extend(["--host", host])
185
+ if port:
186
+ cmd.extend(["--port", str(port)])
187
+ if path:
188
+ cmd.extend(["--path", path])
189
+ if log_level:
190
+ cmd.extend(["--log-level", log_level])
191
+ if not show_banner:
192
+ cmd.append("--no-banner")
193
+
194
+ # Run the command
195
+ logger.debug(f"Running command: {' '.join(cmd)}")
196
+ try:
197
+ process = subprocess.run(cmd, check=True)
198
+ sys.exit(process.returncode)
199
+ except subprocess.CalledProcessError as e:
200
+ logger.error(f"Failed to run server: {e}")
201
+ sys.exit(e.returncode)
202
+
203
+
204
  def create_client_server(url: str) -> Any:
205
  """Create a FastMCP server from a client URL.
206
 
 
254
  log_level: LogLevelType | None = None,
255
  server_args: list[str] | None = None,
256
  show_banner: bool = True,
257
+ use_direct_import: bool = False,
258
  ) -> None:
259
  """Run a MCP server or connect to a remote one.
260
 
 
267
  log_level: Log level
268
  server_args: Additional arguments to pass to the server
269
  show_banner: Whether to show the server banner
270
+ use_direct_import: Whether to use direct import instead of subprocess
271
  """
272
  if is_url(server_spec):
273
  # Handle URL case
tests/cli/test_cli.py CHANGED
@@ -90,6 +90,94 @@ class TestMainCLI:
90
  ]
91
  assert cmd == expected
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
  class TestVersionCommand:
95
  """Test the version command."""
@@ -167,6 +255,29 @@ class TestDevCommand:
167
  assert bound.arguments["inspector_version"] == "1.0.0"
168
  assert bound.arguments["ui_port"] == 3000
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  class TestRunCommand:
172
  """Test the run command."""
@@ -236,6 +347,32 @@ class TestRunCommand:
236
  assert "log_level" not in bound.arguments
237
  assert "path" not in bound.arguments
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  def test_run_command_transport_aliases(self):
240
  """Test that both 'http' and 'streamable-http' are accepted as valid transport options."""
241
  # Test with 'http' transport
 
90
  ]
91
  assert cmd == expected
92
 
93
+ def test_build_uv_command_with_python_version(self):
94
+ """Test building uv command with Python version."""
95
+ cmd = _build_uv_command("server.py", python_version="3.11")
96
+ expected = [
97
+ "uv",
98
+ "run",
99
+ "--python",
100
+ "3.11",
101
+ "--with",
102
+ "fastmcp",
103
+ "fastmcp",
104
+ "run",
105
+ "server.py",
106
+ ]
107
+ assert cmd == expected
108
+
109
+ def test_build_uv_command_with_project(self):
110
+ """Test building uv command with project directory."""
111
+ project_path = Path("/path/to/project")
112
+ cmd = _build_uv_command("server.py", project=project_path)
113
+ expected = [
114
+ "uv",
115
+ "run",
116
+ "--project",
117
+ str(project_path),
118
+ "--with",
119
+ "fastmcp",
120
+ "fastmcp",
121
+ "run",
122
+ "server.py",
123
+ ]
124
+ assert cmd == expected
125
+
126
+ def test_build_uv_command_with_requirements(self):
127
+ """Test building uv command with requirements file."""
128
+ req_path = Path("requirements.txt")
129
+ cmd = _build_uv_command("server.py", with_requirements=req_path)
130
+ expected = [
131
+ "uv",
132
+ "run",
133
+ "--with",
134
+ "fastmcp",
135
+ "--with-requirements",
136
+ "requirements.txt",
137
+ "fastmcp",
138
+ "run",
139
+ "server.py",
140
+ ]
141
+ assert cmd == expected
142
+
143
+ def test_build_uv_command_with_all_options(self):
144
+ """Test building uv command with all options."""
145
+ project_path = Path("/my/project")
146
+ editable_path = Path("/local/pkg")
147
+ requirements_path = Path("reqs.txt")
148
+ cmd = _build_uv_command(
149
+ "server.py",
150
+ python_version="3.10",
151
+ project=project_path,
152
+ with_packages=["pandas", "numpy"],
153
+ with_requirements=requirements_path,
154
+ with_editable=editable_path,
155
+ no_banner=True,
156
+ )
157
+ expected = [
158
+ "uv",
159
+ "run",
160
+ "--python",
161
+ "3.10",
162
+ "--project",
163
+ str(project_path),
164
+ "--with",
165
+ "fastmcp",
166
+ "--with-editable",
167
+ str(editable_path),
168
+ "--with",
169
+ "pandas",
170
+ "--with",
171
+ "numpy",
172
+ "--with-requirements",
173
+ str(requirements_path),
174
+ "fastmcp",
175
+ "run",
176
+ "server.py",
177
+ "--no-banner",
178
+ ]
179
+ assert cmd == expected
180
+
181
 
182
  class TestVersionCommand:
183
  """Test the version command."""
 
255
  assert bound.arguments["inspector_version"] == "1.0.0"
256
  assert bound.arguments["ui_port"] == 3000
257
 
258
+ def test_dev_command_parsing_with_new_options(self):
259
+ """Test dev command parsing with new uv options."""
260
+ command, bound, _ = app.parse_args(
261
+ [
262
+ "dev",
263
+ "server.py",
264
+ "--python",
265
+ "3.10",
266
+ "--project",
267
+ "/workspace",
268
+ "--with-requirements",
269
+ "dev-requirements.txt",
270
+ "--with",
271
+ "pytest",
272
+ ]
273
+ )
274
+ assert command is not None
275
+ assert bound.arguments["server_spec"] == "server.py"
276
+ assert bound.arguments["python"] == "3.10"
277
+ assert bound.arguments["project"] == Path("/workspace")
278
+ assert bound.arguments["with_requirements"] == Path("dev-requirements.txt")
279
+ assert bound.arguments["with_packages"] == ["pytest"]
280
+
281
 
282
  class TestRunCommand:
283
  """Test the run command."""
 
347
  assert "log_level" not in bound.arguments
348
  assert "path" not in bound.arguments
349
 
350
+ def test_run_command_parsing_with_new_options(self):
351
+ """Test run command parsing with new uv options."""
352
+ command, bound, _ = app.parse_args(
353
+ [
354
+ "run",
355
+ "server.py",
356
+ "--python",
357
+ "3.11",
358
+ "--with",
359
+ "pandas",
360
+ "--with",
361
+ "numpy",
362
+ "--project",
363
+ "/path/to/project",
364
+ "--with-requirements",
365
+ "requirements.txt",
366
+ ]
367
+ )
368
+
369
+ assert command is not None
370
+ assert bound.arguments["server_spec"] == "server.py"
371
+ assert bound.arguments["python"] == "3.11"
372
+ assert bound.arguments["with_packages"] == ["pandas", "numpy"]
373
+ assert bound.arguments["project"] == Path("/path/to/project")
374
+ assert bound.arguments["with_requirements"] == Path("requirements.txt")
375
+
376
  def test_run_command_transport_aliases(self):
377
  """Test that both 'http' and 'streamable-http' are accepted as valid transport options."""
378
  # Test with 'http' transport
tests/cli/test_cursor.py CHANGED
@@ -327,6 +327,9 @@ class TestCursorCommand:
327
  with_editable=None,
328
  with_packages=[],
329
  env_vars={},
 
 
 
330
  )
331
  mock_exit.assert_not_called()
332
 
 
327
  with_editable=None,
328
  with_packages=[],
329
  env_vars={},
330
+ python_version=None,
331
+ with_requirements=None,
332
+ project=None,
333
  )
334
  mock_exit.assert_not_called()
335
 
tests/cli/test_install.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  from fastmcp.cli.install import install_app
2
 
3
 
@@ -63,6 +65,27 @@ class TestClaudeCodeInstall:
63
  assert bound.arguments["with_packages"] == ["package1", "package2"]
64
  assert bound.arguments["env_vars"] == ["VAR1=value1"]
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  class TestClaudeDesktopInstall:
68
  """Test claude-desktop install command."""
@@ -94,6 +117,27 @@ class TestClaudeDesktopInstall:
94
 
95
  assert bound.arguments["env_vars"] == ["VAR1=value1", "VAR2=value2"]
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  class TestCursorInstall:
99
  """Test cursor install command."""
@@ -163,3 +207,45 @@ class TestInstallCommandParsing:
163
  command, bound, _ = install_app.parse_args(["mcp-json", "server.py"])
164
  assert command is not None
165
  assert bound.arguments["server_spec"] == "server.py"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
  from fastmcp.cli.install import install_app
4
 
5
 
 
65
  assert bound.arguments["with_packages"] == ["package1", "package2"]
66
  assert bound.arguments["env_vars"] == ["VAR1=value1"]
67
 
68
+ def test_claude_code_with_new_options(self):
69
+ """Test claude-code install with new uv options."""
70
+ from pathlib import Path
71
+
72
+ command, bound, _ = install_app.parse_args(
73
+ [
74
+ "claude-code",
75
+ "server.py",
76
+ "--python",
77
+ "3.11",
78
+ "--project",
79
+ "/workspace",
80
+ "--with-requirements",
81
+ "requirements.txt",
82
+ ]
83
+ )
84
+
85
+ assert bound.arguments["python"] == "3.11"
86
+ assert bound.arguments["project"] == Path("/workspace")
87
+ assert bound.arguments["with_requirements"] == Path("requirements.txt")
88
+
89
 
90
  class TestClaudeDesktopInstall:
91
  """Test claude-desktop install command."""
 
117
 
118
  assert bound.arguments["env_vars"] == ["VAR1=value1", "VAR2=value2"]
119
 
120
+ def test_claude_desktop_with_new_options(self):
121
+ """Test claude-desktop install with new uv options."""
122
+ from pathlib import Path
123
+
124
+ command, bound, _ = install_app.parse_args(
125
+ [
126
+ "claude-desktop",
127
+ "server.py",
128
+ "--python",
129
+ "3.10",
130
+ "--project",
131
+ "/my/project",
132
+ "--with-requirements",
133
+ "reqs.txt",
134
+ ]
135
+ )
136
+
137
+ assert bound.arguments["python"] == "3.10"
138
+ assert bound.arguments["project"] == Path("/my/project")
139
+ assert bound.arguments["with_requirements"] == Path("reqs.txt")
140
+
141
 
142
  class TestCursorInstall:
143
  """Test cursor install command."""
 
207
  command, bound, _ = install_app.parse_args(["mcp-json", "server.py"])
208
  assert command is not None
209
  assert bound.arguments["server_spec"] == "server.py"
210
+
211
+ def test_python_option(self):
212
+ """Test --python option for all install commands."""
213
+ commands_to_test = [
214
+ ["claude-code", "server.py", "--python", "3.11"],
215
+ ["claude-desktop", "server.py", "--python", "3.11"],
216
+ ["cursor", "server.py", "--python", "3.11"],
217
+ ["mcp-json", "server.py", "--python", "3.11"],
218
+ ]
219
+
220
+ for cmd_args in commands_to_test:
221
+ command, bound, _ = install_app.parse_args(cmd_args)
222
+ assert command is not None
223
+ assert bound.arguments["python"] == "3.11"
224
+
225
+ def test_with_requirements_option(self):
226
+ """Test --with-requirements option for all install commands."""
227
+ commands_to_test = [
228
+ ["claude-code", "server.py", "--with-requirements", "requirements.txt"],
229
+ ["claude-desktop", "server.py", "--with-requirements", "requirements.txt"],
230
+ ["cursor", "server.py", "--with-requirements", "requirements.txt"],
231
+ ["mcp-json", "server.py", "--with-requirements", "requirements.txt"],
232
+ ]
233
+
234
+ for cmd_args in commands_to_test:
235
+ command, bound, _ = install_app.parse_args(cmd_args)
236
+ assert command is not None
237
+ assert str(bound.arguments["with_requirements"]) == "requirements.txt"
238
+
239
+ def test_project_option(self):
240
+ """Test --project option for all install commands."""
241
+ commands_to_test = [
242
+ ["claude-code", "server.py", "--project", "/path/to/project"],
243
+ ["claude-desktop", "server.py", "--project", "/path/to/project"],
244
+ ["cursor", "server.py", "--project", "/path/to/project"],
245
+ ["mcp-json", "server.py", "--project", "/path/to/project"],
246
+ ]
247
+
248
+ for cmd_args in commands_to_test:
249
+ command, bound, _ = install_app.parse_args(cmd_args)
250
+ assert command is not None
251
+ assert str(bound.arguments["project"]) == str(Path("/path/to/project"))
tests/cli/test_run_with_uv.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for the run_with_uv function and related functionality."""
2
+
3
+ import subprocess
4
+ from pathlib import Path
5
+ from unittest.mock import Mock, patch
6
+
7
+ import pytest
8
+
9
+ from fastmcp.cli.run import run_with_uv
10
+
11
+
12
+ class TestRunWithUv:
13
+ """Test the run_with_uv function."""
14
+
15
+ @patch("subprocess.run")
16
+ def test_run_with_uv_basic(self, mock_run):
17
+ """Test basic run_with_uv execution."""
18
+ mock_run.return_value = Mock(returncode=0)
19
+
20
+ with pytest.raises(SystemExit) as exc_info:
21
+ run_with_uv("server.py")
22
+
23
+ assert exc_info.value.code == 0
24
+
25
+ # Check the command that was called
26
+ mock_run.assert_called_once()
27
+ cmd = mock_run.call_args[0][0]
28
+
29
+ expected = ["uv", "run", "--with", "fastmcp", "fastmcp", "run", "server.py"]
30
+ assert cmd == expected
31
+
32
+ @patch("subprocess.run")
33
+ def test_run_with_uv_python_version(self, mock_run):
34
+ """Test run_with_uv with Python version."""
35
+ mock_run.return_value = Mock(returncode=0)
36
+
37
+ with pytest.raises(SystemExit) as exc_info:
38
+ run_with_uv("server.py", python_version="3.11")
39
+
40
+ assert exc_info.value.code == 0
41
+
42
+ cmd = mock_run.call_args[0][0]
43
+ expected = [
44
+ "uv",
45
+ "run",
46
+ "--python",
47
+ "3.11",
48
+ "--with",
49
+ "fastmcp",
50
+ "fastmcp",
51
+ "run",
52
+ "server.py",
53
+ ]
54
+ assert cmd == expected
55
+
56
+ @patch("subprocess.run")
57
+ def test_run_with_uv_project(self, mock_run):
58
+ """Test run_with_uv with project directory."""
59
+ mock_run.return_value = Mock(returncode=0)
60
+ project_path = Path("/my/project")
61
+
62
+ with pytest.raises(SystemExit) as exc_info:
63
+ run_with_uv("server.py", project=project_path)
64
+
65
+ assert exc_info.value.code == 0
66
+
67
+ cmd = mock_run.call_args[0][0]
68
+ expected = [
69
+ "uv",
70
+ "run",
71
+ "--project",
72
+ str(Path("/my/project")),
73
+ "--with",
74
+ "fastmcp",
75
+ "fastmcp",
76
+ "run",
77
+ "server.py",
78
+ ]
79
+ assert cmd == expected
80
+
81
+ @patch("subprocess.run")
82
+ def test_run_with_uv_with_packages(self, mock_run):
83
+ """Test run_with_uv with additional packages."""
84
+ mock_run.return_value = Mock(returncode=0)
85
+
86
+ with pytest.raises(SystemExit) as exc_info:
87
+ run_with_uv("server.py", with_packages=["pandas", "numpy"])
88
+
89
+ assert exc_info.value.code == 0
90
+
91
+ cmd = mock_run.call_args[0][0]
92
+ expected = [
93
+ "uv",
94
+ "run",
95
+ "--with",
96
+ "fastmcp",
97
+ "--with",
98
+ "pandas",
99
+ "--with",
100
+ "numpy",
101
+ "fastmcp",
102
+ "run",
103
+ "server.py",
104
+ ]
105
+ assert cmd == expected
106
+
107
+ @patch("subprocess.run")
108
+ def test_run_with_uv_with_requirements(self, mock_run):
109
+ """Test run_with_uv with requirements file."""
110
+ mock_run.return_value = Mock(returncode=0)
111
+ req_path = Path("requirements.txt")
112
+
113
+ with pytest.raises(SystemExit) as exc_info:
114
+ run_with_uv("server.py", with_requirements=req_path)
115
+
116
+ assert exc_info.value.code == 0
117
+
118
+ cmd = mock_run.call_args[0][0]
119
+ expected = [
120
+ "uv",
121
+ "run",
122
+ "--with",
123
+ "fastmcp",
124
+ "--with-requirements",
125
+ "requirements.txt",
126
+ "fastmcp",
127
+ "run",
128
+ "server.py",
129
+ ]
130
+ assert cmd == expected
131
+
132
+ @patch("subprocess.run")
133
+ def test_run_with_uv_transport_options(self, mock_run):
134
+ """Test run_with_uv with transport-related options."""
135
+ mock_run.return_value = Mock(returncode=0)
136
+
137
+ with pytest.raises(SystemExit) as exc_info:
138
+ run_with_uv(
139
+ "server.py",
140
+ transport="http",
141
+ host="localhost",
142
+ port=8080,
143
+ path="/api",
144
+ log_level="DEBUG",
145
+ show_banner=False,
146
+ )
147
+
148
+ assert exc_info.value.code == 0
149
+
150
+ cmd = mock_run.call_args[0][0]
151
+ expected = [
152
+ "uv",
153
+ "run",
154
+ "--with",
155
+ "fastmcp",
156
+ "fastmcp",
157
+ "run",
158
+ "server.py",
159
+ "--transport",
160
+ "http",
161
+ "--host",
162
+ "localhost",
163
+ "--port",
164
+ "8080",
165
+ "--path",
166
+ "/api",
167
+ "--log-level",
168
+ "DEBUG",
169
+ "--no-banner",
170
+ ]
171
+ assert cmd == expected
172
+
173
+ @patch("subprocess.run")
174
+ def test_run_with_uv_all_options(self, mock_run):
175
+ """Test run_with_uv with all options combined."""
176
+ mock_run.return_value = Mock(returncode=0)
177
+
178
+ with pytest.raises(SystemExit) as exc_info:
179
+ run_with_uv(
180
+ "server.py",
181
+ python_version="3.10",
182
+ project=Path("/workspace"),
183
+ with_packages=["pandas"],
184
+ with_requirements=Path("reqs.txt"),
185
+ transport="http",
186
+ port=9000,
187
+ show_banner=False,
188
+ )
189
+
190
+ assert exc_info.value.code == 0
191
+
192
+ cmd = mock_run.call_args[0][0]
193
+ expected = [
194
+ "uv",
195
+ "run",
196
+ "--python",
197
+ "3.10",
198
+ "--project",
199
+ str(Path("/workspace")),
200
+ "--with",
201
+ "fastmcp",
202
+ "--with",
203
+ "pandas",
204
+ "--with-requirements",
205
+ "reqs.txt",
206
+ "fastmcp",
207
+ "run",
208
+ "server.py",
209
+ "--transport",
210
+ "http",
211
+ "--port",
212
+ "9000",
213
+ "--no-banner",
214
+ ]
215
+ assert cmd == expected
216
+
217
+ @patch("subprocess.run")
218
+ def test_run_with_uv_error_handling(self, mock_run):
219
+ """Test run_with_uv error handling."""
220
+ mock_run.side_effect = subprocess.CalledProcessError(1, ["uv", "run"])
221
+
222
+ with pytest.raises(SystemExit) as exc_info:
223
+ run_with_uv("server.py")
224
+
225
+ assert exc_info.value.code == 1
226
+
227
+ @patch("fastmcp.cli.run.logger")
228
+ @patch("subprocess.run")
229
+ def test_run_with_uv_logging(self, mock_run, mock_logger):
230
+ """Test that run_with_uv logs the command."""
231
+ mock_run.return_value = Mock(returncode=0)
232
+
233
+ with pytest.raises(SystemExit):
234
+ run_with_uv("server.py", python_version="3.11")
235
+
236
+ # Check that debug logging was called with the command
237
+ mock_logger.debug.assert_called()
238
+ call_args = mock_logger.debug.call_args[0][0]
239
+ assert "Running command:" in call_args
240
+ assert "uv run --python 3.11" in call_args