MCP热插拔多代理助手
通过模型上下文协议热插拔AI工具
一个生产级的人工智能代理平台,具有运行时工具热交换、LLM驱动的路由和全栈可观察性。通过删除Python文件可以添加新功能——无需重新启动代理,无需更改代码,也无需重新部署。
100%本地。 与Ollama一起完全在您的机器上运行。没有API密钥,没有云成本。
______________________________________________________________________
主要特点
- 热插拔工具架构 --工具服务器开始处于休眠状态(AST已扫描,未运行)。它们在单个查询生命周期内按需加载、执行和使用后自动分离。
- 动态工具发现 --路由器代理在启动时发现MCP服务器,并静态扫描休眠插件。新工具在通过REST API注册时立即出现。
- LLM供电路由 --Ollama(llama3.2)从自然语言中选择正确的工具;支持并行多工具调度
asyncio.gather(). - 自动参数校正 --当计数匹配时,将LLM生成的错误参数名称位置重新映射到架构正确的名称——零手动干预。
- 完全可观察性 --6普罗米修斯指标,带有预构建的Grafana仪表板,涵盖P50/P95/P99延迟、工具调用率和错误率。
- 对话记忆 --每个会话的聊天历史记录保存在Redis中,跨会话隔离。
- 一个命令部署 —
bash scripts/start.sh显示全部7项服务,完全有线。
______________________________________________________________________
🏗 建筑
它是如何工作的:
- 用户通过Streamlit UI发送自然语言查询
- FastAPI路由器代理将查询+可用工具列表发送给Ollama
- LLM决定调用哪些工具(零、一或多)
- 休眠服务器按需热插拔——加载、执行,然后自动分离
- 工具通过MCP stdio会话并行执行
- 结果被合成为单个响应
______________________________________________________________________
技术栈
| 层 | 技术 | 目的 |
|---|---|---|
| LLM | Ollama+llama3.2 | 本地推理,零成本工具布线 |
| 代理 | FastAPI+asyncio | 具有并行工具执行的异步路由器代理 |
| 工具协议 | MCP SDK(stdio传输) | 标准化的工具发现和执行 |
| 热插拔引擎 | AST扫描器+停止事件 | 休眠插件生命周期管理 |
| 注册表 | Redis哈希+排序集 | 工具元数据、服务器映射、脚本路径 |
| 聊天历史 | Redis列表(上限,50毫秒) | 每会话会话持久性 |
| UI | Streamlit | 聊天界面+服务器管理面板 |
| 监控 | 普罗米修斯+格拉法纳 | 6台仪器,P50/P95/P99延迟仪表板 |
| 编排 | Docker Compose | 7服务单命令部署 |
______________________________________________________________________
MCP工具服务器
| 服务器 | 工具 | 说明 |
|---|---|---|
| 计算器 *(休眠-按需热插拔)* | calculate, percentage, split_bill, unit_convert, loan_emi | 数学、转换、金融 |
| 网络研究 | search_web, fetch_url, summarize_url | DuckDuckGo搜索,页面抓取 |
| 笔记创建者 | create_note, create_note_from_topic, list_notes, read_note | 带YAML frontmatter的Markdown注释 |
| 油管 | get_transcript, summarize_video, ask_about_video | 转录提取、视频问答 |
4台服务器上共有14个工具。 计算器在需要之前保持休眠状态,证明零停机热插拔。
______________________________________________________________________
快速开始
先决条件
- Docker桌面(分配4 GB+RAM)
- Ollama与骆驼3.2拉
ollama pull llama3.2跑
git clone https://github.com/Arj-01/mcp-hotswap-agent.git
cd mcp-hotswap-agent
bash scripts/start.sh这将启动所有7个服务(API、前端、Redis、Ollama、Prometheus、Grafana),并自动提取LLM模型。
| 服务 | URL |
|---|---|
| 聊天界面 | http://localhost:8501 |
| 代理API | http://localhost:8000/docs |
| 格拉法纳 | http://localhost:3000(管理员/管理员) |
| 普罗米修斯 | http://localhost:9090 |
本地开发
# Install dependencies
pip install -e ".[dev]"
# Start Redis and Ollama
redis-server &
ollama serve &
# Start the API
uvicorn agents.main:app --reload --port 8000
# Start the frontend (separate terminal)
streamlit run frontend/app.py______________________________________________________________________
热交换演示
查看核心价值主张的实际应用——计算器服务器在启动时处于休眠状态,然后在会话中期热插拔:
零代码更改。零重启。
bash scripts/load_test.shServers at startup:
- youtube_summary_server (3 tools, active)
- notes_creator_server (4 tools, active)
- web_research_server (3 tools, active)
Dormant: calculator (calculate, percentage, split_bill, unit_convert, loan_emi)
Query 1: "search for latest AI news" → search_web hot-plug: NO
Query 2: "say hello in French" → none (LLM) hot-plug: NO
Query 4: "calculate 42 * 58" → calculate hot-plug: YES ⚡ calculator_server
Query 5: "search for python tutorials" → search_web hot-plug: NO (calculator detached)
Query 8: "calculate 15% of 8500" → calculate hot-plug: YES ⚡ fresh plug again
Query 11: "split bill of 2400 for 3" → split_bill hot-plug: YES ⚡ third cycle
ALL TESTS PASSED ✓ (12/12)
Hot-plug cycles: attached 3× · detached 3× · perfect symmetry______________________________________________________________________
API终点
| 方法 | 端点 | 描述 |
|---|---|---|
POST | /query | 向路由器代理发送查询 |
GET | /tools | 列出所有已注册的工具 |
GET | /servers | 列出已连接的MCP服务器 |
POST | /servers/register | 注册新的MCP服务器 |
DELETE | /servers/{name} | 断开服务器连接 |
GET | /chat/history/{session_id} | 获取对话历史记录 |
DELETE | /chat/history/{session_id} | 清除会话历史记录 |
GET | /health | 健康检查(服务器、工具、Redis) |
GET | /metrics | 普罗米修斯指标 |
______________________________________________________________________
监控
自动配置 MCP助理 Grafana仪表板包括:
| 面板 | 公制 |
|---|---|
| 查询总数 | sum(queries_total) |
| 活动服务器 | active_servers_count |
| 可用工具 | available_tools_count |
| 错误率 | queries_total{status="error"} /总计×100 |
| 每分钟查询次数 | rate(queries_total[1m]) * 60 |
| 响应时间P50/P95/P99 | histogram_quantile 超过 query_duration_seconds_bucket |
| 按服务器调用工具 | rate(tool_calls_total[5m]) 按服务器 |
| 工具响应时间 | histogram_quantile(0.95, ...) 通过工具 |
访问地址: http://localhost:3000 (管理员/管理员)
Grafana屏幕截图
Metrics Overview Query Latency Tool Calls Tool Response Time
______________________________________________________________________
聊天界面
______________________________________________________________________
添加自定义工具服务器
将Python文件放入 servers/:
# servers/my_tools_server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-tools")
@mcp.tool()
def greet(name: str) -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="stdio")通过API注册-无需重新启动:
curl -X POST http://localhost:8000/servers/register \
-H "Content-Type: application/json" \
-d '{"name": "my-tools", "script_path": "servers/my_tools_server.py"}'代理立即开始将查询路由到您的新工具。
______________________________________________________________________
项目结构
mcp-hotswap-agent/
├── agents/
│ ├── main.py # FastAPI app with all endpoints
│ ├── router_agent.py # LLM-powered tool routing + hot-swap logic
│ ├── mcp_client.py # MCP stdio session manager + AST plugin scanner
│ ├── tool_registry.py # Redis-backed tool storage (Hash + Sorted Set)
│ ├── chat_history.py # Session-isolated conversation persistence
│ ├── config.py # Settings (env vars)
│ └── metrics.py # Prometheus counters / histograms / gauges
├── servers/
│ ├── calculator_server.py # Math, finance, unit conversion (dormant)
│ ├── web_research_server.py # DuckDuckGo search, URL fetch
│ ├── notes_creator_server.py # Markdown notes with YAML frontmatter
│ └── youtube_summary_server.py # Transcript extraction, video Q&A
├── frontend/
│ └── app.py # Streamlit chat UI + server management
├── docker/
│ ├── Dockerfile
│ ├── Dockerfile.frontend
│ └── docker-compose.yml # 7-service orchestration
├── monitoring/
│ ├── prometheus.yml
│ ├── grafana-dashboard.json
│ ├── grafana-datasource.yml
│ └── grafana-dashboard-provider.yml
├── scripts/
│ ├── start.sh # One-command Docker startup
│ ├── load_test.sh # 12-query hot-swap verification test
│ └── e2e_smoke.sh # E2E smoke test against live stack
├── screenshots/
│ ├── architecture.png
│ └── grafana-metrics/
│ ├── metrics_1.png
│ ├── metrics_2.png
│ ├── metrics_3.png
│ └── metrics_4.png
├── tests/
│ ├── test_hotswap.py # Hot-plug lifecycle: attach → execute → detach → rescan
│ ├── test_integration.py # Full API flows (ASGI client + fakeredis)
│ ├── test_error_scenarios.py # Ollama offline, timeout, garbage JSON, tool errors
│ ├── test_param_correction.py # LLM param name correction edge cases
│ ├── test_chat_history.py # Session-isolated Redis chat history
│ └── test_tool_registry.py # Redis registry CRUD
└── pyproject.toml______________________________________________________________________
测试
# Run all 40+ tests
pytest tests/ -v
# Run specific modules
pytest tests/test_hotswap.py -v
pytest tests/test_integration.py -v
pytest tests/test_error_scenarios.py -v
# E2E smoke test (requires docker compose up)
bash scripts/e2e_smoke.sh
# Hot-swap load test (12 queries, 3 hot-plug cycles)
bash scripts/load_test.sh______________________________________________________________________
主要功能(详细)
- 热插拔生命周期 --休眠扫描→ 热插拔→ 执行→ 自动分离→ 重新扫描,在3个独立循环中通过完美的附着/分离对称性进行验证。
- 异步会话管理器 背景
asyncio.Task每个服务器都有停止事件信号,以实现清洁生命周期;连接失败时重试一次;会话丢失时自动重新连接。 - 并行工具执行 --多工具查询通过以下方式并发调度
asyncio.gather()具有每个工具的延迟跟踪功能。 - 参数自动校正 --当参数计数与模式匹配时,LLM键名的位置重新映射不匹配——在4种边缘情况下进行了测试。
- 测试了5种故障模式 --Ollama离线、ReadTimeout、垃圾JSON(重试+回退)、工具异常传播、合成失败回退到级联。
- Redis数据模型 —
tools:{name}搞砸,server_tools:{name}设置,tool_index排序集,chat:{session_id}capped List——所有操作都通过异步管道实现原子性。
