Tapan Chugh tapanc commited on
Commit
cbb550a
·
unverified ·
1 Parent(s): 957b451

Fix server argument passing in CLI run command (#1293)

Browse files

Co-authored-by: Tapan Chugh <tapanc@cs.washington.edu>

Files changed (2) hide show
  1. src/fastmcp/cli/cli.py +3 -6
  2. tests/cli/test_cli.py +73 -0
src/fastmcp/cli/cli.py CHANGED
@@ -285,7 +285,7 @@ def dev(
285
  @app.command
286
  def run(
287
  server_spec: str,
288
- *,
289
  transport: Annotated[
290
  run_module.TransportType | None,
291
  cyclopts.Parameter(
@@ -373,9 +373,6 @@ def run(
373
  Args:
374
  server_spec: Python file, object specification (file:obj), MCPConfig file, or URL
375
  """
376
- # TODO: Handle server_args from extra context
377
- server_args = [] # Will need to handle this with Cyclopts context
378
-
379
  logger.debug(
380
  "Running server or client",
381
  extra={
@@ -385,7 +382,7 @@ def run(
385
  "port": port,
386
  "path": path,
387
  "log_level": log_level,
388
- "server_args": server_args,
389
  },
390
  )
391
 
@@ -424,7 +421,7 @@ def run(
424
  port=port,
425
  path=path,
426
  log_level=log_level,
427
- server_args=server_args,
428
  show_banner=not no_banner,
429
  )
430
  except Exception as e:
 
285
  @app.command
286
  def run(
287
  server_spec: str,
288
+ *server_args: str,
289
  transport: Annotated[
290
  run_module.TransportType | None,
291
  cyclopts.Parameter(
 
373
  Args:
374
  server_spec: Python file, object specification (file:obj), MCPConfig file, or URL
375
  """
 
 
 
376
  logger.debug(
377
  "Running server or client",
378
  extra={
 
382
  "port": port,
383
  "path": path,
384
  "log_level": log_level,
385
+ "server_args": list(server_args),
386
  },
387
  )
388
 
 
421
  port=port,
422
  path=path,
423
  log_level=log_level,
424
+ server_args=list(server_args),
425
  show_banner=not no_banner,
426
  )
427
  except Exception as e:
tests/cli/test_cli.py CHANGED
@@ -399,6 +399,79 @@ class TestRunCommand:
399
  assert command is not None
400
  assert bound.arguments["transport"] == "streamable-http"
401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
 
403
  class TestWindowsSpecific:
404
  """Test Windows-specific functionality."""
 
399
  assert command is not None
400
  assert bound.arguments["transport"] == "streamable-http"
401
 
402
+ def test_run_command_parsing_with_server_args(self):
403
+ """Test run command parsing with server arguments after --."""
404
+ command, bound, _ = app.parse_args(
405
+ [
406
+ "run",
407
+ "server.py",
408
+ "--",
409
+ "--config",
410
+ "test.json",
411
+ "--debug",
412
+ ]
413
+ )
414
+
415
+ assert command is not None
416
+ assert bound.arguments["server_spec"] == "server.py"
417
+ # Server args after -- are captured as positional arguments in bound.args
418
+ assert bound.args == ("server.py", "--config", "test.json", "--debug")
419
+
420
+ def test_run_command_parsing_with_mixed_args(self):
421
+ """Test run command parsing with both FastMCP options and server args."""
422
+ command, bound, _ = app.parse_args(
423
+ [
424
+ "run",
425
+ "server.py",
426
+ "--transport",
427
+ "http",
428
+ "--port",
429
+ "8080",
430
+ "--",
431
+ "--server-port",
432
+ "9090",
433
+ "--debug",
434
+ ]
435
+ )
436
+
437
+ assert command is not None
438
+ assert bound.arguments["server_spec"] == "server.py"
439
+ assert bound.arguments["transport"] == "http"
440
+ assert bound.arguments["port"] == 8080
441
+ # Server args after -- are captured separately from FastMCP options
442
+ assert bound.args == ("server.py", "--server-port", "9090", "--debug")
443
+
444
+ def test_run_command_parsing_with_positional_server_args(self):
445
+ """Test run command parsing with positional server arguments."""
446
+ command, bound, _ = app.parse_args(
447
+ [
448
+ "run",
449
+ "server.py",
450
+ "--",
451
+ "arg1",
452
+ "arg2",
453
+ "--flag",
454
+ ]
455
+ )
456
+
457
+ assert command is not None
458
+ assert bound.arguments["server_spec"] == "server.py"
459
+ # Positional args and flags after -- are all captured
460
+ assert bound.args == ("server.py", "arg1", "arg2", "--flag")
461
+
462
+ def test_run_command_parsing_server_args_require_delimiter(self):
463
+ """Test that server args without -- delimiter are rejected."""
464
+ # Should fail because --config is not a recognized FastMCP option
465
+ with pytest.raises(SystemExit):
466
+ app.parse_args(
467
+ [
468
+ "run",
469
+ "server.py",
470
+ "--config",
471
+ "test.json",
472
+ ]
473
+ )
474
+
475
 
476
  class TestWindowsSpecific:
477
  """Test Windows-specific functionality."""