当前位置: 首页 > news >正文

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

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

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

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路由)

@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路由)

@browser_mcp.tool()
async def get_webpage_title(url: str) -> Dict[str, Any]:"""获取网页标题"""try:response = requests.get(url, timeout=5)# 简单提取标题import retitle_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可以访问各自的路由:

# 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工具服务器。这种架构不仅实现了工具隔离,还为系统的可扩展性和安全性提供了坚实基础。

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

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

mcp 服务

from starlette.applications import Starlette
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCPimport requestsfrom 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 retitle_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方法,默认GETheaders: 请求头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 configurationMount("/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 uvicornuvicorn.run(app, host="0.0.0.0", port=8000)

客户请求

import asyncio
from fastmcp import Clientclient = 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"))
http://www.dtcms.com/a/511268.html

相关文章:

  • [云计算] Classic Network-->VPC: 用SDN和Overlay实现隔离
  • linux shell编程实战 04 条件判断与流程控制
  • 10.21云计算作业
  • 服务器数据恢复—EqualLogic存储硬硬盘坏道,数据恢复有妙招
  • 风险识别不充分会让项目付出什么代价
  • LeetCode 46. 全排列
  • 洛谷 - P13982 数列分块入门 7(线段树解法 - 超详细版)
  • 页面PDF文件格式预览(不使用pdf.js)
  • Prompt Engineering 关键技能:精准掌控 LLM 输出的格式、内容与风格
  • 苹果(IOS)制作开发和发布证书
  • iOS 上架技术支持全流程解析,从签名配置到使用 开心上架 的实战经验分享
  • ISO 15765系列标准在车载诊断系统中的具体应用有哪些?
  • 人体含水量测量体验系统-VR节约用水互动游戏
  • 【ArcGIS软件教程】数据导出、CAD转换、属性表导出、裁剪、空间连接、修复几何
  • XYlease租赁商城小程序
  • 上海做网站建设平面设计线上培训班哪个好
  • 硬件语言:verilog(1)
  • 全排列——交换的思想
  • 【系统架构设计师(第2版)】六、数据库设计基础知识
  • LeetCode每日一题——缀点成线
  • COM组件访问权限错误的解决方案‌错误信息:检索 COM 类工厂中 CLSID 为{xxxx} 的组件失败,原因是出现以下错误:80070005 拒绝访问
  • 计算机组成原理 刘宏伟 第四章 存储器(下)
  • MS-YOLOv11:一种用于遥感图像中小目标检测的小波增强多尺度网络
  • 外贸企业网站设计公司龙中龙网站开发
  • 整站优化seo做电脑网站手机能显示不出来怎么办
  • Android设备GPU频点挡位路径
  • Vanna Text2SQL框架:用自然语言查询数据库的新方式
  • Android Studio新手开发第二十七天
  • ros中的Navigation导航系统
  • Python循环结构、控制语句及综合应用问答