Skip to main content
Glama

IBKR TWS MCP Server

by haymant
FIX_EVENT_LOOP_ALREADY_RUNNING.md3.68 kB
# Fix: "this event loop is already running" Error ## Issue Fixed ✅ **Error:** `ibkr_stream_market_data` returned error "this event loop is already running." ## Root Cause The `ib_async` library's `waitOnUpdate()` method was trying to run an event loop inside an already-running event loop (the MCP server's event loop). This is not allowed in asyncio. ## Solution Replaced `self.ib.waitOnUpdate(timeout=...)` with proper event-based waiting using `updateEvent`: ### Before (Broken): ```python async def stream_market_data(self, req): while True: await self.ib.waitOnUpdate(timeout=2) # ❌ Tries to run event loop yield data ``` ### After (Fixed): ```python async def stream_market_data(self, req): while True: try: await asyncio.wait_for( ticker.updateEvent.wait(), # ✅ Properly awaits event timeout=2.0 ) ticker.updateEvent.clear() except asyncio.TimeoutError: yield {} # Keep-alive continue yield data ``` ## Files Modified ### 1. `src/tws_client.py` ✅ - **`stream_market_data()`** - Fixed to use `ticker.updateEvent.wait()` - **`stream_account_updates()`** - Fixed to use `ib.updateEvent.wait()` ### 2. `tests/unit/test_tws_client.py` ✅ - Updated `MockIB` to include sync methods: `positions()`, `placeOrder()` - Updated `test_stream_market_data_generator` to mock `updateEvent` - Updated assertions to check sync methods instead of async ones ## Changes Summary | Method | Old Approach | New Approach | |--------|-------------|--------------| | `stream_market_data()` | `await self.ib.waitOnUpdate(timeout=2)` | `await asyncio.wait_for(ticker.updateEvent.wait(), 2.0)` | | `stream_account_updates()` | `await self.ib.waitOnUpdate(timeout=5)` | `await asyncio.wait_for(self.ib.updateEvent.wait(), 5.0)` | ## Why This Works **ib_async provides event objects** that fire when updates occur: - `ticker.updateEvent` - Fires when market data updates - `ib.updateEvent` - Fires when any IB object updates These are standard `asyncio.Event` objects that can be properly awaited without trying to run a nested event loop. ## Test Results ```bash $ uv run pytest tests/unit/test_tws_client.py -v # Result: 6 passed in 1.23s ✅ ``` All unit tests passing, including: - ✅ `test_stream_market_data_generator` - Now properly mocks `updateEvent` - ✅ `test_get_positions` - Updated for sync `positions()` method - ✅ `test_place_market_order` - Updated for sync `placeOrder()` method ## Benefits 1. **✅ No event loop errors** - Properly integrates with MCP server's event loop 2. **✅ Efficient** - Uses event-based waiting instead of polling 3. **✅ Compatible with ib_async** - Uses the library's recommended pattern 4. **✅ Keep-alive support** - Yields empty dicts on timeout to prevent SSE disconnects ## Next Steps The streaming functions should now work properly when called through MCP: ### Test Streaming 1. **Start TWS** (make sure it's on port 7497 since that worked for you) 2. **Update .env** to use port 7497: ```env TWS_PORT=7497 ``` 3. **Start MCP server**: ```bash uv run python main.py ``` 4. **Connect via MCP Inspector** and test: - `ibkr_connect` - Should work (you already tested port 7497 ✅) - `ibkr_stream_market_data` - Should now work without event loop errors - `ibkr_stream_account_updates` - Should also work ## Status - ✅ Fixed "event loop already running" error - ✅ All unit tests passing - ✅ Connection to TWS working (port 7497) - ⏳ Ready to test streaming through MCP **The ibkr_stream_market_data tool should now work!** 🎉

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/haymant/tws-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server