多路由隔离:构建模块化Agent工具服务器

在构建多Agent系统时,工具隔离是一个关键需求。通过Starlette和FastMCP,我们可以创建一个支持多路由隔离的工具服务器,让不同Agent调用各自专属的工具集。

核心思路:路由隔离工具集

python 复制代码
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP

# 创建多个独立的MCP实例
github_mcp = FastMCP("GitHub API")
browser_mcp = FastMCP("Browser")
curl_mcp = FastMCP("Curl")
search_mcp = FastMCP("Search")

# 应用配置
app = Starlette(
    routes=[
        Mount("/github", app=github_mcp.sse_app()),
        Mount("/browser", app=browser_mcp.sse_app()),
        Mount("/curl", app=curl_mcp.sse_app()),
        Mount("/search", app=search_mcp.sse_app()),
    ]
)

这种架构的关键优势在于:

  1. 工具隔离:每个路由下的工具相互独立
  2. 模块化设计:按功能划分工具组
  3. 独立扩展:不同工具集可以单独扩展和部署
  4. 权限控制:为不同Agent分配不同路由权限

工具定义示例

GitHub工具集(/github路由)

python 复制代码
@github_mcp.tool()
async def search_github_repos(query: str, limit: int = 10) -> Dict[str, Any]:
    """搜索GitHub仓库"""
    url = f"https://api.github.com/search/repositories?q={query}&per_page={limit}"
    response = requests.get(url)
    return response.json()

浏览器工具集(/browser路由)

python 复制代码
@browser_mcp.tool()
async def get_webpage_title(url: str) -> Dict[str, Any]:
    """获取网页标题"""
    try:
        response = requests.get(url, timeout=5)
        # 简单提取标题
        import re
        title_match = re.search(r'<title>(.*?)</title>', response.text, re.IGNORECASE | re.DOTALL)
        title = title_match.group(1) if title_match else "未找到标题"
        return {"url": url, "title": title}
    except Exception as e:
        return {"url": url, "error": str(e)}

客户端调用示例

不同Agent可以访问各自的路由:

python 复制代码
# GitHub Agent
github_client = Client("http://localhost:8000/github/sse")
await github_client.call_tool("search_github_repos", {"query": "AI"})

# 浏览器Agent
browser_client = Client("http://localhost:8000/browser/sse")
await browser_client.call_tool("get_webpage_title", {"url": "https://example.com"})

架构优势分析

  1. 职责分离:每个工具组专注于特定领域
  2. 安全隔离:敏感工具(如curl)可单独保护
  3. 性能优化:高负载工具可独立扩展
  4. 版本管理:不同工具组可独立升级

实际应用场景

  1. 多Agent协作系统:不同Agent使用不同工具集
  2. 微服务架构:每个路由作为独立微服务
  3. 权限分级系统:根据用户角色分配路由访问权限
  4. A/B测试环境:不同路由部署不同版本工具

总结

通过Starlette的路由挂载功能和FastMCP的工具管理能力,我们可以构建高度模块化的Agent工具服务器。这种架构不仅实现了工具隔离,还为系统的可扩展性和安全性提供了坚实基础。

python 复制代码
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

启动服务器后,不同Agent就可以通过各自的路由访问专属工具集,实现安全、高效的协作。

mcp 服务

python 复制代码
from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP

import requests

from typing import Dict, Any


# Create multiple MCP servers
github_mcp = FastMCP("GitHub API")
browser_mcp = FastMCP("Browser")
curl_mcp = FastMCP("Curl")
search_mcp = FastMCP("Search")


@github_mcp.tool()
async def search_github_repos(query: str, limit: int = 10) -> Dict[str, Any]:
    """
    搜索GitHub仓库
    
    Args:
        query: 搜索关键词
        limit: 返回结果数量限制,默认10个
        
    Returns:
        包含仓库信息的字典
    """
    url = f"https://api.github.com/search/repositories?q={query}&per_page={limit}"
    response = requests.get(url)
    return response.json()


@browser_mcp.tool()
async def get_webpage_title(url: str) -> Dict[str, Any]:
    """
    获取网页标题
    
    Args:
        url: 网页地址
        
    Returns:
        包含网页标题的字典
    """
    try:
        response = requests.get(url, timeout=5)
        # 简单提取标题
        import re
        title_match = re.search(r'<title>(.*?)</title>', response.text, re.IGNORECASE | re.DOTALL)
        title = title_match.group(1) if title_match else "未找到标题"
        return {"url": url, "title": title}
    except Exception as e:
        return {"url": url, "error": str(e)}


@curl_mcp.tool()
async def make_http_request(url: str, method: str = "GET", headers: Dict[str, str] = None) -> Dict[str, Any]:
    """
    发起HTTP请求
    
    Args:
        url: 请求地址
        method: HTTP方法,默认GET
        headers: 请求头
        
    Returns:
        HTTP响应结果
    """
    try:
        if headers is None:
            headers = {}
            
        response = requests.request(method, url, headers=headers)
        return {
            "status_code": response.status_code,
            "headers": dict(response.headers),
            "content": response.text[:1000]  # 限制返回内容长度
        }
    except Exception as e:
        return {"error": str(e)}


@search_mcp.tool()
async def search_text(query: str, texts: list) -> Dict[str, Any]:
    """
    在文本列表中搜索关键词
    
    Args:
        query: 搜索关键词
        texts: 要搜索的文本列表
        
    Returns:
        包含匹配文本的列表
    """
    results = []
    for i, text in enumerate(texts):
        if query.lower() in text.lower():
            results.append({"index": i, "text": text})
    return {"query": query, "results": results}


app = Starlette(
    routes=[
        # Using settings-based configuration
        Mount("/github", app=github_mcp.sse_app()),
        Mount("/browser", app=browser_mcp.sse_app()),
        Mount("/curl", app=curl_mcp.sse_app()),
        Mount("/search", app=search_mcp.sse_app()),
    ]
)


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

客户请求

python 复制代码
import asyncio
from fastmcp import Client

client = Client("http://localhost:8000/search/sse")

async def call_tool(name: str):
    async with client:
        result = await client.list_tools()
        print(result)
        result = await client.call_tool("search_text", {"query": name,"texts":["dfdsf","sdfsdfsf"]})
        print(result)

asyncio.run(call_tool("Ford"))




client = Client("http://localhost:8000/curl/sse")

async def call_tool(name: str):
    async with client:
        result = await client.list_tools()
        print(result)


asyncio.run(call_tool("Ford"))





client = Client("http://localhost:8000/browser/sse")

async def call_tool(name: str):
    async with client:
        result = await client.list_tools()
        print(result)


asyncio.run(call_tool("Ford"))


client = Client("http://localhost:8000/github/sse")

async def call_tool(name: str):
    async with client:
        result = await client.list_tools()
        print(result)


asyncio.run(call_tool("Ford"))
相关推荐
大树8810 小时前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠10 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质11 小时前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
小宇宙Zz11 小时前
Maven依赖冲突
java·服务器·maven
Inhand陈工12 小时前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智12 小时前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_12 小时前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
古城小栈12 小时前
Unix 与 Linux 异同小叙
linux·服务器·unix
施努卡机器视觉13 小时前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造
程序猿阿伟13 小时前
《Chrome离线扩展安装的底层逻辑与场景落地指南》
服务器·网络·chrome