Spaces:
Running
Running
File size: 9,108 Bytes
dd7600a ca11c0a a3e3aed ca11c0a a3e3aed ca11c0a dd7600a ca11c0a a3e3aed ca11c0a a3e3aed ca11c0a dd7600a ca11c0a a3e3aed ca11c0a a3e3aed ca11c0a 23b21a0 ca11c0a 23b21a0 ca11c0a dd7600a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | from pathlib import Path
from fastmcp.cli.install import install_app
class TestInstallApp:
"""Test the install subapp."""
def test_install_app_exists(self):
"""Test that the install app is properly configured."""
# install_app.name is a tuple in cyclopts
assert "install" in install_app.name
assert "Install MCP servers" in install_app.help
def test_install_commands_registered(self):
"""Test that all install commands are registered."""
# Check that the app has the expected help text and structure
# This is a simpler check that doesn't rely on internal methods
assert hasattr(install_app, "help")
assert "Install MCP servers" in install_app.help
# We can test that the commands parse without errors
try:
install_app.parse_args(["claude-code", "--help"])
install_app.parse_args(["claude-desktop", "--help"])
install_app.parse_args(["cursor", "--help"])
install_app.parse_args(["mcp-json", "--help"])
except SystemExit:
# Help commands exit with 0, that's expected
pass
class TestClaudeCodeInstall:
"""Test claude-code install command."""
def test_claude_code_basic(self):
"""Test basic claude-code install command parsing."""
# Parse command with correct parameter names
command, bound, _ = install_app.parse_args(
["claude-code", "server.py", "--name", "test-server"]
)
# Verify parsing was successful
assert command is not None
assert bound.arguments["server_spec"] == "server.py"
assert bound.arguments["server_name"] == "test-server"
def test_claude_code_with_options(self):
"""Test claude-code install with various options."""
command, bound, _ = install_app.parse_args(
[
"claude-code",
"server.py",
"--name",
"test-server",
"--with",
"package1",
"--with",
"package2",
"--env",
"VAR1=value1",
]
)
assert bound.arguments["with_packages"] == ["package1", "package2"]
assert bound.arguments["env_vars"] == ["VAR1=value1"]
def test_claude_code_with_new_options(self):
"""Test claude-code install with new uv options."""
from pathlib import Path
command, bound, _ = install_app.parse_args(
[
"claude-code",
"server.py",
"--python",
"3.11",
"--project",
"/workspace",
"--with-requirements",
"requirements.txt",
]
)
assert bound.arguments["python"] == "3.11"
assert bound.arguments["project"] == Path("/workspace")
assert bound.arguments["with_requirements"] == Path("requirements.txt")
class TestClaudeDesktopInstall:
"""Test claude-desktop install command."""
def test_claude_desktop_basic(self):
"""Test basic claude-desktop install command parsing."""
command, bound, _ = install_app.parse_args(
["claude-desktop", "server.py", "--name", "test-server"]
)
assert command is not None
assert bound.arguments["server_spec"] == "server.py"
assert bound.arguments["server_name"] == "test-server"
def test_claude_desktop_with_env_vars(self):
"""Test claude-desktop install with environment variables."""
command, bound, _ = install_app.parse_args(
[
"claude-desktop",
"server.py",
"--name",
"test-server",
"--env",
"VAR1=value1",
"--env",
"VAR2=value2",
]
)
assert bound.arguments["env_vars"] == ["VAR1=value1", "VAR2=value2"]
def test_claude_desktop_with_new_options(self):
"""Test claude-desktop install with new uv options."""
from pathlib import Path
command, bound, _ = install_app.parse_args(
[
"claude-desktop",
"server.py",
"--python",
"3.10",
"--project",
"/my/project",
"--with-requirements",
"reqs.txt",
]
)
assert bound.arguments["python"] == "3.10"
assert bound.arguments["project"] == Path("/my/project")
assert bound.arguments["with_requirements"] == Path("reqs.txt")
class TestCursorInstall:
"""Test cursor install command."""
def test_cursor_basic(self):
"""Test basic cursor install command parsing."""
command, bound, _ = install_app.parse_args(
["cursor", "server.py", "--name", "test-server"]
)
assert command is not None
assert bound.arguments["server_spec"] == "server.py"
assert bound.arguments["server_name"] == "test-server"
def test_cursor_with_options(self):
"""Test cursor install with options."""
command, bound, _ = install_app.parse_args(
["cursor", "server.py", "--name", "test-server"]
)
assert bound.arguments["server_spec"] == "server.py"
assert bound.arguments["server_name"] == "test-server"
class TestMcpJsonInstall:
"""Test mcp-json install command."""
def test_mcp_json_basic(self):
"""Test basic mcp-json install command parsing."""
command, bound, _ = install_app.parse_args(
["mcp-json", "server.py", "--name", "test-server"]
)
assert command is not None
assert bound.arguments["server_spec"] == "server.py"
assert bound.arguments["server_name"] == "test-server"
def test_mcp_json_with_copy(self):
"""Test mcp-json install with copy to clipboard option."""
command, bound, _ = install_app.parse_args(
["mcp-json", "server.py", "--name", "test-server", "--copy"]
)
assert bound.arguments["copy"] is True
class TestInstallCommandParsing:
"""Test command parsing and error handling."""
def test_install_minimal_args(self):
"""Test install commands with minimal required arguments."""
# Each command should work with just a server spec
commands_to_test = [
["claude-code", "server.py"],
["claude-desktop", "server.py"],
["cursor", "server.py"],
]
for cmd_args in commands_to_test:
command, bound, _ = install_app.parse_args(cmd_args)
assert command is not None
assert bound.arguments["server_spec"] == "server.py"
def test_mcp_json_minimal(self):
"""Test that mcp-json works with minimal arguments."""
# Should work with just server spec
command, bound, _ = install_app.parse_args(["mcp-json", "server.py"])
assert command is not None
assert bound.arguments["server_spec"] == "server.py"
def test_python_option(self):
"""Test --python option for all install commands."""
commands_to_test = [
["claude-code", "server.py", "--python", "3.11"],
["claude-desktop", "server.py", "--python", "3.11"],
["cursor", "server.py", "--python", "3.11"],
["mcp-json", "server.py", "--python", "3.11"],
]
for cmd_args in commands_to_test:
command, bound, _ = install_app.parse_args(cmd_args)
assert command is not None
assert bound.arguments["python"] == "3.11"
def test_with_requirements_option(self):
"""Test --with-requirements option for all install commands."""
commands_to_test = [
["claude-code", "server.py", "--with-requirements", "requirements.txt"],
["claude-desktop", "server.py", "--with-requirements", "requirements.txt"],
["cursor", "server.py", "--with-requirements", "requirements.txt"],
["mcp-json", "server.py", "--with-requirements", "requirements.txt"],
]
for cmd_args in commands_to_test:
command, bound, _ = install_app.parse_args(cmd_args)
assert command is not None
assert str(bound.arguments["with_requirements"]) == "requirements.txt"
def test_project_option(self):
"""Test --project option for all install commands."""
commands_to_test = [
["claude-code", "server.py", "--project", "/path/to/project"],
["claude-desktop", "server.py", "--project", "/path/to/project"],
["cursor", "server.py", "--project", "/path/to/project"],
["mcp-json", "server.py", "--project", "/path/to/project"],
]
for cmd_args in commands_to_test:
command, bound, _ = install_app.parse_args(cmd_args)
assert command is not None
assert str(bound.arguments["project"]) == str(Path("/path/to/project"))
|