feat: 子代理继承主代理的 MCP 工具

- 为 McpToolWrapper 添加 Clone trait,支持工具实例复用
- 修改 build_subagent_tools 方法,支持传入 MCP 工具列表
- 调整 runtime 构建顺序:先等待 MCP 连接,再将 MCP 工具传递给子代理

子代理现在可以自动使用主代理配置的 MCP 工具(如 filesystem、fetch 等)。
This commit is contained in:
oudecheng 2026-05-26 11:53:40 +08:00
parent 861aa04690
commit 644f5f9132
3 changed files with 61 additions and 6 deletions

View File

@ -124,10 +124,51 @@ pub(crate) fn build_session_manager_with_sender(
factory
};
// Wait for MCP connections and collect MCP tools for subagents
// This needs to happen before building subagent tools
let mut mcp_tools_for_subagents: Vec<crate::mcp::tool_adapter::McpToolWrapper> = Vec::new();
if mcp_initializer.is_enabled() {
tokio::task::block_in_place(|| {
tokio::runtime::Handle::current().block_on(async {
// Wait for connections to complete
if let Err(e) = mcp_initializer.wait_for_connections().await {
tracing::error!(error = %e, "Failed to wait for MCP connections");
return;
}
// Collect MCP tools for subagents
if let Some(manager) = mcp_initializer.manager() {
let all_tools = manager.all_tools().await;
for (server_key, tool_info) in all_tools {
let wrapper = crate::mcp::tool_adapter::McpToolWrapper::new(
manager.clone(),
server_key.clone(),
tool_info,
);
mcp_tools_for_subagents.push(wrapper);
}
tracing::info!(
tool_count = mcp_tools_for_subagents.len(),
"Collected MCP tools for subagents"
);
}
})
});
}
// Create SubAgentRuntime (if task tool is enabled)
let (factory, task_repository): (_, Arc<dyn TaskRepository>) = if task_config.enabled {
let task_repository = Arc::new(InMemoryTaskRepository::new());
let subagent_tools = Arc::new(factory.build_subagent_tools());
// Build subagent tools with MCP tools
let subagent_tools = Arc::new(
factory.build_subagent_tools(
if mcp_tools_for_subagents.is_empty() {
None
} else {
Some(mcp_tools_for_subagents.clone())
}
)
);
// Create subagent catalog with discovery
let catalog = Arc::new(SubagentCatalog::discover(&subagents_config));
@ -157,14 +198,16 @@ pub(crate) fn build_session_manager_with_sender(
// Build base tools
let mut tools = factory.build();
// Register MCP tools (async)
// This waits briefly for connections, then registers available tools
// Register MCP tools to main agent (async)
// Note: MCP tools for subagents are already collected above
if mcp_initializer.is_enabled() {
tokio::task::block_in_place(|| {
tokio::runtime::Handle::current().block_on(async {
if let Err(e) = mcp_initializer.register_tools(&mut tools).await {
tracing::error!(error = %e, "Failed to register MCP tools");
// Register pre-collected MCP tools
for tool in mcp_tools_for_subagents {
tools.register(tool);
}
tracing::info!("Registered MCP tools to main agent");
})
});
}

View File

@ -142,7 +142,11 @@ impl ToolRegistryFactory {
}
/// 构建子代理专用工具集(不包含 task 工具防止递归)
pub(crate) fn build_subagent_tools(&self) -> ToolRegistry {
/// 可选地包含 MCP 工具(通过 mcp_tools 参数传递)
pub(crate) fn build_subagent_tools(
&self,
mcp_tools: Option<Vec<crate::mcp::tool_adapter::McpToolWrapper>>,
) -> ToolRegistry {
let mut registry = ToolRegistry::new();
// 基础工具
@ -194,6 +198,13 @@ impl ToolRegistryFactory {
registry.register(SessionSendTool::new(self.session_message_sender.clone()));
}
// 注册 MCP 工具(如果提供)
if let Some(mcp_tools) = mcp_tools {
for tool in mcp_tools {
registry.register(tool);
}
}
// 注意:不注册 task 工具,防止递归创建子代理
registry

View File

@ -9,6 +9,7 @@ use crate::mcp::client::McpClientManager;
use crate::tools::traits::{Tool as PicoBotTool, ToolResult};
/// Wrapper that adapts an MCP tool to PicoBot's Tool trait
#[derive(Clone)]
pub struct McpToolWrapper {
/// The MCP client manager
manager: Arc<McpClientManager>,