Skip to content

Commit a236cc2

Browse files
authored
fix: ensure consistent DbTool creation across gateway registration, update, and rediscovery scenarios (IBM#937)
- Add _create_db_tool() helper method to centralize DbTool creation logic - Update toggle_gateway_status(), update_gateway(), and fetch_tools_after_oauth() methods to use the helper - Preserve federation metadata (federation_source, visibility, team_id, owner_email, etc.) consistently across all scenarios - Fix bug where tools lost federation context during reconnection and rediscovery operations This ensures that DbTool objects maintain their complete metadata regardless of whether they are created during initial registration, gateway updates, or health check rediscovery. Signed-off-by: Athavan Kanapuli <[email protected]>
1 parent e72569b commit a236cc2

File tree

1 file changed

+67
-42
lines changed

1 file changed

+67
-42
lines changed

mcpgateway/services/gateway_service.py

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -676,23 +676,14 @@ async def fetch_tools_after_oauth(self, db: Session, gateway_id: str) -> Dict[st
676676
continue
677677

678678
try:
679-
db_tool = DbTool(
680-
original_name=tool.name,
681-
custom_name=tool.name,
682-
custom_name_slug=slugify(tool.name),
683-
display_name=generate_display_name(tool.name),
684-
url=gateway.url.rstrip("/"),
685-
description=tool.description,
686-
integration_type="MCP", # Gateway-discovered tools are MCP type
687-
request_type=tool.request_type,
688-
headers=tool.headers,
689-
input_schema=tool.input_schema,
690-
annotations=tool.annotations,
691-
jsonpath_filter=tool.jsonpath_filter,
692-
auth_type=gateway.auth_type,
693-
auth_value=gateway.auth_value,
694-
gateway=gateway, # attach relationship to avoid NoneType during flush
679+
db_tool = self._create_db_tool(
680+
tool=tool,
681+
gateway=gateway,
682+
created_by="system",
683+
created_via="oauth",
695684
)
685+
# Attach relationship to avoid NoneType during flush
686+
db_tool.gateway = gateway
696687
tools_to_add.append(db_tool)
697688
except Exception as e:
698689
logger.warning(f"Failed to create DbTool for tool {getattr(tool, 'name', 'unknown')}: {e}")
@@ -941,20 +932,11 @@ async def update_gateway(self, db: Session, gateway_id: str, gateway_update: Gat
941932
existing_tool = db.execute(select(DbTool).where(DbTool.original_name == tool.name).where(DbTool.gateway_id == gateway_id)).scalar_one_or_none()
942933
if not existing_tool:
943934
gateway.tools.append(
944-
DbTool(
945-
original_name=tool.name,
946-
custom_name=tool.custom_name,
947-
custom_name_slug=slugify(tool.custom_name),
948-
display_name=generate_display_name(tool.custom_name),
949-
url=gateway.url,
950-
description=tool.description,
951-
integration_type="MCP", # Gateway-discovered tools are MCP type
952-
request_type=tool.request_type,
953-
headers=tool.headers,
954-
input_schema=tool.input_schema,
955-
jsonpath_filter=tool.jsonpath_filter,
956-
auth_type=gateway.auth_type,
957-
auth_value=gateway.auth_value,
935+
self._create_db_tool(
936+
tool=tool,
937+
gateway=gateway,
938+
created_by="system",
939+
created_via="update",
958940
)
959941
)
960942

@@ -1130,18 +1112,11 @@ async def toggle_gateway_status(self, db: Session, gateway_id: str, activate: bo
11301112
existing_tool = db.execute(select(DbTool).where(DbTool.original_name == tool.name).where(DbTool.gateway_id == gateway_id)).scalar_one_or_none()
11311113
if not existing_tool:
11321114
gateway.tools.append(
1133-
DbTool(
1134-
original_name=tool.name,
1135-
display_name=generate_display_name(tool.name),
1136-
url=gateway.url,
1137-
description=tool.description,
1138-
integration_type="MCP", # Gateway-discovered tools are MCP type
1139-
request_type=tool.request_type,
1140-
headers=tool.headers,
1141-
input_schema=tool.input_schema,
1142-
jsonpath_filter=tool.jsonpath_filter,
1143-
auth_type=gateway.auth_type,
1144-
auth_value=gateway.auth_value,
1115+
self._create_db_tool(
1116+
tool=tool,
1117+
gateway=gateway,
1118+
created_by="system",
1119+
created_via="rediscovery",
11451120
)
11461121
)
11471122

@@ -1943,6 +1918,56 @@ async def _notify_gateway_removed(self, gateway: DbGateway) -> None:
19431918
}
19441919
await self._publish_event(event)
19451920

1921+
def _create_db_tool(
1922+
self,
1923+
tool: ToolCreate,
1924+
gateway: DbGateway,
1925+
created_by: Optional[str] = None,
1926+
created_from_ip: Optional[str] = None,
1927+
created_via: Optional[str] = None,
1928+
created_user_agent: Optional[str] = None,
1929+
) -> DbTool:
1930+
"""Create a DbTool with consistent federation metadata across all scenarios.
1931+
1932+
Args:
1933+
tool: Tool creation schema
1934+
gateway: Gateway database object
1935+
created_by: Username who created/updated this tool
1936+
created_from_ip: IP address of creator
1937+
created_via: Creation method (ui, api, federation, rediscovery)
1938+
created_user_agent: User agent of creation request
1939+
1940+
Returns:
1941+
DbTool: Consistently configured database tool object
1942+
"""
1943+
return DbTool(
1944+
original_name=tool.name,
1945+
custom_name=tool.name,
1946+
custom_name_slug=slugify(tool.name),
1947+
display_name=generate_display_name(tool.name),
1948+
url=gateway.url,
1949+
description=tool.description,
1950+
integration_type="MCP", # Gateway-discovered tools are MCP type
1951+
request_type=tool.request_type,
1952+
headers=tool.headers,
1953+
input_schema=tool.input_schema,
1954+
annotations=tool.annotations,
1955+
jsonpath_filter=tool.jsonpath_filter,
1956+
auth_type=gateway.auth_type,
1957+
auth_value=gateway.auth_value,
1958+
# Federation metadata - consistent across all scenarios
1959+
created_by=created_by or "system",
1960+
created_from_ip=created_from_ip,
1961+
created_via=created_via or "federation",
1962+
created_user_agent=created_user_agent,
1963+
federation_source=gateway.name,
1964+
version=1,
1965+
# Inherit team assignment and visibility from gateway
1966+
team_id=gateway.team_id,
1967+
owner_email=gateway.owner_email,
1968+
visibility="public", # Federated tools should be public for discovery
1969+
)
1970+
19461971
async def _publish_event(self, event: Dict[str, Any]) -> None:
19471972
"""Publish event to all subscribers.
19481973

0 commit comments

Comments
 (0)