源文件:chapter4/agent-with-event-trigger/README.md Event-Triggered AI Agent with MCP Tools A modern AI agent with native async support that responds to events from various sources. Built with FastAPI and integrated with 42 MCP tools for enhanced capabilities including browser automation, web search, document processing, and more.
源文件:chapter4/agent-with-event-trigger/README.md
A modern AI agent with native async support that responds to events from various sources. Built with FastAPI and integrated with 42 MCP tools for enhanced capabilities including browser automation, web search, document processing, and more.
/docsCollaboration Tools (18 tools):
Execution Tools (6 tools):
Perception Tools (18 tools):
在启动 HTTP 服务器之前,推荐先运行 event_loop_demo.py,它在单个进程里
直观演示本章的核心概念——外部世界主动唤醒 Agent。脚本注册三类"事件触发器",
由后台线程在事件真正发生时把结构化事件推入统一的事件队列,事件循环逐个取出
并唤醒 Agent 处理,形成"注册 → 触发 → 唤醒 → 处理"的完整闭环:
| 触发器 | 类 | 对应书中概念 |
|---|---|---|
| 一次性定时器 | OneShotTimer |
set_timer 一次性定时器(如"下周一 10:00 致电 DMV") |
| 循环定时器 | RecurringTimer |
set_timer 循环定时器 / Heartbeat(如"每小时检查服务器") |
| 文件监听 | FileWatchTrigger |
n8n 等平台的文件变更触发器 |
--mock 离线模式不调用大模型,用"模拟动作"打印 Agent 被唤醒后的处理过程,
因此无需任何 API Key 即可跑通:
# 离线演示全部触发器(一次性定时器 + 循环定时器 + 文件监听) python event_loop_demo.py --mock # 只演示一次性定时器;2 秒后触发,共运行 6 秒 python event_loop_demo.py --mock --trigger timer --delay 2 --duration 6 # 每 3 秒触发一次循环定时器 python event_loop_demo.py --mock --trigger recurring --interval 3 --duration 12 # 监听目录,向其中写入文件即可触发事件(另开终端 echo hello > watched_dir/a.txt) python event_loop_demo.py --mock --trigger file --watch-dir watched_dir
离线运行的输出示例(节选):
⏱️ [OneShotTimer(daily_backup_check)] 已注册:2 秒后触发 🔁 [RecurringTimer(health_check)] 已注册:每 3 秒触发一次 🟢 事件循环启动,将运行 8 秒,等待事件唤醒 Agent... ⚡ [OneShotTimer(daily_backup_check)] 触发事件 -> timer_trigger: 一次性定时器到期:请检查每日备份是否已经完成。 📥 事件循环取出第 1 个事件 -> 唤醒 Agent 🤖 Agent 被唤醒,收到消息: [Timer daily_backup_check triggered] 一次性定时器到期:请检查每日备份是否已经完成。 🛠️ [模拟动作] 读取定时任务上下文 -> 执行例行检查 -> 汇报结果 ✅ Agent 处理完成: 已响应 timer_trigger 事件
去掉 --mock 即接入真实的大模型(默认仅用内置工具,不加载 MCP),
需要设置对应 provider 的 API Key:
export KIMI_API_KEY='your-api-key-here' python event_loop_demo.py --trigger timer --provider kimi
OpenRouter 通用兜底:若所选 provider(默认
kimi)的 Key 缺失,但设置了OPENROUTER_API_KEY,event_loop_demo.py/server.py/quickstart.py会自动
改用openrouterprovider 继续运行(可用LLM_MODEL=openai/gpt-5.6-luna指定模型)。例如:OPENROUTER_API_KEY=sk-or-xxx LLM_MODEL=openai/gpt-5.6-luna python event_loop_demo.py --trigger timer
完整参数见 python event_loop_demo.py --help。
cd projects/week4/agent-with-event-trigger # Install dependencies (includes FastAPI, uvicorn, MCP SDK) pip install -r requirements.txt # Set up environment cp env.example .env # Edit .env and add your API key export KIMI_API_KEY='your-api-key-here'
python server.py
服务器支持命令行参数(优先级高于环境变量),完整列表见 python server.py --help:
python server.py --port 9000 # 自定义端口 python server.py --provider doubao # 指定大模型提供商 python server.py --no-mcp # 只用内置工具,不加载 MCP 工具
Output:
🤖 EVENT-TRIGGERED AGENT SERVER (FastAPI) ✅ Starting server on port 8000 📡 API Documentation: http://localhost:8000/docs 📊 ReDoc: http://localhost:8000/redoc 🚀 Starting Event-Triggered Agent Server (FastAPI) ✅ Agent initialized with kimi provider 🔄 MCP tools enabled (default) - loading asynchronously... ✅ Discovered tools from 'collaboration': 18 tools ✅ Discovered tools from 'execution': 6 tools ✅ Discovered tools from 'perception': 18 tools ✅ MCP tools loaded: 42 tools available ✅ Server ready to receive events INFO: Uvicorn running on http://0.0.0.0:8000
Visit http://localhost:8000/docs to:
# Health check curl http://localhost:8000/health # Check MCP tools status curl http://localhost:8000/mcp/status # Send an event curl -X POST http://localhost:8000/event \ -H "Content-Type: application/json" \ -d '{ "event_type": "web_message", "content": "Search the web for Python async best practices", "metadata": {"user": "demo"} }' # Get agent status curl http://localhost:8000/agent/status # Reset agent state curl -X POST http://localhost:8000/agent/reset # Reload MCP tools curl -X POST http://localhost:8000/mcp/reload
POST /event)For a complete demonstration of MCP integration without the server, run:
python example_with_mcp.py
This standalone script:
Output:
================================================================================ Event-Triggered Agent with MCP Tools Example ================================================================================ Initializing agent... ✅ Agent initialized with kimi provider Loading MCP tools... ✅ Discovered tools from 'collaboration': 18 tools ✅ Discovered tools from 'execution': 6 tools ✅ Discovered tools from 'perception': 18 tools ✅ MCP tools loaded: 42 tools available Testing Event Processing ================================================================================ 📥 RECEIVED EVENT: Search the web for 'Python async best practices'...
This is useful for:
curl -X POST http://localhost:8000/event \ -H "Content-Type: application/json" \ -d '{ "event_type": "web_message", "content": "Search for the latest FastAPI features and summarize them", "metadata": {"user": "demo"} }'
The agent will:
perception_web_search to find resultsperception_webpage_readercurl -X POST http://localhost:8000/event \ -H "Content-Type: application/json" \ -d '{ "event_type": "web_message", "content": "Navigate to example.com and take a screenshot", "metadata": {} }'
Uses:
collaboration_mcp_browser_navigatecollaboration_mcp_browser_screenshotcurl -X POST http://localhost:8000/event \ -H "Content-Type: application/json" \ -d '{ "event_type": "web_message", "content": "Download and summarize the PDF from https://example.com/doc.pdf", "metadata": {} }'
Uses:
perception_downloadperception_document_readercurl -X POST http://localhost:8000/event \ -H "Content-Type: application/json" \ -d '{ "event_type": "timer_trigger", "content": "Send daily report to admin@example.com", "metadata": {"scheduled": true} }'
Uses:
collaboration_mcp_send_email# Required export KIMI_API_KEY="your-key" # Optional export LLM_PROVIDER="kimi" # kimi, siliconflow, doubao, openrouter export LLM_MODEL="kimi-k3" # Override default model export AGENT_PORT="8000" # Server port (default: 8000) export ENABLE_MCP_TOOLS="true" # Enable MCP (default: true)
If you only want built-in tools:
ENABLE_MCP_TOOLS=false python server.py
AGENT_PORT=9000 python server.py
┌─────────────────────────────────────────────────────────┐ │ FastAPI Server │ │ (Native Async) │ └───────────┬─────────────────────────────────────────────┘ │ ├─► Lifespan Events (Startup/Shutdown) │ └─► Load MCP Tools Asynchronously │ ├─► Event Handler (Process incoming events) │ └─► EventTriggeredAgent │ ├─► System Hints (timestamps, TODOs) │ ├─► Tool Execution (MCP + built-in) │ └─► Trajectory Saving │ └─► MCP Server Manager ├─► Collaboration Tools (18 tools) ├─► Execution Tools (6 tools) └─► Perception Tools (18 tools)
agent-with-event-trigger/ ├── agent.py # Event-triggered agent with system hints ├── event_types.py # Event type definitions ├── event_loop_demo.py # Offline event-loop demo (timer / recurring / file-watch triggers) ├── server.py # FastAPI server (main entry point) ├── requirements.txt # Dependencies (FastAPI, uvicorn, MCP) ├── env.example # Environment template ├── README.md # This file ├── FASTAPI_GUIDE.md # Detailed FastAPI guide ├── MCP_INTEGRATION.md # MCP tools documentation └── example_with_mcp.py # Standalone MCP example
curl http://localhost:8000/mcp/status
Response shows:
tools: List of all 42 tool namestools_by_server: Tools grouped by servertools_count: Total countloaded: Whether MCP tools are activeMCP tools use underscore prefixes:
collaboration_* - Collaboration toolsexecution_* - Execution toolsperception_* - Perception toolsBuilt-in tools (no prefix):
read_filewrite_filecode_interpreterexecute_commandrewrite_todo_listupdate_todo_statusclass EventType(Enum): # External input events WEB_MESSAGE = "web_message" # Web interface IM_MESSAGE = "im_message" # Instant messaging EMAIL_REPLY = "email_reply" # Email responses GITHUB_PR_UPDATE = "github_pr_update" # PR notifications TIMER_TRIGGER = "timer_trigger" # Scheduled tasks (one-shot / recurring) FILE_CHANGE = "file_change" # File watch trigger (created / modified) # System reminder events USER_TIMEOUT = "user_timeout" # No user activity PROCESS_TIMEOUT = "process_timeout" # Long-running process SYSTEM_ALERT = "system_alert" # System warnings
{ "event_type": "web_message", "content": "Your task description", "metadata": { "user_id": "user123", "session_id": "session456" } }
The included client provides easy testing:
# Interactive mode python client.py --mode interactive # Test scenarios python client.py --mode test # Send a single event (defaults to web_message) python client.py --message "Create a Python hello world script" # Send a single event of a specific type python client.py --event-type timer_trigger --message "检查每日备份"
For production deployment:
| Feature | Old (Flask) | New (FastAPI) |
|---|---|---|
| Framework | Flask (WSGI) | FastAPI (ASGI) |
| Async Support | ❌ Threads | ✅ Native async/await |
| MCP Integration | ⚠️ Complex | ✅ Clean |
| API Docs | ❌ Manual | ✅ Auto-generated |
| Performance | Good | Better (2-3x) |
| Port | 4242 | 8000 |
| Deprecation Warnings | N/A | ✅ Fixed (lifespan) |
# Check what's using port 8000 lsof -i :8000 # Use different port AGENT_PORT=8001 python server.py
# Check status curl http://localhost:8000/mcp/status # Look for error in response # Common issue: Missing API keys for MCP servers # Reload tools curl -X POST http://localhost:8000/mcp/reload
# Reinstall dependencies pip install -r requirements.txt # Verify FastAPI installed python -c "import fastapi; print(fastapi.__version__)"
# Check health curl http://localhost:8000/health # View logs in server terminal # Check trajectory file: event_agent_trajectory.json
If upgrading from Flask version:
ENABLE_MCP_TOOLS=false to disableContributions welcome! Areas for improvement:
MIT License - See LICENSE file for details