多路由隔离:构建模块化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"))
相关推荐
未来之窗软件服务16 分钟前
幽冥大陆(十七)手机摄像头注册到电脑——东方仙盟炼气期
服务器·智能手机·电脑·服务器运维·东方仙盟·东方仙盟sdk
9ilk23 分钟前
【基于one-loop-per-thread的高并发服务器】--- 项目测试
运维·服务器·c++·后端·中间件
property-25 分钟前
服务器开荒:安装宝塔面板
运维·服务器
教练、我想打篮球41 分钟前
05 2个路由器配置dhcp服务器+dhcp中继器配置两个子网的dhcp服务
运维·服务器
adnyting43 分钟前
【Linux日新月异(二)】CentOS 7用户与用户组管理深度指南:保障系统安全的基石
linux·运维·centos
渡我白衣1 小时前
深入理解 OverlayFS:用分层的方式重新组织 Linux 文件系统
android·java·linux·运维·服务器·开发语言·人工智能
waves浪游1 小时前
进程概念(上)
linux·运维·服务器·开发语言·c++
顾安r1 小时前
11.15 脚本算法 加密网页
服务器·算法·flask·html·同态加密
司铭鸿1 小时前
数学图论的艺术:解码最小公倍数图中的连通奥秘
运维·开发语言·算法·游戏·图论
CXH7282 小时前
nginx-file-server
运维·数据库·nginx