Skip to content

[PERFORMANCE]: Fix N+1 Query in list_tools - Missing joinedload for gateway #1879

@crivetimihai

Description

@crivetimihai

Summary

The list_tools() method in tool_service.py triggers N+1 queries when accessing the gateway_slug property. Each tool causes a separate database query to load its gateway relationship.

Root Cause

Location: mcpgateway/services/tool_service.py:1504

The query is built without eager loading:

query = select(DbTool).order_by(desc(DbTool.created_at), desc(DbTool.id))

When convert_tool_to_read() accesses gateway_slug (line 536):

tool_dict["gateway_slug"] = getattr(tool, "gateway_slug", "") or ""

The gateway_slug hybrid property (db.py:2831) triggers lazy loading:

@hybrid_property
def gateway_slug(self) -> Optional[str]:
    return self.gateway.slug if self.gateway else None

Impact

  • With 50 tools: 51 queries instead of 1-2
  • At ~5ms per query: ~250ms overhead per request
  • At 2000 RPS with 20% hitting /tools: 100+ extra DB queries/second
  • Contributes to "idle in transaction" connection buildup

Fix

Add joinedload(DbTool.gateway) to the query:

from sqlalchemy.orm import joinedload

query = select(DbTool).options(joinedload(DbTool.gateway)).order_by(desc(DbTool.created_at), desc(DbTool.id))

Reference

list_server_tools() at line 1643 already uses the correct pattern:

select(DbTool).options(joinedload(DbTool.gateway))...

Verification

Existing test confirms the issue and fix:

  • tests/performance/test_db_query_patterns.py:68 - test_list_tools_with_gateway_n1_potential
  • tests/performance/test_db_query_patterns.py:91 - test_list_tools_with_eager_loading

Acceptance Criteria

  • Add joinedload(DbTool.gateway) to list_tools() query
  • Audit similar patterns in list_resources, list_prompts, list_servers
  • Verify with load test (make load-test-ui)
  • Passes make verify

Metadata

Metadata

Assignees

Labels

performancePerformance related itemspythonPython / backend development (FastAPI)

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions