Enhancement
Title: Sync tool functions fail with Windows COM (CoInitialize not called) due to thread pool execution
Description:
When a sync (non-async) tool function uses Windows COM-based libraries (e.g. uiautomation, comtypes, pywinauto), it fails with:
[WinError -2147221008] CoInitialize has not been called.
Root Cause:
FastMCP dispatches sync tool functions to a worker thread (likely via anyio.to_thread.run_sync or loop.run_in_executor). These worker threads don't have COM initialized, which breaks any tool that relies on Windows COM APIs.
In contrast, the official mcp SDK (mcp.server.fastmcp) calls sync functions directly in the event loop thread (return fn(**args)), so COM state is inherited from the main thread and everything works fine.
Minimal Reproduction:
from fastmcp import FastMCP
import uiautomation as auto
mcp = FastMCP("test")
@mcp.tool()
def list_windows() -> str:
"""List desktop windows via UI Automation (COM-based)."""
desktop = auto.GetRootControl()
return str([w.Name for w in desktop.GetChildren()[:5]])
if __name__ == "__main__":
mcp.run(transport="stdio")
Calling list_windows produces:
[WinError -2147221008] CoInitialize has not been called.
Current Workaround:
Manually call ctypes.windll.ole32.CoInitialize(None) at the start of every sync tool function.
Proposed Solution (any of):
- Call
CoInitialize/CoUninitialize automatically on worker threads (Windows only).
- Provide an option to run sync tools on the main thread (like the official
mcp SDK does), e.g.:
@mcp.tool(run_in_thread=False)
def my_com_tool(): ...
- Provide a server-level setting:
mcp = FastMCP("test", sync_tool_runner="main_thread") # or "thread_pool"
Environment:
- OS: Windows 10/11
- Python: 3.12+
- fastmcp: 3.x
- Affected libraries:
uiautomation, comtypes, or any COM-dependent library
Enhancement
Title: Sync tool functions fail with Windows COM (CoInitialize not called) due to thread pool execution
Description:
When a sync (non-async) tool function uses Windows COM-based libraries (e.g.
uiautomation,comtypes,pywinauto), it fails with:Root Cause:
FastMCP dispatches sync tool functions to a worker thread (likely via
anyio.to_thread.run_syncorloop.run_in_executor). These worker threads don't have COM initialized, which breaks any tool that relies on Windows COM APIs.In contrast, the official
mcpSDK (mcp.server.fastmcp) calls sync functions directly in the event loop thread (return fn(**args)), so COM state is inherited from the main thread and everything works fine.Minimal Reproduction:
Calling
list_windowsproduces:Current Workaround:
Manually call
ctypes.windll.ole32.CoInitialize(None)at the start of every sync tool function.Proposed Solution (any of):
CoInitialize/CoUninitializeautomatically on worker threads (Windows only).mcpSDK does), e.g.:Environment:
uiautomation,comtypes, or any COM-dependent library