Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cforge/commands/server/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ def run(
# Register if requested
if register:

# Default to SSE if no protocol specified
is_sse = expose_sse or expose_streamable_http or (not expose_sse and not expose_streamable_http)
# Use streamable HTTP only when it's explicitly enabled without SSE
is_sse = expose_sse or not expose_streamable_http

registered_server_id: Optional[str] = None
try:
Expand Down
93 changes: 93 additions & 0 deletions tests/commands/server/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,3 +735,96 @@ def test_run_temporary_without_source_uses_fallback_name(self) -> None:
# Verify cleanup was registered
mock_atexit.register.assert_called_once()
mock_process.assert_called_once()

def test_run_registration_with_streamable_http_only(self) -> None:
"""Test that registration uses /mcp endpoint when only streamable HTTP is enabled."""
with (
patch("mcpgateway.translate.main") as mock_translate,
patch("multiprocessing.Process") as mock_process,
patch("cforge.commands.server.run.requests") as mock_requests,
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
):
# Mock returning a 200 on health
mock_get_res = MagicMock()
mock_get_res.status_code = 200
mock_requests.get = MagicMock(return_value=mock_get_res)

mock_request.return_value = {"id": "streamable-http-server-id"}

invoke_typer_command(run, stdio="uvx mcp-server-git", port=9005, expose_streamable_http=True, register=True)

# Verify registration was attempted
mock_request.assert_called_once()
call_args = mock_request.call_args
json_data = call_args[1]["json_data"]

# Verify correct endpoint and transport type for streamable HTTP
assert json_data["url"] == "http://127.0.0.1:9005/mcp"
assert json_data["transport"] == "STREAMABLEHTTP"

# Verify translate_main was called via Process
mock_process.assert_called_once()
proc_call_args = mock_process.call_args[1]
assert proc_call_args.get("target") is mock_translate

def test_run_registration_with_both_protocols_defaults_to_sse(self) -> None:
"""Test that registration defaults to SSE when both protocols are enabled."""
with (
patch("mcpgateway.translate.main") as mock_translate,
patch("multiprocessing.Process") as mock_process,
patch("cforge.commands.server.run.requests") as mock_requests,
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
):
# Mock returning a 200 on health
mock_get_res = MagicMock()
mock_get_res.status_code = 200
mock_requests.get = MagicMock(return_value=mock_get_res)

mock_request.return_value = {"id": "both-protocols-server-id"}

invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, expose_sse=True, expose_streamable_http=True, register=True)

# Verify registration was attempted
mock_request.assert_called_once()
call_args = mock_request.call_args
json_data = call_args[1]["json_data"]

# Verify SSE is used when both protocols are enabled (SSE takes priority)
assert json_data["url"] == "http://127.0.0.1:9000/sse"
assert json_data["transport"] == "SSE"

# Verify translate_main was called via Process
mock_process.assert_called_once()
proc_call_args = mock_process.call_args[1]
assert proc_call_args.get("target") is mock_translate

def test_run_registration_without_protocol_flags_defaults_to_sse(self) -> None:
"""Test that registration defaults to SSE when no protocol flags are specified."""
with (
patch("mcpgateway.translate.main") as mock_translate,
patch("multiprocessing.Process") as mock_process,
patch("cforge.commands.server.run.requests") as mock_requests,
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
):
# Mock returning a 200 on health
mock_get_res = MagicMock()
mock_get_res.status_code = 200
mock_requests.get = MagicMock(return_value=mock_get_res)

mock_request.return_value = {"id": "default-server-id"}

invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, register=True)

# Verify registration was attempted
mock_request.assert_called_once()
call_args = mock_request.call_args
json_data = call_args[1]["json_data"]

# Verify SSE is used by default when no protocol flags are specified
assert json_data["url"] == "http://127.0.0.1:9000/sse"
assert json_data["transport"] == "SSE"

# Verify translate_main was called via Process
mock_process.assert_called_once()
proc_call_args = mock_process.call_args[1]
assert proc_call_args.get("target") is mock_translate