Skip to content

Commit 3df219b

Browse files
authored
Merge pull request #29 from ABruneel04/bugfix/auto-registration
fix: correct endpoint selection for streamable HTTP auto-registration
2 parents 30b7497 + 13a9940 commit 3df219b

2 files changed

Lines changed: 95 additions & 2 deletions

File tree

cforge/commands/server/run.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ def run(
174174
# Register if requested
175175
if register:
176176

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

180180
registered_server_id: Optional[str] = None
181181
try:

tests/commands/server/test_run.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,3 +736,96 @@ def test_run_temporary_without_source_uses_fallback_name(self) -> None:
736736
# Verify cleanup was registered
737737
mock_atexit.register.assert_called_once()
738738
mock_process.assert_called_once()
739+
740+
def test_run_registration_with_streamable_http_only(self) -> None:
741+
"""Test that registration uses /mcp endpoint when only streamable HTTP is enabled."""
742+
with (
743+
patch("mcpgateway.translate.main") as mock_translate,
744+
patch("multiprocessing.Process") as mock_process,
745+
patch("cforge.commands.server.run.requests") as mock_requests,
746+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
747+
):
748+
# Mock returning a 200 on health
749+
mock_get_res = MagicMock()
750+
mock_get_res.status_code = 200
751+
mock_requests.get = MagicMock(return_value=mock_get_res)
752+
753+
mock_request.return_value = {"id": "streamable-http-server-id"}
754+
755+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9005, expose_streamable_http=True, register=True)
756+
757+
# Verify registration was attempted
758+
mock_request.assert_called_once()
759+
call_args = mock_request.call_args
760+
json_data = call_args[1]["json_data"]
761+
762+
# Verify correct endpoint and transport type for streamable HTTP
763+
assert json_data["url"] == "http://127.0.0.1:9005/mcp"
764+
assert json_data["transport"] == "STREAMABLEHTTP"
765+
766+
# Verify translate_main was called via Process
767+
mock_process.assert_called_once()
768+
proc_call_args = mock_process.call_args[1]
769+
assert proc_call_args.get("target") is mock_translate
770+
771+
def test_run_registration_with_both_protocols_defaults_to_sse(self) -> None:
772+
"""Test that registration defaults to SSE when both protocols are enabled."""
773+
with (
774+
patch("mcpgateway.translate.main") as mock_translate,
775+
patch("multiprocessing.Process") as mock_process,
776+
patch("cforge.commands.server.run.requests") as mock_requests,
777+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
778+
):
779+
# Mock returning a 200 on health
780+
mock_get_res = MagicMock()
781+
mock_get_res.status_code = 200
782+
mock_requests.get = MagicMock(return_value=mock_get_res)
783+
784+
mock_request.return_value = {"id": "both-protocols-server-id"}
785+
786+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, expose_sse=True, expose_streamable_http=True, register=True)
787+
788+
# Verify registration was attempted
789+
mock_request.assert_called_once()
790+
call_args = mock_request.call_args
791+
json_data = call_args[1]["json_data"]
792+
793+
# Verify SSE is used when both protocols are enabled (SSE takes priority)
794+
assert json_data["url"] == "http://127.0.0.1:9000/sse"
795+
assert json_data["transport"] == "SSE"
796+
797+
# Verify translate_main was called via Process
798+
mock_process.assert_called_once()
799+
proc_call_args = mock_process.call_args[1]
800+
assert proc_call_args.get("target") is mock_translate
801+
802+
def test_run_registration_without_protocol_flags_defaults_to_sse(self) -> None:
803+
"""Test that registration defaults to SSE when no protocol flags are specified."""
804+
with (
805+
patch("mcpgateway.translate.main") as mock_translate,
806+
patch("multiprocessing.Process") as mock_process,
807+
patch("cforge.commands.server.run.requests") as mock_requests,
808+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
809+
):
810+
# Mock returning a 200 on health
811+
mock_get_res = MagicMock()
812+
mock_get_res.status_code = 200
813+
mock_requests.get = MagicMock(return_value=mock_get_res)
814+
815+
mock_request.return_value = {"id": "default-server-id"}
816+
817+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, register=True)
818+
819+
# Verify registration was attempted
820+
mock_request.assert_called_once()
821+
call_args = mock_request.call_args
822+
json_data = call_args[1]["json_data"]
823+
824+
# Verify SSE is used by default when no protocol flags are specified
825+
assert json_data["url"] == "http://127.0.0.1:9000/sse"
826+
assert json_data["transport"] == "SSE"
827+
828+
# Verify translate_main was called via Process
829+
mock_process.assert_called_once()
830+
proc_call_args = mock_process.call_args[1]
831+
assert proc_call_args.get("target") is mock_translate

0 commit comments

Comments
 (0)