microsoft/autogen · critical · RuntimeError
MCP actor task crashed
Error message
MCP actor task crashed
What it means
call() checks whether the actor's background task (_actor_task) has already completed; if it has, the actor loop crashed (or exited) and every subsequent command would hang on the queue. It raises RuntimeError('MCP actor task crashed', exception) chaining the original exception that killed the loop — inspect the second argument for the root cause (stdio process death, protocol error, unhandled exception in _run_actor).
Source
Thrown at python/packages/autogen-ext/src/autogen_ext/tools/mcp/_actor.py:102
self._shutdown_future: asyncio.Future[Any] | None = None
self._active = False
self._initialize_result: mcp_types.InitializeResult | None = None
atexit.register(self._sync_shutdown)
@property
def initialize_result(self) -> mcp_types.InitializeResult | None:
return self._initialize_result
async def initialize(self) -> None:
if not self._active:
self._active = True
self._actor_task = asyncio.create_task(self._run_actor())
async def call(self, type: str, args: McpActorArgs | None = None) -> McpFuture:
if not self._active:
raise RuntimeError("MCP Actor not running, call initialize() first")
if self._actor_task and self._actor_task.done():
raise RuntimeError("MCP actor task crashed", self._actor_task.exception())
fut: asyncio.Future[McpFuture] = asyncio.Future()
if type in {"list_tools", "list_prompts", "list_resources", "list_resource_templates", "shutdown"}:
await self._command_queue.put({"type": type, "future": fut})
res = await fut
elif type in {"call_tool", "read_resource", "get_prompt"}:
if args is None:
raise ValueError(f"args is required for {type}")
name = args.get("name", None)
kwargs = args.get("kargs", {})
if type == "call_tool" and name is None:
raise ValueError("name is required for call_tool")
elif type == "read_resource":
uri = kwargs.get("uri", None)
if uri is None:
raise ValueError("uri is required for read_resource")
await self._command_queue.put({"type": type, "uri": uri, "future": fut})
elif type == "get_prompt":
if name is None:View on GitHub (pinned to 027ecf0a37)
Solutions
- Catch the RuntimeError and inspect .__cause__ / the second constructor argument to find the real failure.
- Fix the underlying cause: verify the MCP server command/args, that the binary is on PATH, and that credentials are valid.
- Recreate the actor (initialize() a fresh instance) rather than calling the dead one again — the crashed task never recovers.
- If the crash is inside your sampling/elicitation callback, fix the callback; its exception propagates and kills the actor loop.
Example fix
# before
actor = McpActor(server_params)
await actor.initialize()
await asyncio.sleep(60) # server dies meanwhile
tools = await actor.call("list_tools") # RuntimeError: MCP actor task crashed
# after
try:
tools = await actor.call("list_tools")
except RuntimeError as e:
cause = e.args[1] if len(e.args) > 1 else None
logger.error("actor crashed: %r", cause)
actor = McpActor(server_params)
await actor.initialize()
tools = await actor.call("list_tools") Defensive patterns
Strategy: retry
Validate before calling
task = actor._actor_task
crashed = task is not None and task.done() and not task.cancelled() and task.exception() is not None
if crashed:
logger.error("actor already crashed: %r", task.exception()) Try / catch
try:
res = await actor.call(cmd, args)
except RuntimeError as e:
if "crashed" in str(e):
cause = e.args[1] if len(e.args) > 1 else e
logger.error("MCP actor crashed: %r", cause)
actor = McpActor(session_factory)
await actor.initialize()
res = await actor.call(cmd, args) # one bounded retry
else:
raise Prevention
- Smoke-test the MCP server command manually (run the binary) before wiring it into the actor.
- Log the actor task exception when close/call fails so root causes are not lost.
- Keep sampling/elicitation callbacks exception-safe — an exception inside them kills the actor loop.
When it happens
Trigger: The underlying MCP server process dies (stdio transport: the spawned binary exits) or the session raises inside _run_actor; the next actor.call(...) detects _actor_task.done() and raises RuntimeError with the stored exception.
Common situations: MCP stdio server executable not found or crashing on startup; server closing the stream after auth failure; unhandled exception inside a sampling or elicitation callback; the actor task was garbage collected or cancelled externally; network disconnect for SSE/HTTP transports killing the loop.
Related errors
- MCP Actor not running, call initialize() first
- The team is already running, it cannot run again until it is
- The group chat is currently running. It must be stopped befo
- The team cannot be loaded while it is running.
- Failed to list MCP tools
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/74c479ee161ac1b1.
Report an issue: GitHub.