Jeremiah Lowin commited on
Commit
ca9981d
·
1 Parent(s): 0994cd4

Update tests

Browse files
src/fastmcp/server/server.py CHANGED
@@ -213,7 +213,6 @@ class FastMCP(Generic[LifespanResultT]):
213
  Args:
214
  transport: Transport protocol to use ("stdio", "sse", or "streamable-http")
215
  """
216
- logger.debug(f'Starting server "{self.name}"...')
217
 
218
  anyio.run(partial(self.run_async, transport, **transport_kwargs))
219
 
 
213
  Args:
214
  transport: Transport protocol to use ("stdio", "sse", or "streamable-http")
215
  """
 
216
 
217
  anyio.run(partial(self.run_async, transport, **transport_kwargs))
218
 
tests/cli/test_cli.py CHANGED
@@ -173,74 +173,6 @@ class TestHelperFunctions:
173
  "file.py:server",
174
  ]
175
 
176
- def test_parse_file_path_simple(self):
177
- """Test parsing simple file path."""
178
- with (
179
- patch("pathlib.Path.exists") as mock_exists,
180
- patch("pathlib.Path.is_file") as mock_is_file,
181
- patch("pathlib.Path.expanduser") as mock_expanduser,
182
- patch("pathlib.Path.resolve") as mock_resolve,
183
- ):
184
- mock_exists.return_value = True
185
- mock_is_file.return_value = True
186
- mock_expanduser.return_value = Path("file.py")
187
- mock_resolve.return_value = Path("file.py")
188
-
189
- path, obj = cli._parse_file_path("file.py")
190
- assert path == Path("file.py")
191
- assert obj is None
192
-
193
- def test_parse_file_path_with_object(self):
194
- """Test parsing file path with object."""
195
- with (
196
- patch("pathlib.Path.exists") as mock_exists,
197
- patch("pathlib.Path.is_file") as mock_is_file,
198
- patch("pathlib.Path.expanduser") as mock_expanduser,
199
- patch("pathlib.Path.resolve") as mock_resolve,
200
- ):
201
- mock_exists.return_value = True
202
- mock_is_file.return_value = True
203
- mock_expanduser.return_value = Path("file.py")
204
- mock_resolve.return_value = Path("file.py")
205
-
206
- path, obj = cli._parse_file_path("file.py:server")
207
- assert path == Path("file.py")
208
- assert obj == "server"
209
-
210
- def test_parse_file_path_windows(self):
211
- """Test parsing Windows file path."""
212
- with (
213
- patch("pathlib.Path.exists") as mock_exists,
214
- patch("pathlib.Path.is_file") as mock_is_file,
215
- patch("pathlib.Path.expanduser") as mock_expanduser,
216
- patch("pathlib.Path.resolve") as mock_resolve,
217
- ):
218
- mock_exists.return_value = True
219
- mock_is_file.return_value = True
220
- mock_expanduser.return_value = Path("C:/path/file.py")
221
- mock_resolve.return_value = Path("C:/path/file.py")
222
-
223
- path, obj = cli._parse_file_path("C:/path/file.py:server")
224
- assert path == Path("C:/path/file.py")
225
- assert obj == "server"
226
-
227
- def test_parse_file_path_not_file(self, mock_exit, mock_logger):
228
- """Test parsing path that is not a file."""
229
- with (
230
- patch("pathlib.Path.exists") as mock_exists,
231
- patch("pathlib.Path.is_file") as mock_is_file,
232
- patch("pathlib.Path.expanduser") as mock_expanduser,
233
- patch("pathlib.Path.resolve") as mock_resolve,
234
- ):
235
- mock_exists.return_value = True
236
- mock_is_file.return_value = False
237
- mock_expanduser.return_value = Path("directory")
238
- mock_resolve.return_value = Path("directory")
239
-
240
- cli._parse_file_path("directory")
241
- mock_logger.error.assert_called_once()
242
- mock_exit.assert_called_once_with(1)
243
-
244
 
245
  class TestVersionCommand:
246
  """Tests for the version command."""
@@ -259,8 +191,8 @@ class TestDevCommand:
259
  def test_dev_command_success(self, temp_python_file, mock_logger):
260
  """Test successful dev command execution."""
261
  with (
262
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
263
- patch("fastmcp.cli.cli._import_server") as mock_import,
264
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
265
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
266
  patch("subprocess.run") as mock_run,
@@ -285,8 +217,8 @@ class TestDevCommand:
285
  def test_dev_command_with_ui_port(self, temp_python_file):
286
  """Test dev command with UI port."""
287
  with (
288
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
289
- patch("fastmcp.cli.cli._import_server") as mock_import,
290
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
291
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
292
  patch("subprocess.run") as mock_run,
@@ -310,8 +242,8 @@ class TestDevCommand:
310
  def test_dev_command_with_server_port(self, temp_python_file):
311
  """Test dev command with server port."""
312
  with (
313
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
314
- patch("fastmcp.cli.cli._import_server") as mock_import,
315
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
316
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
317
  patch("subprocess.run") as mock_run,
@@ -335,8 +267,8 @@ class TestDevCommand:
335
  def test_dev_command_inspector_version(self, temp_python_file):
336
  """Test dev command with specific inspector version."""
337
  with (
338
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
339
- patch("fastmcp.cli.cli._import_server") as mock_import,
340
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
341
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
342
  patch("subprocess.run") as mock_run,
@@ -360,11 +292,12 @@ class TestDevCommand:
360
  class TestRunCommand:
361
  """Tests for the run command."""
362
 
363
- def test_run_command_success(self, temp_python_file, mock_logger):
364
  """Test successful run command execution."""
365
  with (
366
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
367
- patch("fastmcp.cli.cli._import_server") as mock_import,
 
368
  ):
369
  mock_parse.return_value = (temp_python_file, None)
370
  mock_server = MagicMock()
@@ -374,15 +307,15 @@ class TestRunCommand:
374
  result = runner.invoke(cli.app, ["run", str(temp_python_file)])
375
  assert result.exit_code == 0
376
  mock_server.run.assert_called_once_with()
377
- mock_logger.info.assert_called_with(
378
  f'Found server "test_server" in {temp_python_file}'
379
  )
380
 
381
  def test_run_command_with_transport(self, temp_python_file):
382
  """Test run command with transport option."""
383
  with (
384
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
385
- patch("fastmcp.cli.cli._import_server") as mock_import,
386
  ):
387
  mock_parse.return_value = (temp_python_file, None)
388
  mock_server = MagicMock()
@@ -398,8 +331,8 @@ class TestRunCommand:
398
  def test_run_command_with_host(self, temp_python_file):
399
  """Test run command with host option."""
400
  with (
401
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
402
- patch("fastmcp.cli.cli._import_server") as mock_import,
403
  ):
404
  mock_parse.return_value = (temp_python_file, None)
405
  mock_server = MagicMock()
@@ -415,8 +348,8 @@ class TestRunCommand:
415
  def test_run_command_with_port(self, temp_python_file):
416
  """Test run command with port option."""
417
  with (
418
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
419
- patch("fastmcp.cli.cli._import_server") as mock_import,
420
  ):
421
  mock_parse.return_value = (temp_python_file, None)
422
  mock_server = MagicMock()
@@ -432,8 +365,8 @@ class TestRunCommand:
432
  def test_run_command_with_log_level(self, temp_python_file):
433
  """Test run command with log level option."""
434
  with (
435
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
436
- patch("fastmcp.cli.cli._import_server") as mock_import,
437
  ):
438
  mock_parse.return_value = (temp_python_file, None)
439
  mock_server = MagicMock()
@@ -449,8 +382,8 @@ class TestRunCommand:
449
  def test_run_command_with_multiple_options(self, temp_python_file):
450
  """Test run command with multiple options."""
451
  with (
452
- patch("fastmcp.cli.cli._parse_file_path") as mock_parse,
453
- patch("fastmcp.cli.cli._import_server") as mock_import,
454
  ):
455
  mock_parse.return_value = (temp_python_file, None)
456
  mock_server = MagicMock()
 
173
  "file.py:server",
174
  ]
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  class TestVersionCommand:
178
  """Tests for the version command."""
 
191
  def test_dev_command_success(self, temp_python_file, mock_logger):
192
  """Test successful dev command execution."""
193
  with (
194
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
195
+ patch("fastmcp.cli.run.import_server") as mock_import,
196
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
197
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
198
  patch("subprocess.run") as mock_run,
 
217
  def test_dev_command_with_ui_port(self, temp_python_file):
218
  """Test dev command with UI port."""
219
  with (
220
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
221
+ patch("fastmcp.cli.run.import_server") as mock_import,
222
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
223
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
224
  patch("subprocess.run") as mock_run,
 
242
  def test_dev_command_with_server_port(self, temp_python_file):
243
  """Test dev command with server port."""
244
  with (
245
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
246
+ patch("fastmcp.cli.run.import_server") as mock_import,
247
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
248
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
249
  patch("subprocess.run") as mock_run,
 
267
  def test_dev_command_inspector_version(self, temp_python_file):
268
  """Test dev command with specific inspector version."""
269
  with (
270
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
271
+ patch("fastmcp.cli.run.import_server") as mock_import,
272
  patch("fastmcp.cli.cli._get_npx_command") as mock_get_npx,
273
  patch("fastmcp.cli.cli._build_uv_command") as mock_build_uv,
274
  patch("subprocess.run") as mock_run,
 
292
  class TestRunCommand:
293
  """Tests for the run command."""
294
 
295
+ def test_run_command_success(self, temp_python_file):
296
  """Test successful run command execution."""
297
  with (
298
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
299
+ patch("fastmcp.cli.run.import_server") as mock_import,
300
+ patch("fastmcp.cli.run.logger") as mock_logger,
301
  ):
302
  mock_parse.return_value = (temp_python_file, None)
303
  mock_server = MagicMock()
 
307
  result = runner.invoke(cli.app, ["run", str(temp_python_file)])
308
  assert result.exit_code == 0
309
  mock_server.run.assert_called_once_with()
310
+ mock_logger.debug.assert_called_with(
311
  f'Found server "test_server" in {temp_python_file}'
312
  )
313
 
314
  def test_run_command_with_transport(self, temp_python_file):
315
  """Test run command with transport option."""
316
  with (
317
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
318
+ patch("fastmcp.cli.run.import_server") as mock_import,
319
  ):
320
  mock_parse.return_value = (temp_python_file, None)
321
  mock_server = MagicMock()
 
331
  def test_run_command_with_host(self, temp_python_file):
332
  """Test run command with host option."""
333
  with (
334
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
335
+ patch("fastmcp.cli.run.import_server") as mock_import,
336
  ):
337
  mock_parse.return_value = (temp_python_file, None)
338
  mock_server = MagicMock()
 
348
  def test_run_command_with_port(self, temp_python_file):
349
  """Test run command with port option."""
350
  with (
351
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
352
+ patch("fastmcp.cli.run.import_server") as mock_import,
353
  ):
354
  mock_parse.return_value = (temp_python_file, None)
355
  mock_server = MagicMock()
 
365
  def test_run_command_with_log_level(self, temp_python_file):
366
  """Test run command with log level option."""
367
  with (
368
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
369
+ patch("fastmcp.cli.run.import_server") as mock_import,
370
  ):
371
  mock_parse.return_value = (temp_python_file, None)
372
  mock_server = MagicMock()
 
382
  def test_run_command_with_multiple_options(self, temp_python_file):
383
  """Test run command with multiple options."""
384
  with (
385
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
386
+ patch("fastmcp.cli.run.import_server") as mock_import,
387
  ):
388
  mock_parse.return_value = (temp_python_file, None)
389
  mock_server = MagicMock()
tests/cli/test_run.py CHANGED
@@ -1,22 +1,262 @@
 
 
 
 
 
1
  import pytest
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
 
4
  @pytest.fixture
5
- def server_file(tmp_path):
6
- """Create a simple server file for testing"""
7
- server_path = tmp_path / "test_server.py"
8
- server_path.write_text(
9
- """
10
- from fastmcp import FastMCP
11
 
12
- mcp = FastMCP(name="TestServer")
13
 
14
- @mcp.tool()
15
- def hello(name: str) -> str:
16
- return f"Hello, {name}!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- if __name__ == "__main__":
19
- mcp.run()
 
 
 
 
 
20
  """
21
- )
22
- return server_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for the CLI module."""
2
+
3
+ from pathlib import Path
4
+ from unittest.mock import MagicMock, patch
5
+
6
  import pytest
7
+ from typer.testing import CliRunner
8
+
9
+ import fastmcp.cli.run
10
+ from fastmcp.cli import cli
11
+
12
+ # Set up test runner
13
+ runner = CliRunner()
14
+
15
+
16
+ @pytest.fixture
17
+ def mock_console():
18
+ """Mock the rich console to test output."""
19
+ with patch("fastmcp.cli.cli.console") as mock_console:
20
+ yield mock_console
21
+
22
+
23
+ @pytest.fixture
24
+ def mock_logger():
25
+ """Mock the logger to test logging."""
26
+ with patch("fastmcp.cli.cli.logger") as mock_logger:
27
+ yield mock_logger
28
 
29
 
30
  @pytest.fixture
31
+ def mock_exit():
32
+ """Mock sys.exit to prevent tests from exiting."""
33
+ with patch("sys.exit") as mock_exit:
34
+ yield mock_exit
 
 
35
 
 
36
 
37
+ @pytest.fixture
38
+ def temp_python_file(tmp_path):
39
+ """Create a temporary Python file with a test server."""
40
+ server_code = """
41
+ from mcp import Server
42
+
43
+ class TestServer(Server):
44
+ name = "test_server"
45
+ dependencies = ["package1", "package2"]
46
+
47
+ def run(self, **kwargs):
48
+ print("Running server with", kwargs)
49
+
50
+ mcp = TestServer()
51
+ server = TestServer()
52
+ app = TestServer()
53
+ custom_server = TestServer()
54
+ """
55
+ file_path = tmp_path / "test_server.py"
56
+ file_path.write_text(server_code)
57
+ return file_path
58
 
59
+
60
+ @pytest.fixture
61
+ def temp_env_file(tmp_path):
62
+ """Create a temporary .env file."""
63
+ env_content = """
64
+ TEST_VAR1=value1
65
+ TEST_VAR2=value2
66
  """
67
+ env_path = tmp_path / ".env"
68
+ env_path.write_text(env_content)
69
+ return env_path
70
+
71
+
72
+ class TestHelperFunctions:
73
+ def test_parse_file_path_simple(self):
74
+ """Test parsing simple file path."""
75
+ with (
76
+ patch("pathlib.Path.exists") as mock_exists,
77
+ patch("pathlib.Path.is_file") as mock_is_file,
78
+ patch("pathlib.Path.expanduser") as mock_expanduser,
79
+ patch("pathlib.Path.resolve") as mock_resolve,
80
+ ):
81
+ mock_exists.return_value = True
82
+ mock_is_file.return_value = True
83
+ mock_expanduser.return_value = Path("file.py")
84
+ mock_resolve.return_value = Path("file.py")
85
+
86
+ path, obj = fastmcp.cli.run.parse_file_path("file.py")
87
+ assert path == Path("file.py")
88
+ assert obj is None
89
+
90
+ def test_parse_file_path_with_object(self):
91
+ """Test parsing file path with object."""
92
+ with (
93
+ patch("pathlib.Path.exists") as mock_exists,
94
+ patch("pathlib.Path.is_file") as mock_is_file,
95
+ patch("pathlib.Path.expanduser") as mock_expanduser,
96
+ patch("pathlib.Path.resolve") as mock_resolve,
97
+ ):
98
+ mock_exists.return_value = True
99
+ mock_is_file.return_value = True
100
+ mock_expanduser.return_value = Path("file.py")
101
+ mock_resolve.return_value = Path("file.py")
102
+
103
+ path, obj = fastmcp.cli.run.parse_file_path("file.py:server")
104
+ assert path == Path("file.py")
105
+ assert obj == "server"
106
+
107
+ def test_parse_file_path_windows(self):
108
+ """Test parsing Windows file path."""
109
+ with (
110
+ patch("pathlib.Path.exists") as mock_exists,
111
+ patch("pathlib.Path.is_file") as mock_is_file,
112
+ patch("pathlib.Path.expanduser") as mock_expanduser,
113
+ patch("pathlib.Path.resolve") as mock_resolve,
114
+ ):
115
+ mock_exists.return_value = True
116
+ mock_is_file.return_value = True
117
+ mock_expanduser.return_value = Path("C:/path/file.py")
118
+ mock_resolve.return_value = Path("C:/path/file.py")
119
+
120
+ path, obj = fastmcp.cli.run.parse_file_path("C:/path/file.py:server")
121
+ assert path == Path("C:/path/file.py")
122
+ assert obj == "server"
123
+
124
+ def test_parse_file_path_not_file(self, mock_exit):
125
+ """Test parsing path that is not a file."""
126
+ with (
127
+ patch("pathlib.Path.exists") as mock_exists,
128
+ patch("pathlib.Path.is_file") as mock_is_file,
129
+ patch("pathlib.Path.expanduser") as mock_expanduser,
130
+ patch("pathlib.Path.resolve") as mock_resolve,
131
+ patch("fastmcp.cli.run.logger") as mock_logger,
132
+ ):
133
+ mock_exists.return_value = True
134
+ mock_is_file.return_value = False
135
+ mock_expanduser.return_value = Path("directory")
136
+ mock_resolve.return_value = Path("directory")
137
+
138
+ fastmcp.cli.run.parse_file_path("directory")
139
+ mock_logger.error.assert_called_once()
140
+ mock_exit.assert_called_once_with(1)
141
+
142
+
143
+ class TestRunCommand:
144
+ """Tests for the run command."""
145
+
146
+ def test_run_command_success(self, temp_python_file):
147
+ """Test successful run command execution."""
148
+ with (
149
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
150
+ patch("fastmcp.cli.run.import_server") as mock_import,
151
+ patch("fastmcp.cli.run.logger") as mock_logger,
152
+ ):
153
+ mock_parse.return_value = (temp_python_file, None)
154
+ mock_server = MagicMock()
155
+ mock_server.name = "test_server"
156
+ mock_import.return_value = mock_server
157
+
158
+ result = runner.invoke(cli.app, ["run", str(temp_python_file)])
159
+ assert result.exit_code == 0
160
+ mock_server.run.assert_called_once_with()
161
+ mock_logger.debug.assert_called_with(
162
+ f'Found server "test_server" in {temp_python_file}'
163
+ )
164
+
165
+ def test_run_command_with_transport(self, temp_python_file):
166
+ """Test run command with transport option."""
167
+ with (
168
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
169
+ patch("fastmcp.cli.run.import_server") as mock_import,
170
+ ):
171
+ mock_parse.return_value = (temp_python_file, None)
172
+ mock_server = MagicMock()
173
+ mock_server.name = "test_server"
174
+ mock_import.return_value = mock_server
175
+
176
+ result = runner.invoke(
177
+ cli.app, ["run", str(temp_python_file), "--transport", "sse"]
178
+ )
179
+ assert result.exit_code == 0
180
+ mock_server.run.assert_called_once_with(transport="sse")
181
+
182
+ def test_run_command_with_host(self, temp_python_file):
183
+ """Test run command with host option."""
184
+ with (
185
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
186
+ patch("fastmcp.cli.run.import_server") as mock_import,
187
+ ):
188
+ mock_parse.return_value = (temp_python_file, None)
189
+ mock_server = MagicMock()
190
+ mock_server.name = "test_server"
191
+ mock_import.return_value = mock_server
192
+
193
+ result = runner.invoke(
194
+ cli.app, ["run", str(temp_python_file), "--host", "0.0.0.0"]
195
+ )
196
+ assert result.exit_code == 0
197
+ mock_server.run.assert_called_once_with(host="0.0.0.0")
198
+
199
+ def test_run_command_with_port(self, temp_python_file):
200
+ """Test run command with port option."""
201
+ with (
202
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
203
+ patch("fastmcp.cli.run.import_server") as mock_import,
204
+ ):
205
+ mock_parse.return_value = (temp_python_file, None)
206
+ mock_server = MagicMock()
207
+ mock_server.name = "test_server"
208
+ mock_import.return_value = mock_server
209
+
210
+ result = runner.invoke(
211
+ cli.app, ["run", str(temp_python_file), "--port", "8080"]
212
+ )
213
+ assert result.exit_code == 0
214
+ mock_server.run.assert_called_once_with(port=8080)
215
+
216
+ def test_run_command_with_log_level(self, temp_python_file):
217
+ """Test run command with log level option."""
218
+ with (
219
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
220
+ patch("fastmcp.cli.run.import_server") as mock_import,
221
+ ):
222
+ mock_parse.return_value = (temp_python_file, None)
223
+ mock_server = MagicMock()
224
+ mock_server.name = "test_server"
225
+ mock_import.return_value = mock_server
226
+
227
+ result = runner.invoke(
228
+ cli.app, ["run", str(temp_python_file), "--log-level", "DEBUG"]
229
+ )
230
+ assert result.exit_code == 0
231
+ mock_server.run.assert_called_once_with(log_level="DEBUG")
232
+
233
+ def test_run_command_with_multiple_options(self, temp_python_file):
234
+ """Test run command with multiple options."""
235
+ with (
236
+ patch("fastmcp.cli.run.parse_file_path") as mock_parse,
237
+ patch("fastmcp.cli.run.import_server") as mock_import,
238
+ ):
239
+ mock_parse.return_value = (temp_python_file, None)
240
+ mock_server = MagicMock()
241
+ mock_server.name = "test_server"
242
+ mock_import.return_value = mock_server
243
+
244
+ result = runner.invoke(
245
+ cli.app,
246
+ [
247
+ "run",
248
+ str(temp_python_file),
249
+ "--transport",
250
+ "sse",
251
+ "--host",
252
+ "0.0.0.0",
253
+ "--port",
254
+ "8080",
255
+ "--log-level",
256
+ "DEBUG",
257
+ ],
258
+ )
259
+ assert result.exit_code == 0
260
+ mock_server.run.assert_called_once_with(
261
+ transport="sse", host="0.0.0.0", port=8080, log_level="DEBUG"
262
+ )