"""Dispatch MCP server — lets Hope spawn background tasks. The main agent calls dispatch_task(description) when the user asks for something long-running. The tool returns immediately with a task ID; the actual work runs in a background asyncio task via TaskWorker. Communication with the main agent process happens via /tmp/tasks/events.jsonl (the file-based registry). """ from __future__ import annotations import asyncio import logging from mcp.server.fastmcp import FastMCP logger = logging.getLogger("voice-agent.dispatch") mcp = FastMCP("dispatch") @mcp.tool() async def dispatch_task(description: str) -> str: """Spawn a background task to research or look something up. Use this when the user asks you to do something that will take more than a few seconds (research, look up news, multi-step investigation). The task runs in parallel while you continue the conversation. When it completes, the result will be delivered back to you automatically — you can tell the user "I'll let you know when I find out." Returns a short confirmation with the task ID. """ try: from agent.task_registry import registry from agent.task_worker import TaskWorker except ImportError: from task_registry import registry from task_worker import TaskWorker task = registry.create(description) worker = TaskWorker(task.id, description) asyncio.create_task(_run_worker(worker, task.id)) logger.info("Dispatched task %s: %s", task.id, description) return f"Task {task.id} started. I'll report back when it's done." async def _run_worker(worker: "TaskWorker", task_id: str): try: from agent.task_registry import registry except ImportError: from task_registry import registry try: await worker.run() except Exception as e: logger.exception("Task %s crashed: %s", task_id, e) registry.fail(task_id, str(e))