mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 04:54:17 +02:00
215 lines
6.5 KiB
Python
215 lines
6.5 KiB
Python
"""Tests for the FastMCP CLI."""
|
|
|
|
import json
|
|
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
from typer.testing import CliRunner
|
|
|
|
from fastmcp.cli.cli import app, _parse_env_var
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_config(tmp_path):
|
|
"""Create a mock Claude config file."""
|
|
config = {"mcpServers": {}}
|
|
config_file = tmp_path / "claude_desktop_config.json"
|
|
config_file.write_text(json.dumps(config))
|
|
return config_file
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_server_file(tmp_path):
|
|
"""Create a mock server file."""
|
|
server_file = tmp_path / "server.py"
|
|
server_file.write_text(
|
|
"from fastmcp import Server\n" "server = Server(name='test')\n"
|
|
)
|
|
return server_file
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_env_file(tmp_path):
|
|
"""Create a mock .env file."""
|
|
env_file = tmp_path / ".env"
|
|
env_file.write_text("FOO=bar\nBAZ=123")
|
|
return env_file
|
|
|
|
|
|
def test_parse_env_var():
|
|
"""Test parsing environment variables."""
|
|
assert _parse_env_var("FOO=bar") == ("FOO", "bar")
|
|
assert _parse_env_var("FOO=") == ("FOO", "")
|
|
assert _parse_env_var("FOO=bar baz") == ("FOO", "bar baz")
|
|
assert _parse_env_var("FOO = bar ") == ("FOO", "bar")
|
|
|
|
with pytest.raises(SystemExit):
|
|
_parse_env_var("invalid")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"args,expected_env",
|
|
[
|
|
# Basic env var
|
|
(
|
|
["--env-var", "FOO=bar"],
|
|
{"FOO": "bar"},
|
|
),
|
|
# Multiple env vars
|
|
(
|
|
["--env-var", "FOO=bar", "--env-var", "BAZ=123"],
|
|
{"FOO": "bar", "BAZ": "123"},
|
|
),
|
|
# Env var with spaces
|
|
(
|
|
["--env-var", "FOO=bar baz"],
|
|
{"FOO": "bar baz"},
|
|
),
|
|
],
|
|
)
|
|
def test_install_with_env_vars(mock_config, mock_server_file, args, expected_env):
|
|
"""Test installing with environment variables."""
|
|
runner = CliRunner()
|
|
|
|
with (
|
|
patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
|
|
patch("fastmcp.cli.cli._import_server") as mock_import,
|
|
):
|
|
mock_config_path.return_value = mock_config.parent
|
|
mock_server = Mock()
|
|
mock_server.name = "test" # Set name as an attribute
|
|
mock_import.return_value = mock_server
|
|
|
|
result = runner.invoke(
|
|
app,
|
|
["install", str(mock_server_file)] + args,
|
|
)
|
|
|
|
assert result.exit_code == 0
|
|
|
|
# Read the config file and check env vars
|
|
config = json.loads(mock_config.read_text())
|
|
assert "mcpServers" in config
|
|
assert len(config["mcpServers"]) == 1
|
|
server = next(iter(config["mcpServers"].values()))
|
|
assert server["env"] == expected_env
|
|
|
|
|
|
def test_install_with_env_file(mock_config, mock_server_file, mock_env_file):
|
|
"""Test installing with environment variables from a file."""
|
|
runner = CliRunner()
|
|
|
|
with (
|
|
patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
|
|
patch("fastmcp.cli.cli._import_server") as mock_import,
|
|
):
|
|
mock_config_path.return_value = mock_config.parent
|
|
mock_server = Mock()
|
|
mock_server.name = "test" # Set name as an attribute
|
|
mock_import.return_value = mock_server
|
|
|
|
result = runner.invoke(
|
|
app,
|
|
["install", str(mock_server_file), "--env-file", str(mock_env_file)],
|
|
)
|
|
|
|
assert result.exit_code == 0
|
|
|
|
# Read the config file and check env vars
|
|
config = json.loads(mock_config.read_text())
|
|
assert "mcpServers" in config
|
|
assert len(config["mcpServers"]) == 1
|
|
server = next(iter(config["mcpServers"].values()))
|
|
assert server["env"] == {"FOO": "bar", "BAZ": "123"}
|
|
|
|
|
|
def test_install_preserves_existing_env_vars(mock_config, mock_server_file):
|
|
"""Test that installing preserves existing environment variables."""
|
|
# Set up initial config with env vars
|
|
config = {
|
|
"mcpServers": {
|
|
"test": {
|
|
"command": "uv",
|
|
"args": [
|
|
"run",
|
|
"--with",
|
|
"fastmcp",
|
|
"fastmcp",
|
|
"run",
|
|
str(mock_server_file),
|
|
],
|
|
"env": {"FOO": "bar", "BAZ": "123"},
|
|
}
|
|
}
|
|
}
|
|
mock_config.write_text(json.dumps(config))
|
|
|
|
runner = CliRunner()
|
|
|
|
with (
|
|
patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
|
|
patch("fastmcp.cli.cli._import_server") as mock_import,
|
|
):
|
|
mock_config_path.return_value = mock_config.parent
|
|
mock_server = Mock()
|
|
mock_server.name = "test" # Set name as an attribute
|
|
mock_import.return_value = mock_server
|
|
|
|
# Install with a new env var
|
|
result = runner.invoke(
|
|
app,
|
|
["install", str(mock_server_file), "--env-var", "NEW=value"],
|
|
)
|
|
|
|
assert result.exit_code == 0
|
|
|
|
# Read the config file and check env vars are preserved
|
|
config = json.loads(mock_config.read_text())
|
|
server = next(iter(config["mcpServers"].values()))
|
|
assert server["env"] == {"FOO": "bar", "BAZ": "123", "NEW": "value"}
|
|
|
|
|
|
def test_install_updates_existing_env_vars(mock_config, mock_server_file):
|
|
"""Test that installing updates existing environment variables."""
|
|
# Set up initial config with env vars
|
|
config = {
|
|
"mcpServers": {
|
|
"test": {
|
|
"command": "uv",
|
|
"args": [
|
|
"run",
|
|
"--with",
|
|
"fastmcp",
|
|
"fastmcp",
|
|
"run",
|
|
str(mock_server_file),
|
|
],
|
|
"env": {"FOO": "bar", "BAZ": "123"},
|
|
}
|
|
}
|
|
}
|
|
mock_config.write_text(json.dumps(config))
|
|
|
|
runner = CliRunner()
|
|
|
|
with (
|
|
patch("fastmcp.cli.claude.get_claude_config_path") as mock_config_path,
|
|
patch("fastmcp.cli.cli._import_server") as mock_import,
|
|
):
|
|
mock_config_path.return_value = mock_config.parent
|
|
mock_server = Mock()
|
|
mock_server.name = "test" # Set name as an attribute
|
|
mock_import.return_value = mock_server
|
|
|
|
# Update an existing env var
|
|
result = runner.invoke(
|
|
app,
|
|
["install", str(mock_server_file), "--env-var", "FOO=newvalue"],
|
|
)
|
|
|
|
assert result.exit_code == 0
|
|
|
|
# Read the config file and check env var was updated
|
|
config = json.loads(mock_config.read_text())
|
|
server = next(iter(config["mcpServers"].values()))
|
|
assert server["env"] == {"FOO": "newvalue", "BAZ": "123"}
|