feat: HttpServlet Streamable HTTP server implementation (#290)
Implementation of the Streamable HTTP transport provider for the Servlet API. --- Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com> Co-authored-by: Christian Tzolov <christian.tzolov@broadcom.com> Co-authored-by: Zachary German <zdgerman@amazon.com>
This commit is contained in:
parent
73515346ca
commit
bde1b6beec
4 changed files with 2234 additions and 1 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;
|
||||
|
||||
/**
|
||||
* Tests for {@link McpAsyncServer} using
|
||||
* {@link HttpServletStreamableServerTransportProvider}.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
@Timeout(15)
|
||||
class HttpServletStreamableAsyncServerTests extends AbstractMcpAsyncServerTests {
|
||||
|
||||
protected McpStreamableServerTransportProvider createMcpTransportProvider() {
|
||||
return HttpServletStreamableServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.mcpEndpoint("/mcp/message")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected McpServer.AsyncSpecification<?> prepareAsyncServerBuilder() {
|
||||
return McpServer.async(createMcpTransportProvider());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2024 - 2024 the original author or authors.
|
||||
*/
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
|
||||
import io.modelcontextprotocol.server.McpServer.AsyncSpecification;
|
||||
import io.modelcontextprotocol.server.McpServer.SyncSpecification;
|
||||
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.server.transport.TomcatTestUtil;
|
||||
|
||||
class HttpServletStreamableIntegrationTests extends AbstractMcpClientServerIntegrationTests {
|
||||
|
||||
private static final int PORT = TomcatTestUtil.findAvailablePort();
|
||||
|
||||
private static final String MESSAGE_ENDPOINT = "/mcp/message";
|
||||
|
||||
private HttpServletStreamableServerTransportProvider mcpServerTransportProvider;
|
||||
|
||||
private Tomcat tomcat;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
// Create and configure the transport provider
|
||||
mcpServerTransportProvider = HttpServletStreamableServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.mcpEndpoint(MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
|
||||
tomcat = TomcatTestUtil.createTomcatServer("", PORT, mcpServerTransportProvider);
|
||||
try {
|
||||
tomcat.start();
|
||||
assertThat(tomcat.getServer().getState()).isEqualTo(LifecycleState.STARTED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Failed to start Tomcat", e);
|
||||
}
|
||||
|
||||
clientBuilders
|
||||
.put("httpclient",
|
||||
McpClient.sync(HttpClientStreamableHttpTransport.builder("http://localhost:" + PORT)
|
||||
.endpoint(MESSAGE_ENDPOINT)
|
||||
.build()).initializationTimeout(Duration.ofHours(10)).requestTimeout(Duration.ofHours(10)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AsyncSpecification<?> prepareAsyncServerBuilder() {
|
||||
return McpServer.async(this.mcpServerTransportProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SyncSpecification<?> prepareSyncServerBuilder() {
|
||||
return McpServer.sync(this.mcpServerTransportProvider);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
if (mcpServerTransportProvider != null) {
|
||||
mcpServerTransportProvider.closeGracefully().block();
|
||||
}
|
||||
if (tomcat != null) {
|
||||
try {
|
||||
tomcat.stop();
|
||||
tomcat.destroy();
|
||||
}
|
||||
catch (LifecycleException e) {
|
||||
throw new RuntimeException("Failed to stop Tomcat", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareClients(int port, String mcpEndpoint) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*/
|
||||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;
|
||||
|
||||
/**
|
||||
* Tests for {@link McpSyncServer} using
|
||||
* {@link HttpServletStreamableServerTransportProvider}.
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
@Timeout(15)
|
||||
class HttpServletStreamableSyncServerTests extends AbstractMcpSyncServerTests {
|
||||
|
||||
protected McpStreamableServerTransportProvider createMcpTransportProvider() {
|
||||
return HttpServletStreamableServerTransportProvider.builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.mcpEndpoint("/mcp/message")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected McpServer.SyncSpecification<?> prepareSyncServerBuilder() {
|
||||
return McpServer.sync(createMcpTransportProvider());
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue