feat: 对接 Agent MCP 能力
- 新增 runtime MCP 声明、ClientFactory、Toolkit 适配与工具别名映射 - 增加 MCP 环境检测与 stdio 环境变量透传 - 补齐 MCP 工具事件、审批与生命周期释放测试
This commit is contained in:
@@ -39,9 +39,12 @@ import io.agentscope.core.model.ToolSchema;
|
||||
import io.agentscope.core.skill.SkillBox;
|
||||
import io.agentscope.core.tool.AgentTool;
|
||||
import io.agentscope.core.tool.Toolkit;
|
||||
import io.agentscope.core.tool.mcp.McpClientWrapper;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.Sinks;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -255,6 +258,42 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
.anyMatch(PendingToolRecoveryHook.class::isInstance));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCloseMcpClientsWhenRuntimeCloses() throws Exception {
|
||||
AgentScopeReActRuntime runtime = fakeRuntime();
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("mcp-close");
|
||||
Field mcpClientsField = AgentScopeReActRuntime.class.getDeclaredField("mcpClients");
|
||||
mcpClientsField.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<McpClientWrapper> clients = (List<McpClientWrapper>) mcpClientsField.get(runtime);
|
||||
clients.add(client);
|
||||
|
||||
runtime.close();
|
||||
|
||||
Assert.assertTrue(client.closed.get());
|
||||
Assert.assertTrue(clients.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCloseMcpClientsEvenWhenRuntimeIsStreaming() throws Exception {
|
||||
AgentScopeReActRuntime runtime = fakeRuntime();
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("mcp-close-streaming");
|
||||
Field mcpClientsField = AgentScopeReActRuntime.class.getDeclaredField("mcpClients");
|
||||
mcpClientsField.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<McpClientWrapper> clients = (List<McpClientWrapper>) mcpClientsField.get(runtime);
|
||||
clients.add(client);
|
||||
Field runningField = AgentScopeReActRuntime.class.getDeclaredField("running");
|
||||
runningField.setAccessible(true);
|
||||
AtomicBoolean running = (AtomicBoolean) runningField.get(runtime);
|
||||
running.set(true);
|
||||
|
||||
runtime.close();
|
||||
|
||||
Assert.assertTrue(client.closed.get());
|
||||
Assert.assertTrue(clients.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEmitAutoContextCompressionEventsFromInterceptor() throws Exception {
|
||||
AgentInitRequest request = initRequest();
|
||||
@@ -403,7 +442,11 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
AgentRuntimeExecutionContext context = executionContext();
|
||||
Sinks.Many<AgentRuntimeEvent> sink = Sinks.many().replay().all();
|
||||
AgentRuntimeEventBridge bridge = AgentRuntimeEventBridge.fixed(context, sink);
|
||||
ToolExecutionObserver observer = new ToolExecutionObserver(bridge);
|
||||
AgentToolSpec toolSpec = new AgentToolSpec();
|
||||
toolSpec.setName("search");
|
||||
toolSpec.getMetadata().put("toolDisplayName", "Search Tool");
|
||||
toolSpec.getMetadata().put("rawMcpToolName", "search");
|
||||
ToolExecutionObserver observer = new ToolExecutionObserver(bridge, null, List.of(toolSpec));
|
||||
ReActAgent agent = initializedAgent();
|
||||
Toolkit toolkit = agent.getToolkit();
|
||||
ToolUseBlock toolUse = ToolUseBlock.builder()
|
||||
@@ -421,9 +464,12 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
Assert.assertEquals(AgentRuntimeEventType.TOOL_CALL, events.get(0).getEventType());
|
||||
Assert.assertEquals("RUNNING", events.get(0).getPayload().get("status"));
|
||||
Assert.assertEquals("PRE_ACTING", events.get(0).getPayload().get("phase"));
|
||||
Assert.assertEquals("Search Tool", events.get(0).getPayload().get("toolDisplayName"));
|
||||
Assert.assertEquals("search", events.get(0).getPayload().get("rawMcpToolName"));
|
||||
Assert.assertEquals(AgentRuntimeEventType.TOOL_RESULT, events.get(1).getEventType());
|
||||
Assert.assertEquals("SUCCESS", events.get(1).getPayload().get("status"));
|
||||
Assert.assertEquals("POST_ACTING", events.get(1).getPayload().get("phase"));
|
||||
Assert.assertEquals("Search Tool", events.get(1).getPayload().get("toolDisplayName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -712,6 +758,8 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
toolSpec.setDescription("search");
|
||||
toolSpec.setApprovalRequired(true);
|
||||
toolSpec.getApprovalRequest().setApprovalPrompt("Approve search?");
|
||||
toolSpec.getMetadata().put("toolDisplayName", "MCP Search - search");
|
||||
toolSpec.getMetadata().put("rawMcpToolName", "search");
|
||||
request.getAgentDefinition().setToolSpecs(List.of(toolSpec));
|
||||
AtomicBoolean invoked = new AtomicBoolean(false);
|
||||
request.setToolInvokers(Map.of("search", (arguments, context) -> {
|
||||
@@ -736,6 +784,12 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
Assert.assertFalse(invoked.get());
|
||||
Assert.assertTrue(events.stream()
|
||||
.anyMatch(event -> event.getEventType() == AgentRuntimeEventType.TOOL_APPROVAL_REQUIRED));
|
||||
AgentRuntimeEvent approval = events.stream()
|
||||
.filter(event -> event.getEventType() == AgentRuntimeEventType.TOOL_APPROVAL_REQUIRED)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
Assert.assertEquals("MCP Search - search", approval.getPayload().get("toolDisplayName"));
|
||||
Assert.assertEquals("search", approval.getPayload().get("rawMcpToolName"));
|
||||
AgentRuntimeEvent suspended = events.stream()
|
||||
.filter(event -> event.getEventType() == AgentRuntimeEventType.SUSPENDED)
|
||||
.findFirst()
|
||||
@@ -1117,6 +1171,37 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static class FakeMcpClientWrapper extends McpClientWrapper {
|
||||
|
||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||
|
||||
private FakeMcpClientWrapper(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> initialize() {
|
||||
initialized = true;
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<McpSchema.Tool>> listTools() {
|
||||
return Mono.just(List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<McpSchema.CallToolResult> callTool(String toolName, Map<String, Object> arguments) {
|
||||
return Mono.just(new McpSchema.CallToolResult(List.of(), false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed.set(true);
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
private AgentRuntimeExecutionContext executionContext() {
|
||||
AgentRuntimeExecutionContext context = new AgentRuntimeExecutionContext();
|
||||
AgentDefinition definition = new AgentDefinition();
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.easyagents.agent.runtime.mcp;
|
||||
|
||||
import com.easyagents.agent.runtime.AgentRuntimeException;
|
||||
import com.easyagents.agent.runtime.tool.AgentToolSpec;
|
||||
import com.easyagents.agent.runtime.tool.operate.AgentOperateToolAdapter;
|
||||
import com.easyagents.agent.runtime.tool.operate.AgentOperateToolSpec;
|
||||
import com.easyagents.agent.runtime.tool.operate.AgentOperateToolType;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 测试 MCP 声明校验器。
|
||||
*/
|
||||
public class McpSpecValidatorTest {
|
||||
|
||||
@Test(expected = AgentRuntimeException.class)
|
||||
public void shouldRejectMissingStdioCommand() {
|
||||
McpSpec spec = spec(McpTransportType.STDIO);
|
||||
|
||||
McpSpecValidator.validateConnection(spec);
|
||||
}
|
||||
|
||||
@Test(expected = AgentRuntimeException.class)
|
||||
public void shouldRejectMissingSseUrl() {
|
||||
McpSpec spec = spec(McpTransportType.SSE);
|
||||
|
||||
McpSpecValidator.validateConnection(spec);
|
||||
}
|
||||
|
||||
@Test(expected = AgentRuntimeException.class)
|
||||
public void shouldRejectMissingHttpUrl() {
|
||||
McpSpec spec = spec(McpTransportType.HTTP);
|
||||
|
||||
McpSpecValidator.validateConnection(spec);
|
||||
}
|
||||
|
||||
@Test(expected = AgentRuntimeException.class)
|
||||
public void shouldRejectMcpToolNameConflictWithBusinessTool() {
|
||||
AgentToolSpec businessTool = toolSpec("search");
|
||||
AgentToolSpec mcpTool = toolSpec("search");
|
||||
|
||||
McpSpecValidator.validateToolConflicts(List.of(businessTool), List.of(mcpTool), List.of());
|
||||
}
|
||||
|
||||
@Test(expected = AgentRuntimeException.class)
|
||||
public void shouldRejectMcpToolNameConflictWithOperateTool() {
|
||||
AgentToolSpec mcpTool = toolSpec(AgentOperateToolAdapter.EXECUTE_SHELL_COMMAND_TOOL);
|
||||
AgentOperateToolSpec operateTool = new AgentOperateToolSpec();
|
||||
operateTool.setType(AgentOperateToolType.SHELL);
|
||||
|
||||
McpSpecValidator.validateToolConflicts(List.of(), List.of(mcpTool), List.of(operateTool));
|
||||
}
|
||||
|
||||
@Test(expected = AgentRuntimeException.class)
|
||||
public void shouldRejectDuplicatedRuntimeToolAliases() {
|
||||
McpSpec spec = spec(McpTransportType.STDIO);
|
||||
spec.setCommand("node");
|
||||
spec.setToolAliases(Map.of("search", "mcp_1_tool", "search.v2", "mcp_1_tool"));
|
||||
|
||||
McpSpecValidator.validateConnection(spec);
|
||||
}
|
||||
|
||||
private McpSpec spec(McpTransportType type) {
|
||||
McpSpec spec = new McpSpec();
|
||||
spec.setName("mcp");
|
||||
spec.setTransportType(type);
|
||||
return spec;
|
||||
}
|
||||
|
||||
private AgentToolSpec toolSpec(String name) {
|
||||
AgentToolSpec spec = new AgentToolSpec();
|
||||
spec.setName(name);
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package com.easyagents.agent.runtime.mcp;
|
||||
|
||||
import com.easyagents.agent.runtime.AgentRuntimeException;
|
||||
import com.easyagents.agent.runtime.tool.AgentToolSpec;
|
||||
import io.agentscope.core.message.ToolResultBlock;
|
||||
import io.agentscope.core.tool.Toolkit;
|
||||
import io.agentscope.core.tool.mcp.McpClientWrapper;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 测试 MCP Toolkit 适配器。
|
||||
*/
|
||||
public class McpToolkitAdapterTest {
|
||||
|
||||
@Test
|
||||
public void shouldRegisterEnabledMcpToolsAndBuildRuntimeToolSpecs() {
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("demo",
|
||||
List.of(tool("search"), tool("write_file")));
|
||||
McpToolkitAdapter adapter = new McpToolkitAdapter(new FakeMcpClientFactory(client));
|
||||
McpSpec spec = stdioSpec();
|
||||
spec.setEnableTools(List.of("search"));
|
||||
spec.setApprovalRequired(true);
|
||||
spec.setMetadata(Map.of("owner", "runtime"));
|
||||
Toolkit toolkit = new Toolkit();
|
||||
|
||||
McpRegistration registration = adapter.register(List.of(spec), toolkit);
|
||||
|
||||
Assert.assertEquals(1, registration.getClients().size());
|
||||
Assert.assertEquals(1, registration.getToolSpecs().size());
|
||||
Assert.assertNotNull(toolkit.getTool("search"));
|
||||
Assert.assertNull(toolkit.getTool("write_file"));
|
||||
AgentToolSpec toolSpec = registration.getToolSpecs().get(0);
|
||||
Assert.assertEquals("search", toolSpec.getName());
|
||||
Assert.assertTrue(toolSpec.isApprovalRequired());
|
||||
Assert.assertEquals("MCP", toolSpec.getMetadata().get("source"));
|
||||
Assert.assertEquals("demo", toolSpec.getMetadata().get("mcpName"));
|
||||
Assert.assertEquals("stdio", toolSpec.getMetadata().get("transportType"));
|
||||
Assert.assertEquals("runtime", toolSpec.getMetadata().get("owner"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFilterSensitiveMetadataKeysFromRuntimeToolSpec() {
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("demo", List.of(tool("search")));
|
||||
McpToolkitAdapter adapter = new McpToolkitAdapter(new FakeMcpClientFactory(client));
|
||||
McpSpec spec = stdioSpec();
|
||||
spec.setMetadata(Map.of(
|
||||
"owner", "runtime",
|
||||
"apiKey", "secret-key",
|
||||
"Authorization", "Bearer secret-token",
|
||||
"password", "secret-password"));
|
||||
|
||||
McpRegistration registration = adapter.register(List.of(spec), new Toolkit());
|
||||
|
||||
Map<String, Object> metadata = registration.getToolSpecs().get(0).getMetadata();
|
||||
Assert.assertEquals("runtime", metadata.get("owner"));
|
||||
Assert.assertFalse(metadata.containsKey("apiKey"));
|
||||
Assert.assertFalse(metadata.containsKey("Authorization"));
|
||||
Assert.assertFalse(metadata.containsKey("password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRegisterAliasedMcpToolAndCallRawToolName() {
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("demo", List.of(tool("search")));
|
||||
McpToolkitAdapter adapter = new McpToolkitAdapter(new FakeMcpClientFactory(client));
|
||||
McpSpec spec = stdioSpec();
|
||||
spec.setEnableTools(List.of("mcp_1_search"));
|
||||
spec.setToolAliases(Map.of("search", "mcp_1_search"));
|
||||
Toolkit toolkit = new Toolkit();
|
||||
|
||||
McpRegistration registration = adapter.register(List.of(spec), toolkit);
|
||||
|
||||
Assert.assertNotNull(toolkit.getTool("mcp_1_search"));
|
||||
Assert.assertNull(toolkit.getTool("search"));
|
||||
AgentToolSpec toolSpec = registration.getToolSpecs().get(0);
|
||||
Assert.assertEquals("mcp_1_search", toolSpec.getName());
|
||||
Assert.assertEquals("search", toolSpec.getMetadata().get("rawMcpToolName"));
|
||||
registration.getClients().get(0).callTool("mcp_1_search", Map.of("q", "hello")).block();
|
||||
Assert.assertEquals("search", client.lastCalledToolName.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证未配置工具白名单时会为 MCP 下全部工具动态生成运行时别名。
|
||||
*/
|
||||
@Test
|
||||
public void shouldRegisterAllToolsWithDynamicPrefixAndCallRawToolName() {
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("demo",
|
||||
List.of(tool("search.tool"), tool("write-file")));
|
||||
McpToolkitAdapter adapter = new McpToolkitAdapter(new FakeMcpClientFactory(client));
|
||||
McpSpec spec = stdioSpec();
|
||||
spec.setDescription("Demo MCP");
|
||||
spec.setToolNamePrefix("mcp_20_");
|
||||
Toolkit toolkit = new Toolkit();
|
||||
|
||||
McpRegistration registration = adapter.register(List.of(spec), toolkit);
|
||||
|
||||
Assert.assertNotNull(toolkit.getTool("mcp_20_search_tool"));
|
||||
Assert.assertNotNull(toolkit.getTool("mcp_20_write-file"));
|
||||
Assert.assertNull(toolkit.getTool("search.tool"));
|
||||
Assert.assertEquals(2, registration.getToolSpecs().size());
|
||||
AgentToolSpec toolSpec = registration.getToolSpecs().get(0);
|
||||
Assert.assertEquals("mcp_20_search_tool", toolSpec.getName());
|
||||
Assert.assertEquals("search.tool", toolSpec.getMetadata().get("rawMcpToolName"));
|
||||
Assert.assertEquals("Demo MCP - search.tool", toolSpec.getMetadata().get("toolDisplayName"));
|
||||
registration.getClients().get(0).callTool("mcp_20_search_tool", Map.of("q", "hello")).block();
|
||||
Assert.assertEquals("search.tool", client.lastCalledToolName.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证动态别名安全化后发生重名时会自动追加序号。
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeduplicateDynamicAliasesAfterSanitizingToolNames() {
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("demo",
|
||||
List.of(tool("search.tool"), tool("search_tool")));
|
||||
McpToolkitAdapter adapter = new McpToolkitAdapter(new FakeMcpClientFactory(client));
|
||||
McpSpec spec = stdioSpec();
|
||||
spec.setToolNamePrefix("mcp_20_");
|
||||
Toolkit toolkit = new Toolkit();
|
||||
|
||||
McpRegistration registration = adapter.register(List.of(spec), toolkit);
|
||||
|
||||
Assert.assertNotNull(toolkit.getTool("mcp_20_search_tool"));
|
||||
Assert.assertNotNull(toolkit.getTool("mcp_20_search_tool_2"));
|
||||
Assert.assertEquals("search.tool", registration.getToolSpecs().get(0).getMetadata().get("rawMcpToolName"));
|
||||
Assert.assertEquals("search_tool", registration.getToolSpecs().get(1).getMetadata().get("rawMcpToolName"));
|
||||
registration.getClients().get(0).callTool("mcp_20_search_tool_2", Map.of("q", "hello")).block();
|
||||
Assert.assertEquals("search_tool", client.lastCalledToolName.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnEmptyToolSpecsWhenMcpServerHasNoTools() {
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("demo", List.of());
|
||||
McpToolkitAdapter adapter = new McpToolkitAdapter(new FakeMcpClientFactory(client));
|
||||
|
||||
McpRegistration registration = adapter.register(List.of(stdioSpec()), new Toolkit());
|
||||
|
||||
Assert.assertEquals(1, registration.getClients().size());
|
||||
Assert.assertTrue(registration.getToolSpecs().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCloseCreatedClientWhenRegistrationFails() {
|
||||
FakeMcpClientWrapper client = new FakeMcpClientWrapper("demo", List.of(tool("search")));
|
||||
client.failOnListTools = true;
|
||||
McpToolkitAdapter adapter = new McpToolkitAdapter(new FakeMcpClientFactory(client));
|
||||
|
||||
try {
|
||||
adapter.register(List.of(stdioSpec()), new Toolkit());
|
||||
Assert.fail("Expected MCP registration failure.");
|
||||
} catch (AgentRuntimeException | IllegalStateException ignored) {
|
||||
Assert.assertTrue(client.closed.get());
|
||||
}
|
||||
}
|
||||
|
||||
private McpSpec stdioSpec() {
|
||||
McpSpec spec = new McpSpec();
|
||||
spec.setName("demo");
|
||||
spec.setTransportType(McpTransportType.STDIO);
|
||||
spec.setCommand("node");
|
||||
spec.setTimeout(Duration.ofSeconds(10));
|
||||
spec.setInitializationTimeout(Duration.ofSeconds(3));
|
||||
return spec;
|
||||
}
|
||||
|
||||
private McpSchema.Tool tool(String name) {
|
||||
McpSchema.JsonSchema schema = new McpSchema.JsonSchema("object",
|
||||
Map.of("q", Map.of("type", "string", "description", "query")),
|
||||
List.of("q"), null, null, null);
|
||||
return new McpSchema.Tool(name, name, name + " description", schema, null, null, null);
|
||||
}
|
||||
|
||||
private static class FakeMcpClientFactory extends McpClientFactory {
|
||||
|
||||
private final McpClientWrapper client;
|
||||
|
||||
private FakeMcpClientFactory(McpClientWrapper client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public McpClientWrapper create(McpSpec spec) {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FakeMcpClientWrapper extends McpClientWrapper {
|
||||
|
||||
private final List<McpSchema.Tool> tools;
|
||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||
private final AtomicReference<String> lastCalledToolName = new AtomicReference<>();
|
||||
private boolean failOnListTools;
|
||||
|
||||
private FakeMcpClientWrapper(String name, List<McpSchema.Tool> tools) {
|
||||
super(name);
|
||||
this.tools = tools;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> initialize() {
|
||||
initialized = true;
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<McpSchema.Tool>> listTools() {
|
||||
if (failOnListTools) {
|
||||
return Mono.error(new IllegalStateException("list tools failed"));
|
||||
}
|
||||
return Mono.just(tools);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<McpSchema.CallToolResult> callTool(String toolName, Map<String, Object> arguments) {
|
||||
lastCalledToolName.set(toolName);
|
||||
return Mono.just(new McpSchema.CallToolResult(List.of(), false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed.set(true);
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.easyagents.agent.runtime.mcp;
|
||||
|
||||
import com.easyagents.agent.runtime.AgentRuntimeException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* 测试 MCP 连接方式解析。
|
||||
*/
|
||||
public class McpTransportTypeTest {
|
||||
|
||||
@Test
|
||||
public void shouldParseCompatibleTransportValues() {
|
||||
Assert.assertEquals(McpTransportType.STDIO, McpTransportType.from(null));
|
||||
Assert.assertEquals(McpTransportType.STDIO, McpTransportType.from("stdio"));
|
||||
Assert.assertEquals(McpTransportType.SSE, McpTransportType.from("http-sse"));
|
||||
Assert.assertEquals(McpTransportType.SSE, McpTransportType.from("SSE"));
|
||||
Assert.assertEquals(McpTransportType.HTTP, McpTransportType.from("http-stream"));
|
||||
Assert.assertEquals(McpTransportType.HTTP, McpTransportType.from("HTTP"));
|
||||
Assert.assertEquals(McpTransportType.HTTP, McpTransportType.from("streamable-http"));
|
||||
}
|
||||
|
||||
@Test(expected = AgentRuntimeException.class)
|
||||
public void shouldRejectUnsupportedTransportValue() {
|
||||
McpTransportType.from("websocket");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user