Problem: When creating an MCP server with many tools, the code used
asyncio.gather to create all tools concurrently. Each tool creation involves
database operations (INSERT with upsert logic), leading to N concurrent
database connections.
Example: An MCP server with 50 tools creates 50 simultaneous database
connections during server creation, exhausting the connection pool.
Root cause: asyncio.gather(*[create_mcp_tool_async(...) for tool in tools])
processes all tool creations concurrently, each opening a DB session.
Solution: Create tools sequentially instead of concurrently. While this takes
longer for server creation, it prevents database connection pool exhaustion
and maintains error handling by catching exceptions per tool.
Changes:
- apps/core/letta/services/mcp_manager.py:
- Replaced asyncio.gather with sequential for loop
- Maintained return_exceptions=True behavior with try/except
- Added explanatory comment about db pool exhaustion prevention
Impact: With 50 MCP tools:
- Before: 50 concurrent DB connections (pool exhaustion)
- After: 1 DB connection at a time (no pool exhaustion)
Note: This follows the same pattern as PR #6617, #6619, and #6620 which
fixed similar issues in file operations, multi-agent execution, and file
status checks.