feat: 对接 Agent MCP 能力

- 新增 runtime MCP 声明、ClientFactory、Toolkit 适配与工具别名映射

- 增加 MCP 环境检测与 stdio 环境变量透传

- 补齐 MCP 工具事件、审批与生命周期释放测试
This commit is contained in:
2026-05-29 11:08:39 +08:00
parent 2bc525c16e
commit 43f45956ff
24 changed files with 2559 additions and 55 deletions

View File

@@ -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) {
}
}