tinyagent icon indicating copy to clipboard operation
tinyagent copied to clipboard

Fix MCP client multiple connections issue

Open askdevai-bot opened this issue 7 months ago • 0 comments

Problem

When using multiple MCP clients in tinyagent, closing one client would cause an error in other active clients:

tinyagent.mcp_client - ERROR - Error during client cleanup: Attempted to exit a cancel scope that isn't the current task's current cancel scope

Root Cause

The issue was caused by improper isolation between multiple MCP client instances when using AsyncExitStack. When multiple clients shared the same event loop, closing one client would interfere with the context management of other active clients.

Solution

This PR implements a comprehensive fix for the MCP client to support multiple concurrent connections:

Key Improvements

  1. Connection State Management: Added ConnectionState enum for proper state tracking
  2. Task Isolation: Implemented connection locks to prevent race conditions between multiple clients
  3. Safe Cleanup: Enhanced cleanup process that won't interfere with other active clients
  4. Better Error Handling: Improved error handling that doesn't propagate to other clients
  5. Async Context Manager: Added proper async context manager support (async with)
  6. Connection Validation: Added checks to ensure operations only happen when connected

Changes Made

  • Added ConnectionState enum to track client state
  • Implemented _connection_lock using asyncio.Lock() for thread-safe operations
  • Enhanced close() method with proper isolation and error handling
  • Added is_connected property and connection state validation
  • Implemented __aenter__ and __aexit__ for async context manager support
  • Improved _cleanup_connection() method for safer resource cleanup
  • Enhanced logging and error messages
  • Added comprehensive examples showing multiple client usage

Backward Compatibility

Fully backward compatible - existing code will continue to work without changes ✅ No additional dependencies - keeps tinyagent lightweight ✅ Same API - all existing methods work as before

Testing

The implementation includes comprehensive examples demonstrating:

  • Multiple clients working concurrently
  • Safe cleanup when closing individual clients
  • Async context manager usage
  • Proper error isolation between clients

Example Usage

# Multiple clients working together
clients = []
for i in range(3):
    client = MCPClient()
    await client.connect("python", ["-m", "mcp.examples.echo_server"])
    clients.append(client)

# Close one client - others continue working
await clients[0].close()  # No longer affects other clients

# Async context manager support
async with MCPClient() as client:
    await client.connect("python", ["-m", "mcp.examples.echo_server"])
    result = await client.call_tool("echo", {"message": "Hello!"})
# Automatically cleaned up

This fix resolves the cancel scope error and enables robust multiple MCP client usage in tinyagent applications.

askdevai-bot avatar May 29 '25 00:05 askdevai-bot