Skip to content

Commit 4ca0ac4

Browse files
madhav165crivetimihai
authored andcommitted
[FIX][API]: Propagate gateway visibility to linked tools/prompts/resources (#3476)
* fix: propagate visibility to linked tools/prompts/resources when gateway is updated Closes #3475 Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> * fix(test): assert db.commit() in visibility propagation test Ensure the test verifies that visibility changes to linked tools/resources/prompts are actually persisted to the database when gateway initialization fails. Closes #3475 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com> Signed-off-by: Yosief Eyob <yosiefogbazion@gmail.com>
1 parent 9bf7595 commit 4ca0ac4

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

mcpgateway/services/gateway_service.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,8 +1897,15 @@ async def update_gateway(
18971897
gateway.tags = gateway_update.tags
18981898
if gateway_update.visibility is not None:
18991899
gateway.visibility = gateway_update.visibility
1900-
if gateway_update.visibility is not None:
1901-
gateway.visibility = gateway_update.visibility
1900+
# Propagate visibility to all linked items immediately so it
1901+
# takes effect even when the upstream server is unreachable
1902+
# and _initialize_gateway fails.
1903+
for tool in gateway.tools:
1904+
tool.visibility = gateway.visibility
1905+
for resource in gateway.resources:
1906+
resource.visibility = gateway.visibility
1907+
for prompt in gateway.prompts:
1908+
prompt.visibility = gateway.visibility
19021909
if gateway_update.passthrough_headers is not None:
19031910
if isinstance(gateway_update.passthrough_headers, list):
19041911
gateway.passthrough_headers = gateway_update.passthrough_headers

tests/unit/mcpgateway/services/test_gateway_service.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,56 @@ async def test_update_gateway_url_initialization_failure(self, gateway_service,
10591059
assert mock_gateway.url == url
10601060
test_db.commit.assert_called_once()
10611061

1062+
@pytest.mark.asyncio
1063+
async def test_update_gateway_visibility_propagates_when_init_fails(self, gateway_service, mock_gateway, test_db):
1064+
"""Visibility change must propagate to linked tools/prompts/resources even when gateway init fails."""
1065+
# Set up linked items with old visibility
1066+
mock_tool = MagicMock(spec=DbTool)
1067+
mock_tool.visibility = "public"
1068+
mock_resource = MagicMock(spec=DbResource)
1069+
mock_resource.visibility = "public"
1070+
mock_prompt = MagicMock(spec=DbPrompt)
1071+
mock_prompt.visibility = "public"
1072+
1073+
mock_gateway.visibility = "public"
1074+
mock_gateway.auth_type = "bearer"
1075+
mock_gateway.oauth_config = None
1076+
mock_gateway.auth_query_params = None
1077+
mock_gateway.slug = "test_gateway"
1078+
mock_gateway.tools = [mock_tool]
1079+
mock_gateway.resources = [mock_resource]
1080+
mock_gateway.prompts = [mock_prompt]
1081+
1082+
test_db.execute = Mock(return_value=_make_execute_result(scalar=mock_gateway))
1083+
test_db.commit = Mock()
1084+
test_db.refresh = Mock()
1085+
mock_query = Mock()
1086+
mock_query.filter.return_value = mock_query
1087+
mock_query.first.return_value = None
1088+
mock_query.all.return_value = []
1089+
test_db.query = Mock(return_value=mock_query)
1090+
1091+
# Gateway is unreachable
1092+
gateway_service._initialize_gateway = AsyncMock(side_effect=GatewayConnectionError("Connection failed"))
1093+
gateway_service._notify_gateway_updated = AsyncMock()
1094+
1095+
gateway_update = GatewayUpdate(visibility="team")
1096+
1097+
mock_gateway_read = MagicMock()
1098+
mock_gateway_read.masked.return_value = mock_gateway_read
1099+
1100+
with patch("mcpgateway.services.gateway_service.GatewayRead.model_validate", return_value=mock_gateway_read):
1101+
await gateway_service.update_gateway(test_db, 1, gateway_update)
1102+
1103+
# Gateway visibility updated
1104+
assert mock_gateway.visibility == "team"
1105+
# Linked items must also be updated even though init failed
1106+
assert mock_tool.visibility == "team", "Tool visibility not propagated when gateway init failed"
1107+
assert mock_resource.visibility == "team", "Resource visibility not propagated when gateway init failed"
1108+
assert mock_prompt.visibility == "team", "Prompt visibility not propagated when gateway init failed"
1109+
# Visibility changes must be persisted
1110+
test_db.commit.assert_called_once()
1111+
10621112
@pytest.mark.asyncio
10631113
async def test_update_gateway_partial_update(self, gateway_service, mock_gateway, test_db):
10641114
"""Test updating only some fields."""

0 commit comments

Comments
 (0)