fastmcp 0.3.2__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. {fastmcp-0.3.2 → fastmcp-0.3.3}/.github/workflows/run-tests.yml +11 -0
  2. {fastmcp-0.3.2 → fastmcp-0.3.3}/.gitignore +1 -0
  3. {fastmcp-0.3.2 → fastmcp-0.3.3}/PKG-INFO +173 -62
  4. {fastmcp-0.3.2 → fastmcp-0.3.3}/README.md +172 -61
  5. {fastmcp-0.3.2 → fastmcp-0.3.3}/examples/screenshot.py +8 -8
  6. fastmcp-0.3.3/examples/text_me.py +71 -0
  7. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/cli/claude.py +10 -6
  8. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/cli/cli.py +15 -12
  9. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/server.py +7 -0
  10. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/test_cli.py +118 -42
  11. {fastmcp-0.3.2 → fastmcp-0.3.3}/.github/ai-labeler.yml +0 -0
  12. {fastmcp-0.3.2 → fastmcp-0.3.3}/.github/release.yml +0 -0
  13. {fastmcp-0.3.2 → fastmcp-0.3.3}/.github/workflows/ai-labeler.yml +0 -0
  14. {fastmcp-0.3.2 → fastmcp-0.3.3}/.github/workflows/lint.yml +0 -0
  15. {fastmcp-0.3.2 → fastmcp-0.3.3}/.github/workflows/publish.yml +0 -0
  16. {fastmcp-0.3.2 → fastmcp-0.3.3}/.pre-commit-config.yaml +0 -0
  17. {fastmcp-0.3.2 → fastmcp-0.3.3}/.python-version +0 -0
  18. {fastmcp-0.3.2 → fastmcp-0.3.3}/LICENSE +0 -0
  19. {fastmcp-0.3.2 → fastmcp-0.3.3}/docs/assets/demo-inspector.png +0 -0
  20. {fastmcp-0.3.2 → fastmcp-0.3.3}/examples/desktop.py +0 -0
  21. {fastmcp-0.3.2 → fastmcp-0.3.3}/examples/echo.py +0 -0
  22. {fastmcp-0.3.2 → fastmcp-0.3.3}/examples/readme-quickstart.py +0 -0
  23. {fastmcp-0.3.2 → fastmcp-0.3.3}/examples/simple_echo.py +0 -0
  24. {fastmcp-0.3.2 → fastmcp-0.3.3}/pyproject.toml +0 -0
  25. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/__init__.py +0 -0
  26. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/cli/__init__.py +0 -0
  27. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/exceptions.py +0 -0
  28. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/prompts/__init__.py +0 -0
  29. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/prompts/base.py +0 -0
  30. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/prompts/manager.py +0 -0
  31. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/prompts/prompt_manager.py +0 -0
  32. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/resources/__init__.py +0 -0
  33. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/resources/base.py +0 -0
  34. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/resources/resource_manager.py +0 -0
  35. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/resources/templates.py +0 -0
  36. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/resources/types.py +0 -0
  37. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/tools/__init__.py +0 -0
  38. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/tools/base.py +0 -0
  39. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/tools/tool_manager.py +0 -0
  40. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/utilities/__init__.py +0 -0
  41. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/utilities/logging.py +0 -0
  42. {fastmcp-0.3.2 → fastmcp-0.3.3}/src/fastmcp/utilities/types.py +0 -0
  43. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/__init__.py +0 -0
  44. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/prompts/__init__.py +0 -0
  45. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/prompts/test_base.py +0 -0
  46. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/prompts/test_manager.py +0 -0
  47. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/resources/__init__.py +0 -0
  48. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/resources/test_file_resources.py +0 -0
  49. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/resources/test_function_resources.py +0 -0
  50. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/resources/test_resource_manager.py +0 -0
  51. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/resources/test_resource_template.py +0 -0
  52. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/resources/test_resources.py +0 -0
  53. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/servers/__init__.py +0 -0
  54. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/servers/test_file_server.py +0 -0
  55. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/test_server.py +0 -0
  56. {fastmcp-0.3.2 → fastmcp-0.3.3}/tests/test_tool_manager.py +0 -0
  57. {fastmcp-0.3.2 → fastmcp-0.3.3}/uv.lock +0 -0
@@ -7,7 +7,18 @@ env:
7
7
  on:
8
8
  push:
9
9
  branches: ["main"]
10
+ paths:
11
+ - "src/**"
12
+ - "tests/**"
13
+ - "uv.lock"
14
+ - "pyproject.toml"
10
15
  pull_request:
16
+ paths:
17
+ - "src/**"
18
+ - "tests/**"
19
+ - "uv.lock"
20
+ - "pyproject.toml"
21
+
11
22
  workflow_dispatch:
12
23
 
13
24
  permissions:
@@ -9,6 +9,7 @@ wheels/
9
9
  # Virtual environments
10
10
  .venv
11
11
  .DS_Store
12
+ .env
12
13
 
13
14
 
14
15
  src/fastmcp/_version.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastmcp
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: A more ergonomic interface for MCP servers
5
5
  Author: Jeremiah Lowin
6
6
  License: Apache-2.0
@@ -27,11 +27,12 @@ Description-Content-Type: text/markdown
27
27
 
28
28
  <div align="center">
29
29
 
30
+ <strong>The fast, Pythonic way to build MCP servers.</strong>
31
+
30
32
  [![PyPI - Version](https://img.shields.io/pypi/v/fastmcp.svg)](https://pypi.org/project/fastmcp)
31
33
  [![Tests](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml/badge.svg)](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml)
32
34
  [![License](https://img.shields.io/github/license/jlowin/fastmcp.svg)](https://github.com/jlowin/fastmcp/blob/main/LICENSE)
33
35
 
34
- The fast, Pythonic way to build MCP servers
35
36
 
36
37
  </div>
37
38
 
@@ -85,24 +86,33 @@ FastMCP handles all the complex protocol details and server management, so you c
85
86
  - [Prompts](#prompts)
86
87
  - [Images](#images)
87
88
  - [Context](#context)
88
- - [Deployment](#deployment)
89
- - [Development](#development)
90
- - [Environment Variables](#environment-variables)
91
- - [Claude Desktop](#claude-desktop)
92
- - [Environment Variables](#environment-variables-1)
89
+ - [Running Your Server](#running-your-server)
90
+ - [Development Mode (Recommended for Building \& Testing)](#development-mode-recommended-for-building--testing)
91
+ - [Claude Desktop Integration (For Regular Use)](#claude-desktop-integration-for-regular-use)
92
+ - [Direct Execution (For Advanced Use Cases)](#direct-execution-for-advanced-use-cases)
93
+ - [Server Object Names](#server-object-names)
93
94
  - [Examples](#examples)
94
95
  - [Echo Server](#echo-server)
95
96
  - [SQLite Explorer](#sqlite-explorer)
97
+ - [Contributing](#contributing)
98
+ - [Prerequisites](#prerequisites)
99
+ - [Installation](#installation-1)
100
+ - [Testing](#testing)
101
+ - [Formatting](#formatting)
102
+ - [Opening a Pull Request](#opening-a-pull-request)
96
103
 
97
104
  ## Installation
98
105
 
106
+ We strongly recommend installing FastMCP with [uv](https://docs.astral.sh/uv/), as it is required for deploying servers:
107
+
99
108
  ```bash
100
- # We strongly recommend installing with uv
101
- brew install uv # on macOS
102
109
  uv pip install fastmcp
103
110
  ```
104
111
 
105
- Or with pip:
112
+ Note: on macOS, uv may need to be installed with Homebrew (`brew install uv`) in order to make it available to the Claude Desktop app.
113
+
114
+ Alternatively, to use the SDK without deploying, you may use pip:
115
+
106
116
  ```bash
107
117
  pip install fastmcp
108
118
  ```
@@ -173,8 +183,10 @@ mcp = FastMCP("My App")
173
183
 
174
184
  # Configure host/port for HTTP transport (optional)
175
185
  mcp = FastMCP("My App", host="localhost", port=8000)
186
+
187
+ # Specify dependencies for deployment and development
188
+ mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
176
189
  ```
177
- *Note: All of the following code examples assume you've created a FastMCP server instance called `mcp`, as shown above.*
178
190
 
179
191
  ### Resources
180
192
 
@@ -303,84 +315,101 @@ The Context object provides:
303
315
  - Resource access through `read_resource()`
304
316
  - Request metadata via `request_id` and `client_id`
305
317
 
306
- ## Deployment
318
+ ## Running Your Server
307
319
 
308
- The FastMCP CLI helps you develop and deploy MCP servers.
320
+ There are three main ways to use your FastMCP server, each suited for different stages of development:
309
321
 
310
- Note that for all deployment commands, you are expected to provide the fully qualified path to your server object. For example, if you have a file `server.py` that contains a FastMCP server named `my_server`, you would provide `path/to/server.py:my_server`.
322
+ ### Development Mode (Recommended for Building & Testing)
311
323
 
312
- If your server variable has one of the standard names (`mcp`, `server`, or `app`), you can omit the server name from the path and just provide the file: `path/to/server.py`.
324
+ The fastest way to test and debug your server is with the MCP Inspector:
313
325
 
314
- ### Development
315
-
316
- Test and debug your server with the MCP Inspector:
317
326
  ```bash
318
- # Provide the fully qualified path to your server
319
- fastmcp dev server.py:my_mcp_server
320
-
321
- # Or just the file if your server is named 'mcp', 'server', or 'app'
322
327
  fastmcp dev server.py
323
328
  ```
324
329
 
325
- Your server is run in an isolated environment, so you'll need to indicate any dependencies with the `--with` flag. FastMCP is automatically included. If you are working on a uv project, you can use the `--with-editable` flag to mount your current directory:
326
-
327
- ```bash
328
- # With additional packages
329
- fastmcp dev server.py --with pandas --with numpy
330
-
331
- # Using your project's dependencies and up-to-date code
332
- fastmcp dev server.py --with-editable .
333
- ```
330
+ This launches a web interface where you can:
331
+ - Test your tools and resources interactively
332
+ - See detailed logs and error messages
333
+ - Monitor server performance
334
+ - Set environment variables for testing
334
335
 
335
- #### Environment Variables
336
+ During development, you can:
337
+ - Add dependencies with `--with`:
338
+ ```bash
339
+ fastmcp dev server.py --with pandas --with numpy
340
+ ```
341
+ - Mount your local code for live updates:
342
+ ```bash
343
+ fastmcp dev server.py --with-editable .
344
+ ```
336
345
 
337
- The MCP Inspector runs servers in an isolated environment. Environment variables must be set through the Inspector UI and are not inherited from your system. The Inspector does not currently support setting environment variables via command line (see [Issue #94](https://github.com/modelcontextprotocol/inspector/issues/94)).
346
+ ### Claude Desktop Integration (For Regular Use)
338
347
 
339
- ### Claude Desktop
348
+ Once your server is ready, install it in Claude Desktop to use it with Claude:
340
349
 
341
- Install your server in Claude Desktop:
342
350
  ```bash
343
- # Basic usage (name is taken from your FastMCP instance)
344
351
  fastmcp install server.py
352
+ ```
345
353
 
346
- # With a custom name
347
- fastmcp install server.py --name "My Server"
354
+ Your server will run in an isolated environment with:
355
+ - Automatic installation of dependencies specified in your FastMCP instance:
356
+ ```python
357
+ mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
358
+ ```
359
+ - Custom naming via `--name`:
360
+ ```bash
361
+ fastmcp install server.py --name "My Analytics Server"
362
+ ```
363
+ - Environment variable management:
364
+ ```bash
365
+ # Set variables individually
366
+ fastmcp install server.py -e API_KEY=abc123 -e DB_URL=postgres://...
367
+
368
+ # Or load from a .env file
369
+ fastmcp install server.py -f .env
370
+ ```
371
+
372
+ ### Direct Execution (For Advanced Use Cases)
373
+
374
+ For advanced scenarios like custom deployments or running without Claude, you can execute your server directly:
348
375
 
349
- # With dependencies
350
- fastmcp install server.py --with pandas --with numpy
376
+ ```python
377
+ from fastmcp import FastMCP
378
+
379
+ mcp = FastMCP("My App")
380
+
381
+ if __name__ == "__main__":
382
+ mcp.run()
351
383
  ```
352
384
 
353
- The server name in Claude will be:
354
- 1. The `--name` parameter if provided
355
- 2. The `name` from your FastMCP instance
356
- 3. The filename if the server can't be imported
385
+ Run it with:
386
+ ```bash
387
+ # Using the FastMCP CLI
388
+ fastmcp run server.py
357
389
 
358
- #### Environment Variables
390
+ # Or with Python/uv directly
391
+ python server.py
392
+ uv run python server.py
393
+ ```
359
394
 
360
- Claude Desktop runs servers in an isolated environment. Environment variables from your system are NOT automatically available to the server - you must explicitly provide them during installation:
361
395
 
362
- ```bash
363
- # Single env var
364
- fastmcp install server.py -e API_KEY=abc123
396
+ Note: When running directly, you are responsible for ensuring all dependencies are available in your environment. Any dependencies specified on the FastMCP instance are ignored.
365
397
 
366
- # Multiple env vars
367
- fastmcp install server.py -e API_KEY=abc123 -e OTHER_VAR=value
398
+ Choose this method when you need:
399
+ - Custom deployment configurations
400
+ - Integration with other services
401
+ - Direct control over the server lifecycle
368
402
 
369
- # Load from .env file
370
- fastmcp install server.py -f .env
371
- ```
403
+ ### Server Object Names
372
404
 
373
- Environment variables persist across reinstalls and are only updated when new values are provided:
405
+ All FastMCP commands will look for a server object called `mcp`, `app`, or `server` in your file. If you have a different object name or multiple servers in one file, use the syntax `server.py:my_server`:
374
406
 
375
407
  ```bash
376
- # First install
377
- fastmcp install server.py -e FOO=bar -e BAZ=123
408
+ # Using a standard name
409
+ fastmcp run server.py
378
410
 
379
- # Second install - FOO and BAZ are preserved
380
- fastmcp install server.py -e NEW=value
381
-
382
- # Third install - FOO gets new value, others preserved
383
- fastmcp install server.py -e FOO=newvalue
411
+ # Using a custom name
412
+ fastmcp run server.py:my_custom_server
384
413
  ```
385
414
 
386
415
  ## Examples
@@ -449,3 +478,85 @@ Schema:
449
478
 
450
479
  What insights can you provide about the structure and relationships?"""
451
480
  ```
481
+
482
+ ## Contributing
483
+
484
+ <details>
485
+
486
+ <summary><h3>Open Developer Guide</h3></summary>
487
+
488
+ ### Prerequisites
489
+
490
+ FastMCP requires Python 3.10+ and [uv](https://docs.astral.sh/uv/).
491
+
492
+ ### Installation
493
+
494
+ Create a fork of this repository, then clone it:
495
+
496
+ ```bash
497
+ git clone https://github.com/YouFancyUserYou/fastmcp.git
498
+ cd fastmcp
499
+ ```
500
+
501
+ Next, create a virtual environment and install FastMCP:
502
+
503
+ ```bash
504
+ uv venv
505
+ source .venv/bin/activate
506
+ uv sync --frozen --all-extras --dev
507
+ ```
508
+
509
+
510
+
511
+ ### Testing
512
+
513
+ Please make sure to test any new functionality. Your tests should be simple and atomic and anticipate change rather than cement complex patterns.
514
+
515
+ Run tests from the root directory:
516
+
517
+
518
+ ```bash
519
+ pytest -vv
520
+ ```
521
+
522
+ ### Formatting
523
+
524
+ FastMCP enforces a variety of required formats, which you can automatically enforce with pre-commit.
525
+
526
+ Install the pre-commit hooks:
527
+
528
+ ```bash
529
+ pre-commit install
530
+ ```
531
+
532
+ The hooks will now run on every commit (as well as on every PR). To run them manually:
533
+
534
+ ```bash
535
+ pre-commit run --all-files
536
+ ```
537
+
538
+ ### Opening a Pull Request
539
+
540
+ Fork the repository and create a new branch:
541
+
542
+ ```bash
543
+ git checkout -b my-branch
544
+ ```
545
+
546
+ Make your changes and commit them:
547
+
548
+
549
+ ```bash
550
+ git add . && git commit -m "My changes"
551
+ ```
552
+
553
+ Push your changes to your fork:
554
+
555
+
556
+ ```bash
557
+ git push origin my-branch
558
+ ```
559
+
560
+ Feel free to reach out in a GitHub issue or discussion if you have any questions!
561
+
562
+ </details>
@@ -3,11 +3,12 @@
3
3
 
4
4
  <div align="center">
5
5
 
6
+ <strong>The fast, Pythonic way to build MCP servers.</strong>
7
+
6
8
  [![PyPI - Version](https://img.shields.io/pypi/v/fastmcp.svg)](https://pypi.org/project/fastmcp)
7
9
  [![Tests](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml/badge.svg)](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml)
8
10
  [![License](https://img.shields.io/github/license/jlowin/fastmcp.svg)](https://github.com/jlowin/fastmcp/blob/main/LICENSE)
9
11
 
10
- The fast, Pythonic way to build MCP servers
11
12
 
12
13
  </div>
13
14
 
@@ -61,24 +62,33 @@ FastMCP handles all the complex protocol details and server management, so you c
61
62
  - [Prompts](#prompts)
62
63
  - [Images](#images)
63
64
  - [Context](#context)
64
- - [Deployment](#deployment)
65
- - [Development](#development)
66
- - [Environment Variables](#environment-variables)
67
- - [Claude Desktop](#claude-desktop)
68
- - [Environment Variables](#environment-variables-1)
65
+ - [Running Your Server](#running-your-server)
66
+ - [Development Mode (Recommended for Building \& Testing)](#development-mode-recommended-for-building--testing)
67
+ - [Claude Desktop Integration (For Regular Use)](#claude-desktop-integration-for-regular-use)
68
+ - [Direct Execution (For Advanced Use Cases)](#direct-execution-for-advanced-use-cases)
69
+ - [Server Object Names](#server-object-names)
69
70
  - [Examples](#examples)
70
71
  - [Echo Server](#echo-server)
71
72
  - [SQLite Explorer](#sqlite-explorer)
73
+ - [Contributing](#contributing)
74
+ - [Prerequisites](#prerequisites)
75
+ - [Installation](#installation-1)
76
+ - [Testing](#testing)
77
+ - [Formatting](#formatting)
78
+ - [Opening a Pull Request](#opening-a-pull-request)
72
79
 
73
80
  ## Installation
74
81
 
82
+ We strongly recommend installing FastMCP with [uv](https://docs.astral.sh/uv/), as it is required for deploying servers:
83
+
75
84
  ```bash
76
- # We strongly recommend installing with uv
77
- brew install uv # on macOS
78
85
  uv pip install fastmcp
79
86
  ```
80
87
 
81
- Or with pip:
88
+ Note: on macOS, uv may need to be installed with Homebrew (`brew install uv`) in order to make it available to the Claude Desktop app.
89
+
90
+ Alternatively, to use the SDK without deploying, you may use pip:
91
+
82
92
  ```bash
83
93
  pip install fastmcp
84
94
  ```
@@ -149,8 +159,10 @@ mcp = FastMCP("My App")
149
159
 
150
160
  # Configure host/port for HTTP transport (optional)
151
161
  mcp = FastMCP("My App", host="localhost", port=8000)
162
+
163
+ # Specify dependencies for deployment and development
164
+ mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
152
165
  ```
153
- *Note: All of the following code examples assume you've created a FastMCP server instance called `mcp`, as shown above.*
154
166
 
155
167
  ### Resources
156
168
 
@@ -279,84 +291,101 @@ The Context object provides:
279
291
  - Resource access through `read_resource()`
280
292
  - Request metadata via `request_id` and `client_id`
281
293
 
282
- ## Deployment
294
+ ## Running Your Server
283
295
 
284
- The FastMCP CLI helps you develop and deploy MCP servers.
296
+ There are three main ways to use your FastMCP server, each suited for different stages of development:
285
297
 
286
- Note that for all deployment commands, you are expected to provide the fully qualified path to your server object. For example, if you have a file `server.py` that contains a FastMCP server named `my_server`, you would provide `path/to/server.py:my_server`.
298
+ ### Development Mode (Recommended for Building & Testing)
287
299
 
288
- If your server variable has one of the standard names (`mcp`, `server`, or `app`), you can omit the server name from the path and just provide the file: `path/to/server.py`.
300
+ The fastest way to test and debug your server is with the MCP Inspector:
289
301
 
290
- ### Development
291
-
292
- Test and debug your server with the MCP Inspector:
293
302
  ```bash
294
- # Provide the fully qualified path to your server
295
- fastmcp dev server.py:my_mcp_server
296
-
297
- # Or just the file if your server is named 'mcp', 'server', or 'app'
298
303
  fastmcp dev server.py
299
304
  ```
300
305
 
301
- Your server is run in an isolated environment, so you'll need to indicate any dependencies with the `--with` flag. FastMCP is automatically included. If you are working on a uv project, you can use the `--with-editable` flag to mount your current directory:
302
-
303
- ```bash
304
- # With additional packages
305
- fastmcp dev server.py --with pandas --with numpy
306
-
307
- # Using your project's dependencies and up-to-date code
308
- fastmcp dev server.py --with-editable .
309
- ```
306
+ This launches a web interface where you can:
307
+ - Test your tools and resources interactively
308
+ - See detailed logs and error messages
309
+ - Monitor server performance
310
+ - Set environment variables for testing
310
311
 
311
- #### Environment Variables
312
+ During development, you can:
313
+ - Add dependencies with `--with`:
314
+ ```bash
315
+ fastmcp dev server.py --with pandas --with numpy
316
+ ```
317
+ - Mount your local code for live updates:
318
+ ```bash
319
+ fastmcp dev server.py --with-editable .
320
+ ```
312
321
 
313
- The MCP Inspector runs servers in an isolated environment. Environment variables must be set through the Inspector UI and are not inherited from your system. The Inspector does not currently support setting environment variables via command line (see [Issue #94](https://github.com/modelcontextprotocol/inspector/issues/94)).
322
+ ### Claude Desktop Integration (For Regular Use)
314
323
 
315
- ### Claude Desktop
324
+ Once your server is ready, install it in Claude Desktop to use it with Claude:
316
325
 
317
- Install your server in Claude Desktop:
318
326
  ```bash
319
- # Basic usage (name is taken from your FastMCP instance)
320
327
  fastmcp install server.py
328
+ ```
321
329
 
322
- # With a custom name
323
- fastmcp install server.py --name "My Server"
330
+ Your server will run in an isolated environment with:
331
+ - Automatic installation of dependencies specified in your FastMCP instance:
332
+ ```python
333
+ mcp = FastMCP("My App", dependencies=["pandas", "numpy"])
334
+ ```
335
+ - Custom naming via `--name`:
336
+ ```bash
337
+ fastmcp install server.py --name "My Analytics Server"
338
+ ```
339
+ - Environment variable management:
340
+ ```bash
341
+ # Set variables individually
342
+ fastmcp install server.py -e API_KEY=abc123 -e DB_URL=postgres://...
343
+
344
+ # Or load from a .env file
345
+ fastmcp install server.py -f .env
346
+ ```
347
+
348
+ ### Direct Execution (For Advanced Use Cases)
349
+
350
+ For advanced scenarios like custom deployments or running without Claude, you can execute your server directly:
324
351
 
325
- # With dependencies
326
- fastmcp install server.py --with pandas --with numpy
352
+ ```python
353
+ from fastmcp import FastMCP
354
+
355
+ mcp = FastMCP("My App")
356
+
357
+ if __name__ == "__main__":
358
+ mcp.run()
327
359
  ```
328
360
 
329
- The server name in Claude will be:
330
- 1. The `--name` parameter if provided
331
- 2. The `name` from your FastMCP instance
332
- 3. The filename if the server can't be imported
361
+ Run it with:
362
+ ```bash
363
+ # Using the FastMCP CLI
364
+ fastmcp run server.py
333
365
 
334
- #### Environment Variables
366
+ # Or with Python/uv directly
367
+ python server.py
368
+ uv run python server.py
369
+ ```
335
370
 
336
- Claude Desktop runs servers in an isolated environment. Environment variables from your system are NOT automatically available to the server - you must explicitly provide them during installation:
337
371
 
338
- ```bash
339
- # Single env var
340
- fastmcp install server.py -e API_KEY=abc123
372
+ Note: When running directly, you are responsible for ensuring all dependencies are available in your environment. Any dependencies specified on the FastMCP instance are ignored.
341
373
 
342
- # Multiple env vars
343
- fastmcp install server.py -e API_KEY=abc123 -e OTHER_VAR=value
374
+ Choose this method when you need:
375
+ - Custom deployment configurations
376
+ - Integration with other services
377
+ - Direct control over the server lifecycle
344
378
 
345
- # Load from .env file
346
- fastmcp install server.py -f .env
347
- ```
379
+ ### Server Object Names
348
380
 
349
- Environment variables persist across reinstalls and are only updated when new values are provided:
381
+ All FastMCP commands will look for a server object called `mcp`, `app`, or `server` in your file. If you have a different object name or multiple servers in one file, use the syntax `server.py:my_server`:
350
382
 
351
383
  ```bash
352
- # First install
353
- fastmcp install server.py -e FOO=bar -e BAZ=123
384
+ # Using a standard name
385
+ fastmcp run server.py
354
386
 
355
- # Second install - FOO and BAZ are preserved
356
- fastmcp install server.py -e NEW=value
357
-
358
- # Third install - FOO gets new value, others preserved
359
- fastmcp install server.py -e FOO=newvalue
387
+ # Using a custom name
388
+ fastmcp run server.py:my_custom_server
360
389
  ```
361
390
 
362
391
  ## Examples
@@ -425,3 +454,85 @@ Schema:
425
454
 
426
455
  What insights can you provide about the structure and relationships?"""
427
456
  ```
457
+
458
+ ## Contributing
459
+
460
+ <details>
461
+
462
+ <summary><h3>Open Developer Guide</h3></summary>
463
+
464
+ ### Prerequisites
465
+
466
+ FastMCP requires Python 3.10+ and [uv](https://docs.astral.sh/uv/).
467
+
468
+ ### Installation
469
+
470
+ Create a fork of this repository, then clone it:
471
+
472
+ ```bash
473
+ git clone https://github.com/YouFancyUserYou/fastmcp.git
474
+ cd fastmcp
475
+ ```
476
+
477
+ Next, create a virtual environment and install FastMCP:
478
+
479
+ ```bash
480
+ uv venv
481
+ source .venv/bin/activate
482
+ uv sync --frozen --all-extras --dev
483
+ ```
484
+
485
+
486
+
487
+ ### Testing
488
+
489
+ Please make sure to test any new functionality. Your tests should be simple and atomic and anticipate change rather than cement complex patterns.
490
+
491
+ Run tests from the root directory:
492
+
493
+
494
+ ```bash
495
+ pytest -vv
496
+ ```
497
+
498
+ ### Formatting
499
+
500
+ FastMCP enforces a variety of required formats, which you can automatically enforce with pre-commit.
501
+
502
+ Install the pre-commit hooks:
503
+
504
+ ```bash
505
+ pre-commit install
506
+ ```
507
+
508
+ The hooks will now run on every commit (as well as on every PR). To run them manually:
509
+
510
+ ```bash
511
+ pre-commit run --all-files
512
+ ```
513
+
514
+ ### Opening a Pull Request
515
+
516
+ Fork the repository and create a new branch:
517
+
518
+ ```bash
519
+ git checkout -b my-branch
520
+ ```
521
+
522
+ Make your changes and commit them:
523
+
524
+
525
+ ```bash
526
+ git add . && git commit -m "My changes"
527
+ ```
528
+
529
+ Push your changes to your fork:
530
+
531
+
532
+ ```bash
533
+ git push origin my-branch
534
+ ```
535
+
536
+ Feel free to reach out in a GitHub issue or discussion if you have any questions!
537
+
538
+ </details>
@@ -1,7 +1,3 @@
1
- # /// script
2
- # dependencies = ["fastmcp", "pyautogui", "Pillow"]
3
- # ///
4
-
5
1
  """
6
2
  FastMCP Screenshot Example
7
3
 
@@ -9,20 +5,24 @@ Give Claude a tool to capture and view screenshots.
9
5
  """
10
6
 
11
7
  import io
12
-
13
8
  from fastmcp import FastMCP, Image
14
9
 
10
+
15
11
  # Create server
16
- mcp = FastMCP("Screenshot Demo")
12
+ mcp = FastMCP("Screenshot Demo", dependencies=["pyautogui", "Pillow"])
17
13
 
18
14
 
19
15
  @mcp.tool()
20
16
  def take_screenshot() -> Image:
21
- """Take a screenshot of the user's screen and return it as an image"""
17
+ """
18
+ Take a screenshot of the user's screen and return it as an image. Use
19
+ this tool anytime the user wants you to look at something they're doing.
20
+ """
22
21
  import pyautogui
23
22
 
24
- screenshot = pyautogui.screenshot()
25
23
  buffer = io.BytesIO()
24
+
26
25
  # if the file exceeds ~1MB, it will be rejected by Claude
26
+ screenshot = pyautogui.screenshot()
27
27
  screenshot.convert("RGB").save(buffer, format="JPEG", quality=60, optimize=True)
28
28
  return Image(data=buffer.getvalue(), format="jpeg")
@@ -0,0 +1,71 @@
1
+ # /// script
2
+ # dependencies = ["fastmcp"]
3
+ # ///
4
+
5
+ """
6
+ FastMCP Text Me Server
7
+ --------------------------------
8
+ This defines a simple FastMCP server that sends a text message to a phone number via https://surgemsg.com/.
9
+
10
+ To run this example, create a `.env` file with the following values:
11
+
12
+ SURGE_API_KEY=...
13
+ SURGE_ACCOUNT_ID=...
14
+ SURGE_MY_PHONE_NUMBER=...
15
+ SURGE_MY_FIRST_NAME=...
16
+ SURGE_MY_LAST_NAME=...
17
+
18
+ Visit https://surgemsg.com/ and click "Get Started" to obtain these values.
19
+ """
20
+
21
+ from typing import Annotated
22
+ import httpx
23
+ from pydantic import BeforeValidator
24
+ from pydantic_settings import BaseSettings, SettingsConfigDict
25
+
26
+ from fastmcp import FastMCP
27
+
28
+
29
+ class SurgeSettings(BaseSettings):
30
+ model_config: SettingsConfigDict = SettingsConfigDict(
31
+ env_prefix="SURGE_", env_file=".env"
32
+ )
33
+
34
+ api_key: str
35
+ account_id: str
36
+ my_phone_number: Annotated[
37
+ str, BeforeValidator(lambda v: "+" + v if not v.startswith("+") else v)
38
+ ]
39
+ my_first_name: str
40
+ my_last_name: str
41
+
42
+
43
+ # Create server
44
+ mcp = FastMCP("Text me")
45
+ surge_settings = SurgeSettings() # type: ignore
46
+
47
+
48
+ @mcp.tool(name="textme", description="Send a text message to me")
49
+ def text_me(text_content: str) -> str:
50
+ """Send a text message to a phone number via https://surgemsg.com/"""
51
+ with httpx.Client() as client:
52
+ response = client.post(
53
+ "https://api.surgemsg.com/messages",
54
+ headers={
55
+ "Authorization": f"Bearer {surge_settings.api_key}",
56
+ "Surge-Account": surge_settings.account_id,
57
+ "Content-Type": "application/json",
58
+ },
59
+ json={
60
+ "body": text_content,
61
+ "conversation": {
62
+ "contact": {
63
+ "first_name": surge_settings.my_first_name,
64
+ "last_name": surge_settings.my_last_name,
65
+ "phone_number": surge_settings.my_phone_number,
66
+ }
67
+ },
68
+ },
69
+ )
70
+ response.raise_for_status()
71
+ return f"Message sent: {text_content}"
@@ -68,16 +68,20 @@ def update_claude_config(
68
68
  env_vars = existing_env
69
69
 
70
70
  # Build uv run command
71
- args = ["run", "--with", "fastmcp"]
71
+ args = ["run"]
72
+
73
+ # Collect all packages in a set to deduplicate
74
+ packages = {"fastmcp"}
75
+ if with_packages:
76
+ packages.update(pkg for pkg in with_packages if pkg)
77
+
78
+ # Add all packages with --with
79
+ for pkg in sorted(packages):
80
+ args.extend(["--with", pkg])
72
81
 
73
82
  if with_editable:
74
83
  args.extend(["--with-editable", str(with_editable)])
75
84
 
76
- if with_packages:
77
- for pkg in with_packages:
78
- if pkg:
79
- args.extend(["--with", pkg])
80
-
81
85
  # Convert file path to absolute before adding to command
82
86
  # Split off any :object suffix first
83
87
  if ":" in file_spec:
@@ -193,6 +193,11 @@ def dev(
193
193
  )
194
194
 
195
195
  try:
196
+ # Import server to get dependencies
197
+ server = _import_server(file, server_object)
198
+ if hasattr(server, "dependencies"):
199
+ with_packages = list(set(with_packages + server.dependencies))
200
+
196
201
  uv_cmd = _build_uv_command(file_spec, with_editable, with_packages)
197
202
  # Run the MCP Inspector command
198
203
  process = subprocess.run(
@@ -232,23 +237,16 @@ def run(
232
237
  help="Transport protocol to use (stdio or sse)",
233
238
  ),
234
239
  ] = None,
235
- with_editable: Annotated[
236
- Optional[Path],
237
- typer.Option(
238
- "--with-editable",
239
- "-e",
240
- help="Directory containing pyproject.toml to install in editable mode",
241
- exists=True,
242
- file_okay=False,
243
- resolve_path=True,
244
- ),
245
- ] = None,
246
240
  ) -> None:
247
241
  """Run a FastMCP server.
248
242
 
249
243
  The server can be specified in two ways:
250
244
  1. Module approach: server.py - runs the module directly, expecting a server.run() call
251
245
  2. Import approach: server.py:app - imports and runs the specified server object
246
+
247
+ Note: This command runs the server directly. You are responsible for ensuring
248
+ all dependencies are available. For dependency management, use fastmcp install
249
+ or fastmcp dev instead.
252
250
  """
253
251
  file, server_object = _parse_file_path(file_spec)
254
252
 
@@ -258,7 +256,6 @@ def run(
258
256
  "file": str(file),
259
257
  "server_object": server_object,
260
258
  "transport": transport,
261
- "with_editable": str(with_editable) if with_editable else None,
262
259
  },
263
260
  )
264
261
 
@@ -361,6 +358,7 @@ def install(
361
358
 
362
359
  # Try to import server to get its name, but fall back to file name if dependencies missing
363
360
  name = server_name
361
+ server = None
364
362
  if not name:
365
363
  try:
366
364
  server = _import_server(file, server_object)
@@ -372,6 +370,11 @@ def install(
372
370
  )
373
371
  name = file.stem
374
372
 
373
+ # Get server dependencies if available
374
+ server_dependencies = getattr(server, "dependencies", []) if server else []
375
+ if server_dependencies:
376
+ with_packages = list(set(with_packages + server_dependencies))
377
+
375
378
  # Process environment variables if provided
376
379
  env_dict: Optional[Dict[str, str]] = None
377
380
  if env_file or env_vars:
@@ -9,6 +9,7 @@ from itertools import chain
9
9
  from typing import Any, Callable, Dict, Literal, Sequence
10
10
 
11
11
  import pydantic_core
12
+ from pydantic import Field
12
13
  import uvicorn
13
14
  from mcp.server import Server as MCPServer
14
15
  from mcp.server.sse import SseServerTransport
@@ -76,6 +77,11 @@ class Settings(BaseSettings):
76
77
  # prompt settings
77
78
  warn_on_duplicate_prompts: bool = True
78
79
 
80
+ dependencies: list[str] = Field(
81
+ default_factory=list,
82
+ description="List of dependencies to install in the server environment",
83
+ )
84
+
79
85
 
80
86
  class FastMCP:
81
87
  def __init__(self, name: str | None = None, **settings: Any):
@@ -90,6 +96,7 @@ class FastMCP:
90
96
  self._prompt_manager = PromptManager(
91
97
  warn_on_duplicate_prompts=self.settings.warn_on_duplicate_prompts
92
98
  )
99
+ self.dependencies = self.settings.dependencies
93
100
 
94
101
  # Set up MCP protocol handlers
95
102
  self._setup_handlers()
@@ -1,7 +1,7 @@
1
1
  """Tests for the FastMCP CLI."""
2
2
 
3
3
  import json
4
- from unittest.mock import Mock, patch
4
+ from unittest.mock import patch
5
5
 
6
6
  import pytest
7
7
  from typer.testing import CliRunner
@@ -19,11 +19,13 @@ def mock_config(tmp_path):
19
19
 
20
20
 
21
21
  @pytest.fixture
22
- def mock_server_file(tmp_path):
23
- """Create a mock server file."""
22
+ def server_file(tmp_path):
23
+ """Create a server file."""
24
24
  server_file = tmp_path / "server.py"
25
25
  server_file.write_text(
26
- "from fastmcp import Server\n" "server = Server(name='test')\n"
26
+ """from fastmcp import FastMCP
27
+ mcp = FastMCP("test")
28
+ """
27
29
  )
28
30
  return server_file
29
31
 
@@ -67,22 +69,16 @@ def test_parse_env_var():
67
69
  ),
68
70
  ],
69
71
  )
70
- def test_install_with_env_vars(mock_config, mock_server_file, args, expected_env):
72
+ def test_install_with_env_vars(mock_config, server_file, args, expected_env):
71
73
  """Test installing with environment variables."""
72
74
  runner = CliRunner()
73
75
 
74
- with (
75
- patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
76
- patch("fastmcp.cli.cli._import_server") as mock_import,
77
- ):
76
+ with patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path:
78
77
  mock_config_path.return_value = mock_config.parent
79
- mock_server = Mock()
80
- mock_server.name = "test" # Set name as an attribute
81
- mock_import.return_value = mock_server
82
78
 
83
79
  result = runner.invoke(
84
80
  app,
85
- ["install", str(mock_server_file)] + args,
81
+ ["install", str(server_file)] + args,
86
82
  )
87
83
 
88
84
  assert result.exit_code == 0
@@ -95,22 +91,16 @@ def test_install_with_env_vars(mock_config, mock_server_file, args, expected_env
95
91
  assert server["env"] == expected_env
96
92
 
97
93
 
98
- def test_install_with_env_file(mock_config, mock_server_file, mock_env_file):
94
+ def test_install_with_env_file(mock_config, server_file, mock_env_file):
99
95
  """Test installing with environment variables from a file."""
100
96
  runner = CliRunner()
101
97
 
102
- with (
103
- patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
104
- patch("fastmcp.cli.cli._import_server") as mock_import,
105
- ):
98
+ with patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path:
106
99
  mock_config_path.return_value = mock_config.parent
107
- mock_server = Mock()
108
- mock_server.name = "test" # Set name as an attribute
109
- mock_import.return_value = mock_server
110
100
 
111
101
  result = runner.invoke(
112
102
  app,
113
- ["install", str(mock_server_file), "--env-file", str(mock_env_file)],
103
+ ["install", str(server_file), "--env-file", str(mock_env_file)],
114
104
  )
115
105
 
116
106
  assert result.exit_code == 0
@@ -123,7 +113,7 @@ def test_install_with_env_file(mock_config, mock_server_file, mock_env_file):
123
113
  assert server["env"] == {"FOO": "bar", "BAZ": "123"}
124
114
 
125
115
 
126
- def test_install_preserves_existing_env_vars(mock_config, mock_server_file):
116
+ def test_install_preserves_existing_env_vars(mock_config, server_file):
127
117
  """Test that installing preserves existing environment variables."""
128
118
  # Set up initial config with env vars
129
119
  config = {
@@ -136,7 +126,7 @@ def test_install_preserves_existing_env_vars(mock_config, mock_server_file):
136
126
  "fastmcp",
137
127
  "fastmcp",
138
128
  "run",
139
- str(mock_server_file),
129
+ str(server_file),
140
130
  ],
141
131
  "env": {"FOO": "bar", "BAZ": "123"},
142
132
  }
@@ -146,19 +136,13 @@ def test_install_preserves_existing_env_vars(mock_config, mock_server_file):
146
136
 
147
137
  runner = CliRunner()
148
138
 
149
- with (
150
- patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
151
- patch("fastmcp.cli.cli._import_server") as mock_import,
152
- ):
139
+ with patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path:
153
140
  mock_config_path.return_value = mock_config.parent
154
- mock_server = Mock()
155
- mock_server.name = "test" # Set name as an attribute
156
- mock_import.return_value = mock_server
157
141
 
158
142
  # Install with a new env var
159
143
  result = runner.invoke(
160
144
  app,
161
- ["install", str(mock_server_file), "--env-var", "NEW=value"],
145
+ ["install", str(server_file), "--env-var", "NEW=value"],
162
146
  )
163
147
 
164
148
  assert result.exit_code == 0
@@ -169,7 +153,7 @@ def test_install_preserves_existing_env_vars(mock_config, mock_server_file):
169
153
  assert server["env"] == {"FOO": "bar", "BAZ": "123", "NEW": "value"}
170
154
 
171
155
 
172
- def test_install_updates_existing_env_vars(mock_config, mock_server_file):
156
+ def test_install_updates_existing_env_vars(mock_config, server_file):
173
157
  """Test that installing updates existing environment variables."""
174
158
  # Set up initial config with env vars
175
159
  config = {
@@ -182,7 +166,7 @@ def test_install_updates_existing_env_vars(mock_config, mock_server_file):
182
166
  "fastmcp",
183
167
  "fastmcp",
184
168
  "run",
185
- str(mock_server_file),
169
+ str(server_file),
186
170
  ],
187
171
  "env": {"FOO": "bar", "BAZ": "123"},
188
172
  }
@@ -192,19 +176,13 @@ def test_install_updates_existing_env_vars(mock_config, mock_server_file):
192
176
 
193
177
  runner = CliRunner()
194
178
 
195
- with (
196
- patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
197
- patch("fastmcp.cli.cli._import_server") as mock_import,
198
- ):
179
+ with patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path:
199
180
  mock_config_path.return_value = mock_config.parent
200
- mock_server = Mock()
201
- mock_server.name = "test" # Set name as an attribute
202
- mock_import.return_value = mock_server
203
181
 
204
182
  # Update an existing env var
205
183
  result = runner.invoke(
206
184
  app,
207
- ["install", str(mock_server_file), "--env-var", "FOO=newvalue"],
185
+ ["install", str(server_file), "--env-var", "FOO=newvalue"],
208
186
  )
209
187
 
210
188
  assert result.exit_code == 0
@@ -213,3 +191,101 @@ def test_install_updates_existing_env_vars(mock_config, mock_server_file):
213
191
  config = json.loads(mock_config.read_text())
214
192
  server = next(iter(config["mcpServers"].values()))
215
193
  assert server["env"] == {"FOO": "newvalue", "BAZ": "123"}
194
+
195
+
196
+ def test_server_dependencies(mock_config, server_file):
197
+ """Test that server dependencies are correctly handled."""
198
+ # Create a server file with dependencies
199
+ server_file = server_file.parent / "server_with_deps.py"
200
+ server_file.write_text(
201
+ """from fastmcp import FastMCP
202
+ mcp = FastMCP("test", dependencies=["pandas", "numpy"])
203
+ """
204
+ )
205
+
206
+ runner = CliRunner()
207
+
208
+ with patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path:
209
+ mock_config_path.return_value = mock_config.parent
210
+
211
+ result = runner.invoke(app, ["install", str(server_file)])
212
+
213
+ assert result.exit_code == 0
214
+
215
+ # Read the config file and check dependencies were added as --with args
216
+ config = json.loads(mock_config.read_text())
217
+ server = next(iter(config["mcpServers"].values()))
218
+ assert "--with" in server["args"]
219
+ assert "pandas" in server["args"]
220
+ assert "numpy" in server["args"]
221
+
222
+
223
+ def test_server_dependencies_empty(mock_config, server_file):
224
+ """Test that server with no dependencies works correctly."""
225
+ runner = CliRunner()
226
+
227
+ with patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path:
228
+ mock_config_path.return_value = mock_config.parent
229
+
230
+ result = runner.invoke(app, ["install", str(server_file)])
231
+
232
+ assert result.exit_code == 0
233
+
234
+ # Read the config file and check only fastmcp is in --with args
235
+ config = json.loads(mock_config.read_text())
236
+ server = next(iter(config["mcpServers"].values()))
237
+ assert server["args"].count("--with") == 1
238
+ assert "fastmcp" in server["args"]
239
+
240
+
241
+ def test_dev_with_dependencies(mock_config, server_file):
242
+ """Test that dev command handles dependencies correctly."""
243
+ # Create a server file with dependencies
244
+ server_file = server_file.parent / "server_with_deps.py"
245
+ server_file.write_text(
246
+ """from fastmcp import FastMCP
247
+ mcp = FastMCP("test", dependencies=["pandas", "numpy"])
248
+ """
249
+ )
250
+
251
+ runner = CliRunner()
252
+
253
+ with patch("subprocess.run") as mock_run:
254
+ mock_run.return_value.returncode = 0 # Set successful return code
255
+ result = runner.invoke(app, ["dev", str(server_file)])
256
+ assert result.exit_code == 0
257
+
258
+ # Check that dependencies were passed to subprocess.run
259
+ mock_run.assert_called_once()
260
+ args = mock_run.call_args[0][0]
261
+ assert "npx" in args
262
+ assert "@modelcontextprotocol/inspector" in args
263
+ assert "uv" in args
264
+ assert "run" in args
265
+ assert "--with" in args
266
+ assert "pandas" in args
267
+ assert "numpy" in args
268
+ assert "fastmcp" in args
269
+
270
+
271
+ def test_run_with_dependencies(mock_config, server_file):
272
+ """Test that run command does not handle dependencies."""
273
+ # Create a server file with dependencies
274
+ server_file = server_file.parent / "server_with_deps.py"
275
+ server_file.write_text(
276
+ """from fastmcp import FastMCP
277
+ mcp = FastMCP("test", dependencies=["pandas", "numpy"])
278
+
279
+ if __name__ == "__main__":
280
+ mcp.run()
281
+ """
282
+ )
283
+
284
+ runner = CliRunner()
285
+
286
+ with patch("subprocess.run") as mock_run:
287
+ result = runner.invoke(app, ["run", str(server_file)])
288
+ assert result.exit_code == 0
289
+
290
+ # Run command should not call subprocess.run
291
+ mock_run.assert_not_called()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes