feat: 对接 Agent MCP 能力
- 新增 runtime MCP 声明、ClientFactory、Toolkit 适配与工具别名映射 - 增加 MCP 环境检测与 stdio 环境变量透传 - 补齐 MCP 工具事件、审批与生命周期释放测试
This commit is contained in:
@@ -14,6 +14,9 @@ import com.easyagents.agent.runtime.knowledge.AgentKnowledgeSpec;
|
||||
import com.easyagents.agent.runtime.knowledge.citation.AgentKnowledgeCitationMatcher;
|
||||
import com.easyagents.agent.runtime.knowledge.citation.HeuristicKnowledgeCitationMatcher;
|
||||
import com.easyagents.agent.runtime.message.*;
|
||||
import com.easyagents.agent.runtime.mcp.McpRegistration;
|
||||
import com.easyagents.agent.runtime.mcp.McpSpecValidator;
|
||||
import com.easyagents.agent.runtime.mcp.McpToolkitAdapter;
|
||||
import com.easyagents.agent.runtime.persistence.session.noop.NoopAgentSessionStore;
|
||||
import com.easyagents.agent.runtime.skill.AgentSkillBinding;
|
||||
import com.easyagents.agent.runtime.skill.AgentSkillRuntimeContext;
|
||||
@@ -36,6 +39,7 @@ import io.agentscope.core.skill.SkillBox;
|
||||
import io.agentscope.core.state.SessionKey;
|
||||
import io.agentscope.core.tool.AgentTool;
|
||||
import io.agentscope.core.tool.Toolkit;
|
||||
import io.agentscope.core.tool.mcp.McpClientWrapper;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Sinks;
|
||||
|
||||
@@ -57,6 +61,7 @@ public class AgentScopeReActRuntime implements AgentRuntime {
|
||||
private final AgentScopeSkillAdapter skillAdapter;
|
||||
private final AgentScopeMessageAdapter messageAdapter;
|
||||
private final AgentOperateToolAdapter operateToolAdapter = new AgentOperateToolAdapter();
|
||||
private final McpToolkitAdapter mcpToolkitAdapter = new McpToolkitAdapter();
|
||||
private final AgentKnowledgeCitationMatcher citationMatcher = new HeuristicKnowledgeCitationMatcher();
|
||||
private final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||
@@ -68,6 +73,7 @@ public class AgentScopeReActRuntime implements AgentRuntime {
|
||||
private Session session;
|
||||
private SessionKey sessionKey;
|
||||
private ReActAgent agent;
|
||||
private final List<McpClientWrapper> mcpClients = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
* 使用默认适配器创建运行时。
|
||||
@@ -112,15 +118,30 @@ public class AgentScopeReActRuntime implements AgentRuntime {
|
||||
if (!initialized.compareAndSet(false, true)) {
|
||||
throw new AgentRuntimeException("Agent runtime has already been initialized.");
|
||||
}
|
||||
this.initRequest = request;
|
||||
this.runtimeContext = createRuntimeContext(request);
|
||||
this.skillContext = AgentSkillRuntimeContext.from(request.getAgentDefinition().getSkillBoxSpec());
|
||||
this.approvalCoordinator = AgentToolApprovalCoordinator.enabled();
|
||||
this.turnContextHolder = new AgentRuntimeTurnContextHolder();
|
||||
this.session = new AgentScopeSessionAdapter(request.getSessionStore());
|
||||
this.sessionKey = AgentScopeSessionAdapter.sessionKey(request.getSessionId());
|
||||
this.agent = buildAgent(runtimeContext);
|
||||
this.agent.loadIfExists(session, sessionKey);
|
||||
try {
|
||||
this.initRequest = request;
|
||||
this.runtimeContext = createRuntimeContext(request);
|
||||
this.skillContext = AgentSkillRuntimeContext.from(request.getAgentDefinition().getSkillBoxSpec());
|
||||
this.approvalCoordinator = AgentToolApprovalCoordinator.enabled();
|
||||
this.turnContextHolder = new AgentRuntimeTurnContextHolder();
|
||||
this.session = new AgentScopeSessionAdapter(request.getSessionStore());
|
||||
this.sessionKey = AgentScopeSessionAdapter.sessionKey(request.getSessionId());
|
||||
this.agent = buildAgent(runtimeContext);
|
||||
this.agent.loadIfExists(session, sessionKey);
|
||||
} catch (RuntimeException error) {
|
||||
closeMcpClients();
|
||||
initialized.set(false);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭运行时并释放 MCP client。
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
closeMcpClients();
|
||||
initialized.set(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1054,12 +1075,14 @@ public class AgentScopeReActRuntime implements AgentRuntime {
|
||||
if (memory instanceof AutoContextMemory) {
|
||||
interceptors.add(new AutoContextInterceptor(eventBridge, memoryResult.getAutoContextConfig()));
|
||||
}
|
||||
List<AgentToolSpec> runtimeToolSpecs = mergeToolSpecs(definition.getToolSpecs(), toolkitBuildResult.mcpToolSpecs(),
|
||||
toolkitBuildResult.operateToolSpecs());
|
||||
interceptors.add(new ToolHitlInterceptor(eventBridge, approvalCoordinator,
|
||||
mergeToolSpecs(definition.getToolSpecs(), toolkitBuildResult.operateToolSpecs())));
|
||||
runtimeToolSpecs));
|
||||
// 注册旁路事件监听器与主线路干预器。观察器只发旁路事件,不修改 AgentScope HookEvent。
|
||||
List<AgentRuntimeObserver> observers = new ArrayList<>();
|
||||
observers.add(new SkillExecutionObserver(eventBridge, skillContext, skillBox));
|
||||
observers.add(new ToolExecutionObserver(eventBridge, skillContext));
|
||||
observers.add(new ToolExecutionObserver(eventBridge, skillContext, runtimeToolSpecs));
|
||||
observers.add(new ReasoningLifecycleObserver(eventBridge));
|
||||
observers.add(new AgentRuntimeErrorObserver(eventBridge));
|
||||
AgentRuntimeObservationManager observationManager =
|
||||
@@ -1098,7 +1121,7 @@ public class AgentScopeReActRuntime implements AgentRuntime {
|
||||
Toolkit toolkit) {
|
||||
Map<String, List<AgentTool>> skillTools = new LinkedHashMap<>();
|
||||
if (!context.getAgentDefinition().getExecutionOptions().isToolCallingEnabled()) {
|
||||
return new AgentScopeToolkitBuildResult(skillTools, List.of());
|
||||
return new AgentScopeToolkitBuildResult(skillTools, List.of(), List.of());
|
||||
}
|
||||
for (AgentToolSpec toolSpec : context.getAgentDefinition().getToolSpecs()) {
|
||||
AgentToolInvoker invoker = context.getToolInvokers().get(toolSpec.getName());
|
||||
@@ -1111,22 +1134,45 @@ public class AgentScopeReActRuntime implements AgentRuntime {
|
||||
skillTools.computeIfAbsent(skillBinding.getSkillId(), key -> new ArrayList<>()).add(agentTool);
|
||||
}
|
||||
}
|
||||
McpRegistration mcpRegistration = mcpToolkitAdapter.register(
|
||||
context.getAgentDefinition().getMcpSpecs(), toolkit);
|
||||
mcpClients.addAll(mcpRegistration.getClients());
|
||||
List<AgentToolSpec> operateToolSpecs = operateToolAdapter.register(
|
||||
context.getAgentDefinition().getOperateToolSpecs(), toolkit);
|
||||
return new AgentScopeToolkitBuildResult(skillTools, operateToolSpecs);
|
||||
McpSpecValidator.validateToolConflicts(context.getAgentDefinition().getToolSpecs(),
|
||||
mcpRegistration.getToolSpecs(), context.getAgentDefinition().getOperateToolSpecs());
|
||||
return new AgentScopeToolkitBuildResult(skillTools, mcpRegistration.getToolSpecs(), operateToolSpecs);
|
||||
}
|
||||
|
||||
private List<AgentToolSpec> mergeToolSpecs(List<AgentToolSpec> toolSpecs, List<AgentToolSpec> operateToolSpecs) {
|
||||
private List<AgentToolSpec> mergeToolSpecs(List<AgentToolSpec> toolSpecs,
|
||||
List<AgentToolSpec> mcpToolSpecs,
|
||||
List<AgentToolSpec> operateToolSpecs) {
|
||||
List<AgentToolSpec> merged = new ArrayList<>();
|
||||
if (toolSpecs != null) {
|
||||
merged.addAll(toolSpecs);
|
||||
}
|
||||
if (mcpToolSpecs != null) {
|
||||
merged.addAll(mcpToolSpecs);
|
||||
}
|
||||
if (operateToolSpecs != null) {
|
||||
merged.addAll(operateToolSpecs);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
private void closeMcpClients() {
|
||||
for (McpClientWrapper client : mcpClients) {
|
||||
if (client == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
client.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
mcpClients.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建聚合知识库的默认检索配置。
|
||||
*
|
||||
@@ -1163,6 +1209,7 @@ public class AgentScopeReActRuntime implements AgentRuntime {
|
||||
}
|
||||
|
||||
private record AgentScopeToolkitBuildResult(Map<String, List<AgentTool>> skillTools,
|
||||
List<AgentToolSpec> mcpToolSpecs,
|
||||
List<AgentToolSpec> operateToolSpecs) {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user