Skip to content

Commit dc48455

Browse files
authored
fix auth value db constraint (#1120)
Signed-off-by: Shoumi <[email protected]>
1 parent 15be93e commit dc48455

File tree

1 file changed

+42
-21
lines changed

1 file changed

+42
-21
lines changed

mcpgateway/services/gateway_service.py

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ async def register_gateway(
684684
# Notify subscribers
685685
await self._notify_gateway_added(db_gateway)
686686

687-
return GatewayRead.model_validate(db_gateway).masked()
687+
return GatewayRead.model_validate(self._prepare_gateway_for_read(db_gateway)).masked()
688688
except* GatewayConnectionError as ge: # pragma: no mutate
689689
if TYPE_CHECKING:
690690
ge: ExceptionGroup[GatewayConnectionError]
@@ -872,7 +872,7 @@ async def list_gateways(self, db: Session, include_inactive: bool = False, tags:
872872
# # print(f"Gateway auth_type: {g['auth_type']}")
873873
# print("******************************************************************")
874874

875-
return [GatewayRead.model_validate(g).masked() for g in gateways]
875+
return [GatewayRead.model_validate(self._prepare_gateway_for_read(g)).masked() for g in gateways]
876876

877877
async def list_gateways_for_user(
878878
self, db: Session, user_email: str, team_id: Optional[str] = None, visibility: Optional[str] = None, include_inactive: bool = False, skip: int = 0, limit: int = 100
@@ -936,7 +936,7 @@ async def list_gateways_for_user(
936936
query = query.offset(skip).limit(limit)
937937

938938
gateways = db.execute(query).scalars().all()
939-
return [GatewayRead.model_validate(g).masked() for g in gateways]
939+
return [GatewayRead.model_validate(self._prepare_gateway_for_read(g)).masked() for g in gateways]
940940

941941
async def update_gateway(
942942
self,
@@ -1083,19 +1083,21 @@ async def update_gateway(
10831083
if gateway_update.oauth_config is not None:
10841084
gateway.oauth_config = gateway_update.oauth_config
10851085

1086-
if getattr(gateway, "auth_value", "") != "":
1087-
token = gateway_update.auth_token
1088-
password = gateway_update.auth_password
1089-
header_value = gateway_update.auth_header_value
1090-
1091-
# Support multiple custom headers on update
1092-
if hasattr(gateway_update, "auth_headers") and gateway_update.auth_headers:
1093-
header_dict = {h["key"]: h["value"] for h in gateway_update.auth_headers if h.get("key")}
1094-
gateway.auth_value = header_dict # Store as dict for DB JSON field
1095-
elif settings.masked_auth_value not in (token, password, header_value):
1096-
# Check if values differ from existing ones
1097-
if gateway.auth_value != gateway_update.auth_value:
1098-
gateway.auth_value = decode_auth(gateway_update.auth_value) if isinstance(gateway_update.auth_value, str) else gateway_update.auth_value
1086+
# Handle auth_value updates (both existing and new auth values)
1087+
token = gateway_update.auth_token
1088+
password = gateway_update.auth_password
1089+
header_value = gateway_update.auth_header_value
1090+
1091+
# Support multiple custom headers on update
1092+
if hasattr(gateway_update, "auth_headers") and gateway_update.auth_headers:
1093+
header_dict = {h["key"]: h["value"] for h in gateway_update.auth_headers if h.get("key")}
1094+
gateway.auth_value = header_dict # Store as dict for DB JSON field
1095+
elif settings.masked_auth_value not in (token, password, header_value):
1096+
# Check if values differ from existing ones or if setting for first time
1097+
decoded_auth = decode_auth(gateway_update.auth_value) if gateway_update.auth_value else {}
1098+
current_auth = getattr(gateway, "auth_value", {}) or {}
1099+
if current_auth != decoded_auth:
1100+
gateway.auth_value = decoded_auth
10991101

11001102
# Try to reinitialize connection if URL changed
11011103
if gateway_update.url is not None:
@@ -1139,7 +1141,10 @@ async def update_gateway(
11391141
existing_tool.input_schema = tool.input_schema
11401142
existing_tool.jsonpath_filter = tool.jsonpath_filter
11411143
existing_tool.auth_type = gateway.auth_type
1142-
existing_tool.auth_value = gateway.auth_value
1144+
if isinstance(gateway.auth_value, dict):
1145+
existing_tool.auth_value = encode_auth(gateway.auth_value)
1146+
else:
1147+
existing_tool.auth_value = gateway.auth_value
11431148
existing_tool.visibility = gateway.visibility
11441149

11451150
# If the tool doesn't exist, create a new one
@@ -1221,7 +1226,7 @@ async def update_gateway(
12211226

12221227
logger.info(f"Updated gateway: {gateway.name}")
12231228

1224-
return GatewayRead.model_validate(gateway)
1229+
return GatewayRead.model_validate(self._prepare_gateway_for_read(gateway))
12251230
# Gateway is inactive and include_inactive is False → skip update, return None
12261231
return None
12271232
except GatewayNameConflictError as ge:
@@ -1295,7 +1300,7 @@ async def get_gateway(self, db: Session, gateway_id: str, include_inactive: bool
12951300
raise GatewayNotFoundError(f"Gateway not found: {gateway_id}")
12961301

12971302
if gateway.enabled or include_inactive:
1298-
return GatewayRead.model_validate(gateway).masked()
1303+
return GatewayRead.model_validate(self._prepare_gateway_for_read(gateway)).masked()
12991304

13001305
raise GatewayNotFoundError(f"Gateway not found: {gateway_id}")
13011306

@@ -1408,7 +1413,7 @@ async def toggle_gateway_status(self, db: Session, gateway_id: str, activate: bo
14081413

14091414
logger.info(f"Gateway status: {gateway.name} - {'enabled' if activate else 'disabled'} and {'accessible' if reachable else 'inaccessible'}")
14101415

1411-
return GatewayRead.model_validate(gateway).masked()
1416+
return GatewayRead.model_validate(self._prepare_gateway_for_read(gateway)).masked()
14121417

14131418
except Exception as e:
14141419
db.rollback()
@@ -2419,6 +2424,22 @@ async def _notify_gateway_removed(self, gateway: DbGateway) -> None:
24192424
}
24202425
await self._publish_event(event)
24212426

2427+
def _prepare_gateway_for_read(self, gateway: DbGateway) -> DbGateway:
2428+
"""Prepare a gateway object for GatewayRead validation.
2429+
2430+
Ensures auth_value is in the correct format (encoded string) for the schema.
2431+
2432+
Args:
2433+
gateway: Gateway database object
2434+
2435+
Returns:
2436+
Gateway object with properly formatted auth_value
2437+
"""
2438+
# If auth_value is a dict, encode it to string for GatewayRead schema
2439+
if isinstance(gateway.auth_value, dict):
2440+
gateway.auth_value = encode_auth(gateway.auth_value)
2441+
return gateway
2442+
24222443
def _create_db_tool(
24232444
self,
24242445
tool: ToolCreate,
@@ -2455,7 +2476,7 @@ def _create_db_tool(
24552476
annotations=tool.annotations,
24562477
jsonpath_filter=tool.jsonpath_filter,
24572478
auth_type=gateway.auth_type,
2458-
auth_value=gateway.auth_value,
2479+
auth_value=encode_auth(gateway.auth_value) if isinstance(gateway.auth_value, dict) else gateway.auth_value,
24592480
# Federation metadata - consistent across all scenarios
24602481
created_by=created_by or "system",
24612482
created_from_ip=created_from_ip,

0 commit comments

Comments
 (0)