diff --git a/mcp/pom.xml b/mcp/pom.xml
index f9df2bb..536e103 100644
--- a/mcp/pom.xml
+++ b/mcp/pom.xml
@@ -3,13 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
-
- spring.ai.experiment
+ spring.ai.experimental
mcp
0.0.1-SNAPSHOT
mcp
@@ -43,6 +37,25 @@
reactor-core
+
+ org.assertj
+ assertj-core
+ 3.26.3
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.11.3
+ test
+
+
+ org.mockito
+ mockito-core
+ 5.11.0
+ test
+
+
- spring.ai.experiment
- mcp
+ spring.ai.experimental
+ mcp-spring-boot-demo
0.0.1-SNAPSHOT
- mcp
+ mcp-spring-boot-demo
Demo project for Spring Boot
@@ -36,7 +36,11 @@
org.springframework.ai
spring-ai-openai-spring-boot-starter
-
+
+ spring.ai.experimental
+ mcp
+ 0.0.1-SNAPSHOT
+
org.springframework.boot
spring-boot-starter-test
diff --git a/spring/src/main/java/spring/ai/mcp/McpApplication.java b/spring/src/main/java/spring/ai/mcp/McpApplication.java
index a9493db..6e79325 100644
--- a/spring/src/main/java/spring/ai/mcp/McpApplication.java
+++ b/spring/src/main/java/spring/ai/mcp/McpApplication.java
@@ -31,6 +31,7 @@ public class McpApplication {
.build();
var response = chatClient.prompt("What is the content of the test.txt file?").call().content();
+
System.out.println(response);
response = chatClient.prompt(
@@ -56,7 +57,7 @@ public class McpApplication {
var stdioParams = StdioServerParameters.builder("npx")
.args("-y", "@modelcontextprotocol/server-filesystem",
- "dir")
+ "/Users/christiantzolov/Dev/projects/demo/mcp-server/dir")
.build();
McpSyncClient mcpClient = null;
diff --git a/spring/src/main/java/spring/ai/mcp/McpFunctionCallback.java b/spring/src/main/java/spring/ai/mcp/McpFunctionCallback.java
index 453c381..d10caa2 100644
--- a/spring/src/main/java/spring/ai/mcp/McpFunctionCallback.java
+++ b/spring/src/main/java/spring/ai/mcp/McpFunctionCallback.java
@@ -17,7 +17,6 @@ package spring.ai.mcp;
import java.util.Map;
-import spring.ai.mcp.client.McpClient;
import spring.ai.mcp.client.McpSyncClient;
import spring.ai.mcp.spec.McpSchema.CallToolRequest;
import spring.ai.mcp.spec.McpSchema.CallToolResult;
diff --git a/spring/src/main/java/spring/ai/mcp/client/McpAsyncClient.java b/spring/src/main/java/spring/ai/mcp/client/McpAsyncClient.java
deleted file mode 100644
index 03c9f6d..0000000
--- a/spring/src/main/java/spring/ai/mcp/client/McpAsyncClient.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package spring.ai.mcp.client;
-
-import java.time.Duration;
-
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import reactor.core.publisher.Mono;
-import spring.ai.mcp.spec.McpAsyncTransport;
-import spring.ai.mcp.spec.McpSchema;
-
-public class McpAsyncClient extends McpAsyncSession {
-
- public McpAsyncClient(McpAsyncTransport transport) {
- this(transport, Duration.ofSeconds(10), new ObjectMapper());
- }
-
- public McpAsyncClient(McpAsyncTransport transport, Duration requestTimeout, ObjectMapper objectMapper) {
- super(requestTimeout, objectMapper, transport);
- }
-
-
- /**
- * The initialization phase MUST be the first interaction between client and server.
- * During this phase, the client and server:
- *
- * - Establish protocol version compatibility
- * - Exchange and negotiate capabilities
- * - Share implementation details
- *
- *
- * The client MUST initiate this phase by sending an initialize request containing:
- *
- * - The protocol version the client supports
- * - The client's capabilities
- * - Client implementation information
- *
- *
- * The server MUST respond with its own capabilities and information:
- * {@link McpSchema.ServerCapabilities}.
- * After successful initialization, the client MUST send an initialized notification
- * to indicate it is ready to begin normal operations.
- *
- *
- *
- * Initialization
- * Spec
- * @return the initialize result.
- */
- public Mono initialize() {
- McpSchema.InitializeRequest initializeRequest = new McpSchema.InitializeRequest(// @formatter:off
- McpSchema.LATEST_PROTOCOL_VERSION,
- new McpSchema.ClientCapabilities(null, new McpSchema.ClientCapabilities.RootCapabilities(true), null),
- new McpSchema.Implementation("mcp-java-client", "0.0.1")); // @formatter:on
-
- Mono result =
- this.sendRequest("initialize", initializeRequest, new TypeReference() {});
-
- return result.flatMap(initializeResult -> {
- if (!McpSchema.LATEST_PROTOCOL_VERSION.equals(initializeResult.protocolVersion())) {
- return Mono.error(
- new McpError("Unsupported protocol version from the server: "
- + initializeResult.protocolVersion()));
- } else {
- return this.sendNotification("notifications/initialized", null)
- .thenReturn(initializeResult);
- }
- });
- }
-
- /**
- * Send a roots/list_changed notification.
- */
- public Mono sendRootsListChanged() {
- return this.sendNotification("notifications/roots/list_changed");
- }
-
- /**
- * Send a synchronous ping request.
- */
- public Mono ping() {
- return this.sendRequest("ping", null,
- new TypeReference() {});
- }
-
- // --------------------------
- // Tools
- // --------------------------
- /**
- * Send a tools/call request.
- * @param callToolRequest the call tool request.
- * @return the call tool result.
- */
- public Mono callTool(McpSchema.CallToolRequest callToolRequest) {
- return this.sendRequest("tools/call", callToolRequest,
- new TypeReference() {});
- }
-
- /**
- * Send a tools/list request.
- * @return the list of tools result.
- */
- public Mono listTools(String cursor) {
- return this.sendRequest("tools/list", new McpSchema.PaginatedRequest(cursor),
- new TypeReference() {});
- }
-
- // --------------------------
- // Resources
- // --------------------------
-
- /**
- * Send a resources/list request.
- * @param cursor the cursor
- * @return the list of resources result.
- */
- public Mono listResources(String cursor) {
- return this.sendRequest("resources/list", new McpSchema.PaginatedRequest(cursor),
- new TypeReference() {});
- }
-
- /**
- * Send a resources/read request.
- * @param resource the resource to read
- * @return the resource content.
- */
- public Mono readResource(McpSchema.Resource resource) {
- return this.readResource(new McpSchema.ReadResourceRequest(resource.uri()));
- }
-
- /**
- * Send a resources/read request.
- * @param readResourceRequest the read resource request.
- * @return the resource content.
- */
- public Mono readResource(McpSchema.ReadResourceRequest readResourceRequest) {
- return this.sendRequest("resources/read", readResourceRequest,
- new TypeReference() {});
- }
-
- /**
- * Resource templates allow servers to expose parameterized resources using URI
- * templates. Arguments may be auto-completed through the completion API.
- *
- * Request a list of resource templates the server has.
- * @param cursor the cursor
- * @return the list of resource templates result.
- */
- public Mono listResourceTemplates(String cursor) {
- return this.sendRequest("resources/templates/list", new McpSchema.PaginatedRequest(cursor),
- new TypeReference() {});
- }
-
- /**
- * List Changed Notification. When the list of available resources changes, servers
- * that declared the listChanged capability SHOULD send a notification:
- */
- public Mono sendResourcesListChanged() {
- return this.sendNotification("notifications/resources/list_changed");
- }
-
- /**
- * Subscriptions. The protocol supports optional subscriptions to resource changes.
- * Clients can subscribe to specific resources and receive notifications when they
- * change.
- *
- * Send a resources/subscribe request.
- * @param subscribeRequest the subscribe request contains the uri of the resource to
- * subscribe to.
- */
- public Mono subscribeResource(McpSchema.SubscribeRequest subscribeRequest) {
- return this.sendRequest("resources/subscribe", subscribeRequest,
- new TypeReference() {});
- }
-
- /**
- * Send a resources/unsubscribe request.
- * @param unsubscribeRequest the unsubscribe request contains the uri of the resource
- * to unsubscribe from.
- */
- public Mono unsubscribeResource(McpSchema.UnsubscribeRequest unsubscribeRequest) {
- return this.sendRequest("resources/unsubscribe", unsubscribeRequest,
- new TypeReference() {});
- }
-}
diff --git a/spring/src/main/java/spring/ai/mcp/client/McpAsyncSession.java b/spring/src/main/java/spring/ai/mcp/client/McpAsyncSession.java
deleted file mode 100644
index 7adb4f1..0000000
--- a/spring/src/main/java/spring/ai/mcp/client/McpAsyncSession.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package spring.ai.mcp.client;
-
-import java.time.Duration;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import reactor.core.publisher.Mono;
-import reactor.core.publisher.MonoSink;
-import spring.ai.mcp.spec.McpAsyncTransport;
-import spring.ai.mcp.spec.McpTransport;
-
-import org.springframework.util.Assert;
-
-import spring.ai.mcp.spec.McpSchema;
-
-public class McpAsyncSession {
-
- private final ConcurrentHashMap