diff --git a/README.md b/README.md
index a6b72e5..0d36311 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,13 @@
# Java & Spring MCP
-Java SDK for the Model Context Protocol (MCP), providing seamless integration between Java and Spring applications and MCP-compliant AI resources and tools.
+Set of projects that provide Java SDK and Spring Framework integration for the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture).
+It enables Java applications to interact with AI models and tools through a standardized interface, supporting both synchronous and asynchronous communication patterns.
-## Overview
+
-Provides Java and Spring Framework integration for the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture). It enables Java applications to interact with AI models and tools through a standardized interface, supporting both synchronous and asynchronous communication patterns.
+## Projects
-
-
-## Modules
-
-The project consists of two main modules:
-
-### [mcp](./mcp/README.md)
+### [MCP Java SDK](https://docs.spring.io/spring-ai-mcp/reference/mcp.html)
Java implementation of the Model Context Protocol specification. It includes:
- Synchronous and asynchronous [MCP Client](https://github.com/spring-projects-experimental/spring-ai-mcp/blob/main/mcp/README.md#client-usage-examples) and [MCP Server](https://github.com/spring-projects-experimental/spring-ai-mcp/blob/main/mcp/README.md#server-usage-examples) implementations
@@ -20,18 +15,13 @@ Java implementation of the Model Context Protocol specification. It includes:
- [Stdio](https://spec.modelcontextprotocol.io/specification/basic/transports/#stdio) and [SSE](https://spec.modelcontextprotocol.io/specification/basic/transports/#http-with-sse) transport implementations.
- [Find more](./mcp/README.md).
-### [spring-ai-mcp](./spring-ai-mcp/README.md)
+### [Spring AI MCP](https://docs.spring.io/spring-ai-mcp/reference/spring-mcp.html)
The Spring integration module provides Spring-specific functionality:
- Integration with Spring AI's function calling system
- Spring-friendly abstractions for MCP clients
- Auto-configurations (WIP)
-## Requirements
-
-- Java 17 or later
-- Maven 3.6 or later
-- Spring AI 1.0.0-M4 or later
## Installation
@@ -53,6 +43,23 @@ Add the following dependencies to your Maven project:
```
+This is a milestone release, not available on Maven Central.
+Add this repository to your POM:
+
+```xml
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/libs-milestone-local
+
+ false
+
+
+
+```
+
+
## Example Demos
Explore these MCP examples in the [spring-ai-examples/model-context-protocol](https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol) repository:
@@ -71,24 +78,18 @@ Explore these MCP examples in the [spring-ai-examples/model-context-protocol](ht
## Development
-### Building from Source
+- Building from Source
```bash
mvn clean install
```
-### Running Tests
+- Running Tests
```bash
mvn test
```
-## Project Information
-
-- **Group ID**: org.springframework.experimental
-- **Version**: 0.4.0-SNAPSHOT
-- **Java Version**: 17
-- **Spring AI Version**: 1.0.0-M4
## Contributing
diff --git a/docs/MCP-layers.svg b/docs/MCP-layers.svg
deleted file mode 100644
index 2f38d6a..0000000
--- a/docs/MCP-layers.svg
+++ /dev/null
@@ -1,181 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/spring-ai-mcp-architecture.jpg b/docs/spring-ai-mcp-architecture.jpg
deleted file mode 100644
index 7463b84..0000000
Binary files a/docs/spring-ai-mcp-architecture.jpg and /dev/null differ
diff --git a/docs/spring-ai-mcp-uml-classdiagram.svg b/docs/spring-ai-mcp-uml-classdiagram.svg
deleted file mode 100644
index 9636008..0000000
--- a/docs/spring-ai-mcp-uml-classdiagram.svg
+++ /dev/null
@@ -1 +0,0 @@
-McpTransport Mono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> handler) Mono<Void> sendMessage(JSONRPCMessage message) void close() Mono<Void> closeGracefully() <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) McpSession <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) Mono<Void> sendNotification(String method, Map<String, Object> params) Mono<Void> closeGracefully() void close() DefaultMcpSession McpTransport transport ObjectMapper objectMapper interface RequestHandler interface NotificationHandler McpClient Builder using(McpTransport transport) McpAsyncClient async(McpTransport transport) McpSyncClient sync(McpTransport transport) McpAsyncClient Mono<InitializeResult> initialize() Mono<CallToolResult> callTool(CallToolRequest request) Mono<ListToolsResult> listTools() Mono<ListResourcesResult> listResources() Mono<ReadResourceResult> readResource(ReadResourceRequest request) Mono<ListResourceTemplatesResult> listResourceTemplates() Mono<ListPromptsResult> listPrompts() Mono<GetPromptResult> getPrompt(GetPromptRequest request) McpSyncClient InitializeResult initialize() CallToolResult callTool(CallToolRequest request) ListToolsResult listTools() ListResourcesResult listResources() ReadResourceResult readResource(ReadResourceRequest request) ListResourceTemplatesResult listResourceTemplates() ListPromptsResult listPrompts() GetPromptResult getPrompt(GetPromptRequest request) McpServer Builder using(McpTransport transport) McpAsyncServer interface ToolHandler Mono<Void> addTool(ToolHandler toolHandler) Mono<Void> removeTool(String toolName) Mono<Void> notifyToolsListChanged() Mono<Void> notifyResourcesListChanged() Mono<Void> notifyPromptsListChanged() McpSyncServer void addTool(ToolHandler toolHandler) void removeTool(String toolName) void notifyToolsListChanged() void notifyResourcesListChanged() void notifyPromptsListChanged() McpAsyncServer getAsyncServer() StdioClientTransport Process serverProcess ServerParameters parameters SseClientTransport WebClient webClient StdioServerTransport SseServerTransport McpSchema class ErrorCodes interface Request interface JSONRPCMessage interface ResourceContents interface Content interface ServerCapabilities JSONRPCMessage deserializeJsonRpcMessage() McpError int code String message creates creates creates creates uses throws
\ No newline at end of file
diff --git a/mcp-docs/src/main/antora/modules/ROOT/images/class-diagrams.puml b/mcp-docs/src/main/antora/modules/ROOT/images/class-diagrams.puml
new file mode 100644
index 0000000..7a2dfe2
--- /dev/null
+++ b/mcp-docs/src/main/antora/modules/ROOT/images/class-diagrams.puml
@@ -0,0 +1,267 @@
+@startuml Core Components
+
+' Core Interfaces
+interface McpTransport {
+ +Mono connect(Function, Mono> handler)
+ +Mono sendMessage(JSONRPCMessage message)
+ +void close()
+ +Mono closeGracefully()
+ + T unmarshalFrom(Object data, TypeReference typeRef)
+}
+
+interface McpSession {
+ + Mono sendRequest(String method, Object requestParams, TypeReference typeRef)
+ +Mono sendNotification(String method, Map params)
+ +Mono closeGracefully()
+ +void close()
+}
+
+' Core Implementation Classes
+class DefaultMcpSession {
+ +interface RequestHandler
+ +interface NotificationHandler
+}
+
+' Client Classes
+class McpClient {
+ +{static} Builder using(ClientMcpTransport transport)
+}
+
+class McpAsyncClient {
+ +Mono initialize()
+ +ServerCapabilities getServerCapabilities()
+ +Implementation getServerInfo()
+ +ClientCapabilities getClientCapabilities()
+ +Implementation getClientInfo()
+ +void close()
+ +Mono closeGracefully()
+ +Mono ping()
+ +Mono addRoot(Root root)
+ +Mono removeRoot(String rootUri)
+ +Mono rootsListChangedNotification()
+ +Mono callTool(CallToolRequest request)
+ +Mono listTools()
+ +Mono listResources()
+ +Mono readResource(ReadResourceRequest request)
+ +Mono listResourceTemplates()
+ +Mono subscribeResource(SubscribeRequest request)
+ +Mono unsubscribeResource(UnsubscribeRequest request)
+ +Mono listPrompts()
+ +Mono getPrompt(GetPromptRequest request)
+ +Mono setLoggingLevel(LoggingLevel level)
+}
+
+class McpSyncClient {
+ +InitializeResult initialize()
+ +ServerCapabilities getServerCapabilities()
+ +Implementation getServerInfo()
+ +ClientCapabilities getClientCapabilities()
+ +Implementation getClientInfo()
+ +void close()
+ +boolean closeGracefully()
+ +Object ping()
+ +void addRoot(Root root)
+ +void removeRoot(String rootUri)
+ +void rootsListChangedNotification()
+ +CallToolResult callTool(CallToolRequest request)
+ +ListToolsResult listTools()
+ +ListResourcesResult listResources()
+ +ReadResourceResult readResource(ReadResourceRequest request)
+ +ListResourceTemplatesResult listResourceTemplates()
+ +void subscribeResource(SubscribeRequest request)
+ +void unsubscribeResource(UnsubscribeRequest request)
+ +ListPromptsResult listPrompts()
+ +GetPromptResult getPrompt(GetPromptRequest request)
+ +void setLoggingLevel(LoggingLevel level)
+}
+
+' Server Classes
+class McpServer {
+ +{static} Builder using(ServerMcpTransport transport)
+}
+
+class McpAsyncServer {
+
+ +ServerCapabilities getServerCapabilities()
+ +Implementation getServerInfo()
+ +ClientCapabilities getClientCapabilities()
+ +Implementation getClientInfo()
+ +void close()
+ +Mono closeGracefully()
+
+ ' Tool Management
+ +Mono addTool(ToolRegistration toolRegistration)
+ +Mono removeTool(String toolName)
+ +Mono notifyToolsListChanged()
+
+ ' Resource Management
+ +Mono addResource(ResourceRegistration resourceHandler)
+ +Mono removeResource(String resourceUri)
+ +Mono notifyResourcesListChanged()
+
+ ' Prompt Management
+ +Mono addPrompt(PromptRegistration promptRegistration)
+ +Mono removePrompt(String promptName)
+ +Mono notifyPromptsListChanged()
+
+ ' Logging
+ +Mono loggingNotification(LoggingMessageNotification notification)
+
+ ' Sampling
+ +Mono createMessage(CreateMessageRequest request)
+}
+
+class McpSyncServer {
+ +McpAsyncServer getAsyncServer()
+
+ +ServerCapabilities getServerCapabilities()
+ +Implementation getServerInfo()
+ +ClientCapabilities getClientCapabilities()
+ +Implementation getClientInfo()
+ +void close()
+ +void closeGracefully()
+
+ ' Tool Management
+ +void addTool(ToolRegistration toolHandler)
+ +void removeTool(String toolName)
+ +void notifyToolsListChanged()
+
+ ' Resource Management
+ +void addResource(ResourceRegistration resourceHandler)
+ +void removeResource(String resourceUri)
+ +void notifyResourcesListChanged()
+
+ ' Prompt Management
+ +void addPrompt(PromptRegistration promptRegistration)
+ +void removePrompt(String promptName)
+ +void notifyPromptsListChanged()
+
+ ' Logging
+ +void loggingNotification(LoggingMessageNotification notification)
+
+ ' Sampling
+ +CreateMessageResult createMessage(CreateMessageRequest request)
+}
+
+' Transport Implementations
+class StdioClientTransport implements ClientMcpTransport {
+ +void setErrorHandler(Consumer errorHandler)
+ +Sinks.Many getErrorSink()
+}
+
+class SseClientTransport implements ClientMcpTransport {
+}
+
+class StdioServerTransport implements ServerMcpTransport {
+}
+
+class SseServerTransport implements ServerMcpTransport {
+ +RouterFunction> getRouterFunction()
+}
+
+' Schema and Error Classes
+class McpSchema {
+ +class ErrorCodes
+ +interface Request
+ +interface JSONRPCMessage
+ +interface ResourceContents
+ +interface Content
+ +interface ServerCapabilities
+ +{static} JSONRPCMessage deserializeJsonRpcMessage()
+}
+
+class McpError {
+}
+
+' Relationships
+McpTransport <|.. ClientMcpTransport
+McpTransport <|.. ServerMcpTransport
+
+McpSession <|.. DefaultMcpSession
+DefaultMcpSession --o McpAsyncClient
+DefaultMcpSession --o McpAsyncServer
+
+McpClient ..> McpAsyncClient : creates
+McpClient ..> McpSyncClient : creates
+McpSyncClient --> McpAsyncClient : delegates to
+
+McpServer ..> McpAsyncServer : creates
+McpServer ..> McpSyncServer : creates
+McpSyncServer o-- McpAsyncServer
+
+DefaultMcpSession o-- McpTransport
+McpSchema <.. McpSession : uses
+McpError ..> McpSession : throws
+
+@enduml
+
+@startuml Message Flow
+
+package "MCP Schema" {
+ interface JSONRPCMessage {
+ +String jsonrpc()
+ }
+
+ interface Request {
+ }
+
+ class InitializeRequest
+ class CallToolRequest
+ class ListToolsRequest
+ class ListResourcesRequest
+ class ReadResourceRequest
+ class ListResourceTemplatesRequest
+ class ListPromptsRequest
+ class GetPromptRequest
+}
+
+package "Resource Types" {
+ interface ResourceContents {
+ +String uri()
+ +String mimeType()
+ }
+
+ class TextResourceContents
+ class BlobResourceContents
+
+ interface Content {
+ +String type()
+ }
+
+ class TextContent
+ class ImageContent
+ class EmbeddedResource
+
+ interface Annotated {
+ +Annotations annotations()
+ }
+
+ interface PromptOrResourceReference {
+ +String type()
+ }
+
+ class PromptReference
+ class ResourceReference
+}
+
+JSONRPCMessage <|.. Request
+Request <|.. InitializeRequest
+Request <|.. CallToolRequest
+Request <|.. ListToolsRequest
+Request <|.. ListResourcesRequest
+Request <|.. ReadResourceRequest
+Request <|.. ListResourceTemplatesRequest
+Request <|.. ListPromptsRequest
+Request <|.. GetPromptRequest
+
+ResourceContents <|.. TextResourceContents
+ResourceContents <|.. BlobResourceContents
+
+Content <|.. TextContent
+Content <|.. ImageContent
+Content <|.. EmbeddedResource
+
+PromptOrResourceReference <|.. PromptReference
+PromptOrResourceReference <|.. ResourceReference
+
+@enduml
diff --git a/mcp-docs/src/main/antora/modules/ROOT/images/spring-ai-mcp-uml-classdiagram.svg b/mcp-docs/src/main/antora/modules/ROOT/images/spring-ai-mcp-uml-classdiagram.svg
index 9636008..ecf2b64 100644
--- a/mcp-docs/src/main/antora/modules/ROOT/images/spring-ai-mcp-uml-classdiagram.svg
+++ b/mcp-docs/src/main/antora/modules/ROOT/images/spring-ai-mcp-uml-classdiagram.svg
@@ -1 +1 @@
-McpTransport Mono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> handler) Mono<Void> sendMessage(JSONRPCMessage message) void close() Mono<Void> closeGracefully() <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) McpSession <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) Mono<Void> sendNotification(String method, Map<String, Object> params) Mono<Void> closeGracefully() void close() DefaultMcpSession McpTransport transport ObjectMapper objectMapper interface RequestHandler interface NotificationHandler McpClient Builder using(McpTransport transport) McpAsyncClient async(McpTransport transport) McpSyncClient sync(McpTransport transport) McpAsyncClient Mono<InitializeResult> initialize() Mono<CallToolResult> callTool(CallToolRequest request) Mono<ListToolsResult> listTools() Mono<ListResourcesResult> listResources() Mono<ReadResourceResult> readResource(ReadResourceRequest request) Mono<ListResourceTemplatesResult> listResourceTemplates() Mono<ListPromptsResult> listPrompts() Mono<GetPromptResult> getPrompt(GetPromptRequest request) McpSyncClient InitializeResult initialize() CallToolResult callTool(CallToolRequest request) ListToolsResult listTools() ListResourcesResult listResources() ReadResourceResult readResource(ReadResourceRequest request) ListResourceTemplatesResult listResourceTemplates() ListPromptsResult listPrompts() GetPromptResult getPrompt(GetPromptRequest request) McpServer Builder using(McpTransport transport) McpAsyncServer interface ToolHandler Mono<Void> addTool(ToolHandler toolHandler) Mono<Void> removeTool(String toolName) Mono<Void> notifyToolsListChanged() Mono<Void> notifyResourcesListChanged() Mono<Void> notifyPromptsListChanged() McpSyncServer void addTool(ToolHandler toolHandler) void removeTool(String toolName) void notifyToolsListChanged() void notifyResourcesListChanged() void notifyPromptsListChanged() McpAsyncServer getAsyncServer() StdioClientTransport Process serverProcess ServerParameters parameters SseClientTransport WebClient webClient StdioServerTransport SseServerTransport McpSchema class ErrorCodes interface Request interface JSONRPCMessage interface ResourceContents interface Content interface ServerCapabilities JSONRPCMessage deserializeJsonRpcMessage() McpError int code String message creates creates creates creates uses throws
\ No newline at end of file
+McpTransport Mono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> handler) Mono<Void> sendMessage(JSONRPCMessage message) void close() Mono<Void> closeGracefully() <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) McpSession <T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef) Mono<Void> sendNotification(String method, Map<String, Object> params) Mono<Void> closeGracefully() void close() DefaultMcpSession interface RequestHandler interface NotificationHandler McpClient Builder using(ClientMcpTransport transport) McpAsyncClient Mono<InitializeResult> initialize() ServerCapabilities getServerCapabilities() Implementation getServerInfo() ClientCapabilities getClientCapabilities() Implementation getClientInfo() void close() Mono<Void> closeGracefully() Mono<Object> ping() Mono<Void> addRoot(Root root) Mono<Void> removeRoot(String rootUri) Mono<Void> rootsListChangedNotification() Mono<CallToolResult> callTool(CallToolRequest request) Mono<ListToolsResult> listTools() Mono<ListResourcesResult> listResources() Mono<ReadResourceResult> readResource(ReadResourceRequest request) Mono<ListResourceTemplatesResult> listResourceTemplates() Mono<Void> subscribeResource(SubscribeRequest request) Mono<Void> unsubscribeResource(UnsubscribeRequest request) Mono<ListPromptsResult> listPrompts() Mono<GetPromptResult> getPrompt(GetPromptRequest request) Mono<Void> setLoggingLevel(LoggingLevel level) McpSyncClient InitializeResult initialize() ServerCapabilities getServerCapabilities() Implementation getServerInfo() ClientCapabilities getClientCapabilities() Implementation getClientInfo() void close() boolean closeGracefully() Object ping() void addRoot(Root root) void removeRoot(String rootUri) void rootsListChangedNotification() CallToolResult callTool(CallToolRequest request) ListToolsResult listTools() ListResourcesResult listResources() ReadResourceResult readResource(ReadResourceRequest request) ListResourceTemplatesResult listResourceTemplates() void subscribeResource(SubscribeRequest request) void unsubscribeResource(UnsubscribeRequest request) ListPromptsResult listPrompts() GetPromptResult getPrompt(GetPromptRequest request) void setLoggingLevel(LoggingLevel level) McpServer Builder using(ServerMcpTransport transport) McpAsyncServer ServerCapabilities getServerCapabilities() Implementation getServerInfo() ClientCapabilities getClientCapabilities() Implementation getClientInfo() void close() Mono<Void> closeGracefully() Mono<Void> addTool(ToolRegistration toolRegistration) Mono<Void> removeTool(String toolName) Mono<Void> notifyToolsListChanged() Mono<Void> addResource(ResourceRegistration resourceHandler) Mono<Void> removeResource(String resourceUri) Mono<Void> notifyResourcesListChanged() Mono<Void> addPrompt(PromptRegistration promptRegistration) Mono<Void> removePrompt(String promptName) Mono<Void> notifyPromptsListChanged() Mono<Void> loggingNotification(LoggingMessageNotification notification) Mono<CreateMessageResult> createMessage(CreateMessageRequest request) McpSyncServer McpAsyncServer getAsyncServer() ServerCapabilities getServerCapabilities() Implementation getServerInfo() ClientCapabilities getClientCapabilities() Implementation getClientInfo() void close() void closeGracefully() void addTool(ToolRegistration toolHandler) void removeTool(String toolName) void notifyToolsListChanged() void addResource(ResourceRegistration resourceHandler) void removeResource(String resourceUri) void notifyResourcesListChanged() void addPrompt(PromptRegistration promptRegistration) void removePrompt(String promptName) void notifyPromptsListChanged() void loggingNotification(LoggingMessageNotification notification) CreateMessageResult createMessage(CreateMessageRequest request) StdioClientTransport void setErrorHandler(Consumer<String> errorHandler) Sinks.Many<String> getErrorSink() ClientMcpTransport SseClientTransport StdioServerTransport ServerMcpTransport SseServerTransport RouterFunction<?> getRouterFunction() McpSchema class ErrorCodes interface Request interface JSONRPCMessage interface ResourceContents interface Content interface ServerCapabilities JSONRPCMessage deserializeJsonRpcMessage() McpError creates creates delegates to creates creates uses throws
\ No newline at end of file
diff --git a/mcp-docs/src/main/antora/modules/ROOT/pages/mcp.adoc b/mcp-docs/src/main/antora/modules/ROOT/pages/mcp.adoc
index af7ca77..dc3755b 100644
--- a/mcp-docs/src/main/antora/modules/ROOT/pages/mcp.adoc
+++ b/mcp-docs/src/main/antora/modules/ROOT/pages/mcp.adoc
@@ -41,7 +41,7 @@ image::MCP-layers.svg[width=400,align=center]
Following class diagram illustrates the layered architecture of the MCP SDK, showing the relationships between core interfaces (McpTransport, McpSession), their implementations, and the client/server components. It highlights how the transport layer connects to sessions, which in turn support both synchronous and asynchronous client/server implementations.
-image::spring-ai-mcp-uml-classdiagram.svg[width=800]
+image::spring-ai-mcp-uml-classdiagram.svg[width=1000]
Key Interactions:
diff --git a/mcp-docs/src/main/antora/modules/ROOT/pages/overview.adoc b/mcp-docs/src/main/antora/modules/ROOT/pages/overview.adoc
index a45d2fd..04fe69f 100644
--- a/mcp-docs/src/main/antora/modules/ROOT/pages/overview.adoc
+++ b/mcp-docs/src/main/antora/modules/ROOT/pages/overview.adoc
@@ -1,16 +1,13 @@
= Java & Spring MCP
-Java SDK for the Model Context Protocol (MCP), providing seamless integration between Java and Spring applications and MCP-compliant AI resources and tools.
-
-== Overview
-
-Provides Java and Spring Framework integration for the link:https://modelcontextprotocol.org/docs/concepts/architecture[Model Context Protocol]. It enables Java applications to interact with AI models and tools through a standardized interface, supporting both synchronous and asynchronous communication patterns.
+Set of tools to provide Java SDK and Spring Framework integration for the link:https://modelcontextprotocol.org/docs/concepts/architecture[Model Context Protocol].
+It enables Java applications to interact with AI models and tools through a standardized interface, supporting both synchronous and asynchronous communication patterns.
image::spring-ai-mcp-architecture.jpg[Spring AI MCP Architecture,600]
-== Modules
+== Projects
-The project consists of two main modules:
+There are two main projects in this repository:
=== xref:mcp.adoc[MCP Java SDK]
@@ -57,7 +54,8 @@ Maven::
----
+
-This is a milestone release. It is not available on Maven Central. Add this repository to your POM:
+This is a milestone release, not available on Maven Central.
+Add this repository to your POM:
+
[source,xml]
----
diff --git a/mcp/README.md b/mcp/README.md
index f51b0be..0fcffcb 100644
--- a/mcp/README.md
+++ b/mcp/README.md
@@ -2,443 +2,4 @@
Java SDK implementation of the Model Context Protocol, enabling seamless integration with language models and AI tools.
-## Features
-
-- Synchronous and Asynchronous MCP Client and MCP Server implementations
-- Standard MCP operations support:
- - Protocol version compatibility negotiation
- - Tool discovery and execution with change notifications
- - Tool list change notifications with non-blocking consumer support
- - Resource management with URI templates
- - Resource subscription system
- - Roots list management and notifications
- - Prompt handling and management
-- Multiple transport implementations:
- - Stdio-based transport for process-based communication
- - SSE-based transport for HTTP streaming
-- Configurable request timeouts
-
-## Installation
-
-Add the following dependency to your Maven project:
-
-```xml
-
- org.springframework.experimental
- mcp
- 0.4.0-SNAPSHOT
-
-```
-
-## Architecture
-
-The SDK follows a layered architecture with clear separation of concerns:
-
-### Core Components Hierarchy
-
-
-
-- **Transport Layer (McpTransport)**: Handles JSON-RPC message serialization/deserialization via StdioTransport (stdin/stdout) and SseTransport (HTTP streaming).
-- **Session Layer (McpSession)**: Manages communication patterns and state using DefaultMcpSession implementation.
-- **Client/Server Layer**: Both use McpSession for sync/async operations, with McpClient handling client-side protocol operations and McpServer managing server-side protocol operations.
-
-Following class diagram illustrates the layered architecture of the MCP SDK, showing the relationships between core interfaces (McpTransport, McpSession), their implementations, and the client/server components. It highlights how the transport layer connects to sessions, which in turn support both synchronous and asynchronous client/server implementations.
-
-
-
-### Key Interactions
-
-- **Client/Server Initialization**: Transport setup, protocol compatibility check, capability negotiation, and implementation details exchange.
-- **Message Flow**: JSON-RPC message handling with validation, type-safe response processing, and error handling.
-- **Resource Management**: Resource discovery, URI template-based access, subscription system, and content retrieval.
-- **Prompt System**: Discovery, parameter-based retrieval, change notifications, and content management.
-- **Tool Execution**: Discovery, parameter validation, timeout-aware execution, and result processing.
-
-
-## Client Usage Examples
-
-### MCP Client (Sync API)
-
-```java
-// Create a sync client with custom configuration
-McpSyncClient client = McpClient.using(transport)
- .requestTimeout(Duration.ofSeconds(10))
- .capabilities(ClientCapabilities.builder()
- .roots(true) // Enable roots capability
- .sampling() // Enable sampling capability
- .build())
- .sync();
-
-// Initialize connection
-client.initialize();
-
-// List available tools
-ListToolsResult tools = client.listTools();
-
-// Call a tool
-CallToolResult result = client.callTool(
- new CallToolRequest("calculator",
- Map.of("operation", "add", "a", 2, "b", 3))
-);
-
-// List and read resources
-ListResourcesResult resources = client.listResources();
-ReadResourceResult resource = client.readResource(
- new ReadResourceRequest("resource://uri")
-);
-
-// List and use prompts
-ListPromptsResult prompts = client.listPrompts();
-GetPromptResult prompt = client.getPrompt(
- new GetPromptRequest("greeting", Map.of("name", "Spring"))
-);
-
-// Add/remove roots
-client.addRoot(new Root("file:///path", "description"));
-client.removeRoot("file:///path");
-client.rootsListChangedNotification();
-
-// Close client
-client.closeGracefully();
-```
-
-### MCP Client (Async API)
-
-```java
-// Create an async client with custom configuration
-McpAsyncClient client = McpClient.using(transport)
- .requestTimeout(Duration.ofSeconds(10))
- .capabilities(ClientCapabilities.builder()
- .roots(true) // Enable roots capability
- .sampling() // Enable sampling capability
- .build())
- .toolsChangeConsumer(tools -> {
- logger.info("Tools updated: {}", tools);
- })
- .resourcesChangeConsumer(resources -> {
- logger.info("Resources updated: {}", resources);
- })
- .promptsChangeConsumer(prompts -> {
- logger.info("Prompts updated: {}", prompts);
- })
- .async();
-
-// Initialize connection
-client.initialize()
- .flatMap(initResult -> {
- // List available tools
- return client.listTools();
- })
- .flatMap(tools -> {
- // Call a tool
- return client.callTool(new CallToolRequest(
- "calculator",
- Map.of("operation", "add", "a", 2, "b", 3)
- ));
- })
- .flatMap(result -> {
- // List and read resources
- return client.listResources()
- .flatMap(resources ->
- client.readResource(new ReadResourceRequest("resource://uri"))
- );
- })
- .flatMap(resource -> {
- // List and use prompts
- return client.listPrompts()
- .flatMap(prompts ->
- client.getPrompt(new GetPromptRequest(
- "greeting",
- Map.of("name", "Spring")
- ))
- );
- })
- .flatMap(prompt -> {
- // Add/remove roots
- return client.addRoot(new Root("file:///path", "description"))
- .then(client.removeRoot("file:///path"))
- .then(client.rootsListChangedNotification());
- })
- .doFinally(signalType -> {
- // Close client
- client.closeGracefully().subscribe();
- })
- .subscribe();
-```
-
-### Client Transport Options
-
-#### StdioClientTransport
-```java
-// Create transport for process-based communication
-ServerParameters params = ServerParameters.builder("npx")
- .args("-y", "@modelcontextprotocol/server-everything", "dir")
- .build();
-McpTransport transport = new StdioClientTransport(params);
-```
-
-#### SseClientTransport
-```java
-// Create transport for HTTP streaming
-WebClient.Builder webClientBuilder = WebClient.builder()
- .baseUrl("http://your-mcp-server");
-McpTransport transport = new SseClientTransport(webClientBuilder);
-```
-
-
-### Client Capabilities
-
-The client can be configured with various capabilities:
-
-```java
-var capabilities = ClientCapabilities.builder()
- .roots(true) // Enable filesystem roots support with list changes notifications
- .sampling() // Enable LLM sampling support
- .build();
-```
-
-#### Roots Support
-
-Roots define the boundaries of where servers can operate within the filesystem:
-
-```java
-// Add a root dynamically
-client.addRoot(new Root("file:///path", "description"));
-
-// Remove a root
-client.removeRoot("file:///path");
-
-// Notify server of roots changes
-client.rootsListChangedNotification();
-```
-
-The roots capability allows servers to:
-- Request the list of accessible filesystem roots
-- Receive notifications when the root list changes
-- Understand which directories and files they have access to
-
-#### Sampling Support
-
-Sampling enables servers to request LLM interactions ("completions" or "generations") through the client:
-
-```java
-// Configure sampling handler
-Function samplingHandler = request -> {
- // Sampling implementation that interfaces with LLM
- return new CreateMessageResult(response);
-};
-
-// Create client with sampling support
-var client = McpClient.using(transport)
- .capabilities(ClientCapabilities.builder()
- .sampling()
- .build())
- .samplingHandler(samplingHandler)
- .build();
-```
-
-This capability allows:
-- Servers to leverage AI capabilities without requiring API keys
-- Clients to maintain control over model access and permissions
-- Support for both text and image-based interactions
-- Optional inclusion of MCP server context in prompts
-
-## Server Usage Examples
-
-### MCP Server (Sync API)
-
-```java
-// Create a server with custom configuration
-McpSyncServer syncServer = McpServer.using(transport)
- .info("my-server", "1.0.0")
- .capabilities(ServerCapabilities.builder()...build())
- .tools(new CalculatorTool())
- .resources(resourceRegistration)
- .prompts(promptRegistration)
- .sync();
-
-// Add a tool handler at runtime
-syncServer.addTool(new CalculatorTool());
-
-// Remove a tool handler at runtime
-syncServer.removeTool("calculator");
-
-// Add a resource at runtime
-syncServer.addResource(resourceRegistration);
-
-// Remove a resource at runtime
-syncServer.removeResource(resourceUri);
-
-// Add a prompt at runtime
-syncServer.addPrompt(promptRegistration);
-
-// Remove a prompt at runtime
-syncServer.removePrompt(promptName);
-
-// Graceful shutdown
-syncServer.closeGracefully();
-```
-
-### MCP Server (Async API)
-
-```java
-// Create an async server with custom configuration
-McpAsyncServer asyncServer = McpServer.using(transport)
- .info("my-server", "1.0.0")
- .capabilities(ServerCapabilities.builder()...build())
- .tools(new CalculatorTool())
- .resources(resourceRegistration)
- .prompts(promptRegistration)
- .async();
-
-// Add a tool handler at runtime
-asyncServer.addTool(new CalculatorTool())
- .doOnSuccess(v -> logger.info("Tool added"))
- .subscribe();
-
-// Remove a tool handler at runtime
-asyncServer.removeTool("calculator")
- .doOnSuccess(v -> logger.info("Tool removed"))
- .subscribe();
-
-// Add a resource at runtime
-asyncServer.addResource(resourceRegistration)
- .doOnSuccess(v -> logger.info("Resource added"))
- .subscribe();
-
-// Remove a resource at runtime
-asyncServer.removeResource(resourceUri)
- .doOnSuccess(v -> logger.info("Resource removed"))
- .subscribe();
-
-// Add a prompt at runtime
-asyncServer.addPrompt(promptRegistration)
- .doOnSuccess(v -> logger.info("Prompt added"))
- .subscribe();
-
-// Remove a prompt at runtime
-asyncServer.removePrompt(promptName)
- .doOnSuccess(v -> logger.info("Prompt removed"))
- .subscribe();
-
-// Notify clients of changes
-asyncServer.notifyToolsListChanged().subscribe();
-asyncServer.notifyResourcesListChanged().subscribe();
-asyncServer.notifyPromptsListChanged().subscribe();
-
-// Graceful shutdown
-asyncServer.closeGracefully().subscribe();
-```
-
-### Server Transport Options
-
-#### StdioServerTransport
-```java
-// Create transport with custom ObjectMapper
-ObjectMapper mapper = new ObjectMapper();
-StdioServerTransport transport = new StdioServerTransport(mapper);
-```
-
-Provides bidirectional JSON-RPC message handling over standard input/output streams with non-blocking message processing, serialization/deserialization, and graceful shutdown support.
-
-#### SseServerTransport
-```java
-// Create SSE transport
-ObjectMapper mapper = new ObjectMapper();
-String messageEndpoint = "/mcp/message";
-SseServerTransport transport = new SseServerTransport(mapper, messageEndpoint);
-
-// Get router function for web server configuration
-RouterFunction> router = transport.getRouterFunction();
-```
-
-Implements the MCP HTTP with SSE transport specification, providing concurrent client connections through SSE endpoints with message routing, session management, and graceful shutdown capabilities.
-
-
-### Server Capabilities
-
-The server can be configured with various capabilities:
-
-```java
-var capabilities = ServerCapabilities.builder()
- .resources(false, true) // Resource support with list changes notifications
- .tools(true) // Tool support with list changes notifications
- .prompts(true) // Prompt support with list changes notifications
- .logging() // Enable logging support (enabled by default with loging level INFO)
- .build();
-```
-
-#### Logging Support
-
-The server provides structured logging capabilities that allow sending log messages to clients with different severity levels:
-
-```java
-// Send a log message to clients
-server.loggingNotification(LoggingMessageNotification.builder()
- .level(LoggingLevel.INFO)
- .logger("custom-logger")
- .data("Custom log message")
- .build());
-```
-
-Supported logging levels (in order of increasing severity):
-- DEBUG (0)
-- INFO (1)
-- NOTICE (2)
-- WARNING (3)
-- ERROR (4)
-- CRITICAL (5)
-- ALERT (6)
-- EMERGENCY (7)
-
-Clients can control the minimum logging level they receive through the `mcpClient.setLoggingLevel(level)` request. Messages below the set level will be filtered out.
-
-#### Tool Registration
-
-```java
-var toolRegistration = new ToolRegistration(
- new Tool("calculator", "Basic calculator", Map.of(
- "operation", "string",
- "a", "number",
- "b", "number"
- )),
- arguments -> {
- // Tool implementation
- return new CallToolResult(result, false);
- }
-);
-```
-
-#### Resource Registration
-
-```java
-var resourceRegistration = new ResourceRegistration(
- new Resource("custom://resource", "name", "description", "mime-type", null),
- request -> {
- // Resource read implementation
- return new ReadResourceResult(contents);
- }
-);
-```
-
-#### Prompt Registration
-
-```java
-var promptRegistration = new PromptRegistration(
- new Prompt("greeting", "description", List.of(
- new PromptArgument("name", "description", true)
- )),
- request -> {
- // Prompt implementation
- return new GetPromptResult(description, messages);
- }
-);
-```
-
-## Error Handling
-
-The SDK provides comprehensive error handling through the McpError class, covering protocol compatibility, transport communication, JSON-RPC messaging, tool execution, resource management, prompt handling, timeouts, and connection issues. This unified error handling approach ensures consistent and reliable error management across both synchronous and asynchronous operations.
-
-## Contributing
-
-See [CONTRIBUTING.md](../CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
+Find more at [Java MCP SDK](https://docs.spring.io/spring-ai-mcp/reference/mcp.html)
\ No newline at end of file
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/client/McpAsyncClient.java b/mcp/src/main/java/org/springframework/ai/mcp/client/McpAsyncClient.java
index c4473a4..e1bc8f1 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/client/McpAsyncClient.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/client/McpAsyncClient.java
@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.DefaultMcpSession;
import org.springframework.ai.mcp.spec.DefaultMcpSession.NotificationHandler;
import org.springframework.ai.mcp.spec.DefaultMcpSession.RequestHandler;
@@ -129,7 +130,7 @@ public class McpAsyncClient {
* @param loggingConsumers the logging consumers.
* @param samplingHandler the sampling handler.
*/
- public McpAsyncClient(McpTransport transport, Duration requestTimeout, Implementation clientInfo,
+ public McpAsyncClient(ClientMcpTransport transport, Duration requestTimeout, Implementation clientInfo,
ClientCapabilities clientCapabilities, Map roots,
List>> toolsChangeConsumers,
List>> resourcesChangeConsumers,
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/client/McpClient.java b/mcp/src/main/java/org/springframework/ai/mcp/client/McpClient.java
index dcd8bd0..cac0001 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/client/McpClient.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/client/McpClient.java
@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.spec.McpSchema.ClientCapabilities;
import org.springframework.ai.mcp.spec.McpSchema.CreateMessageRequest;
@@ -115,7 +116,7 @@ public interface McpClient {
* @return A new builder instance for configuring the client
* @throws IllegalArgumentException if transport is null
*/
- public static Builder using(McpTransport transport) {
+ public static Builder using(ClientMcpTransport transport) {
return new Builder(transport);
}
@@ -138,7 +139,7 @@ public interface McpClient {
*/
public static class Builder {
- private final McpTransport transport;
+ private final ClientMcpTransport transport;
private Duration requestTimeout = Duration.ofSeconds(20); // Default timeout
@@ -158,7 +159,7 @@ public interface McpClient {
private Function samplingHandler;
- private Builder(McpTransport transport) {
+ private Builder(ClientMcpTransport transport) {
Assert.notNull(transport, "Transport must not be null");
this.transport = transport;
}
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/client/transport/SseClientTransport.java b/mcp/src/main/java/org/springframework/ai/mcp/client/transport/SseClientTransport.java
index a77528b..906735f 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/client/transport/SseClientTransport.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/client/transport/SseClientTransport.java
@@ -32,10 +32,10 @@ import reactor.core.scheduler.Schedulers;
import reactor.util.retry.Retry;
import reactor.util.retry.Retry.RetrySignal;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.McpError;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.spec.McpSchema.JSONRPCMessage;
-import org.springframework.ai.mcp.spec.McpTransport;
import org.springframework.ai.mcp.util.Assert;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.MediaType;
@@ -71,7 +71,7 @@ import org.springframework.web.reactive.function.client.WebClient;
* "https://spec.modelcontextprotocol.io/specification/basic/transports/#http-with-sse">MCP
* HTTP with SSE Transport Specification
*/
-public class SseClientTransport implements McpTransport {
+public class SseClientTransport implements ClientMcpTransport {
private final static Logger logger = LoggerFactory.getLogger(SseClientTransport.class);
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/client/transport/StdioClientTransport.java b/mcp/src/main/java/org/springframework/ai/mcp/client/transport/StdioClientTransport.java
index 01f59d1..e9aac82 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/client/transport/StdioClientTransport.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/client/transport/StdioClientTransport.java
@@ -38,10 +38,10 @@ import reactor.core.publisher.Sinks;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.spec.McpSchema.JSONRPCMessage;
import org.springframework.ai.mcp.util.Assert;
-import org.springframework.ai.mcp.spec.McpTransport;
/**
* Implementation of the MCP Stdio transport that communicates with a server process using
@@ -51,7 +51,7 @@ import org.springframework.ai.mcp.spec.McpTransport;
* @author Christian Tzolov
* @author Dariusz Jędrzejczyk
*/
-public class StdioClientTransport implements McpTransport {
+public class StdioClientTransport implements ClientMcpTransport {
private static final Logger logger = LoggerFactory.getLogger(StdioClientTransport.class);
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/server/McpAsyncServer.java b/mcp/src/main/java/org/springframework/ai/mcp/server/McpAsyncServer.java
index a79c43c..ca8cb83 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/server/McpAsyncServer.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/server/McpAsyncServer.java
@@ -44,7 +44,7 @@ import org.springframework.ai.mcp.spec.McpSchema.ListRootsResult;
import org.springframework.ai.mcp.spec.McpSchema.LoggingLevel;
import org.springframework.ai.mcp.spec.McpSchema.LoggingMessageNotification;
import org.springframework.ai.mcp.spec.McpSchema.Tool;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import org.springframework.ai.mcp.util.Utils;
/**
@@ -63,7 +63,7 @@ public class McpAsyncServer {
*/
private final DefaultMcpSession mcpSession;
- private final McpTransport transport;
+ private final ServerMcpTransport transport;
private final McpSchema.ServerCapabilities serverCapabilities;
@@ -98,7 +98,7 @@ public class McpAsyncServer {
* @param rootsChangeConsumers The list of consumers that will be notified when the
* roots list changes
*/
- public McpAsyncServer(McpTransport mcpTransport, McpSchema.Implementation serverInfo,
+ public McpAsyncServer(ServerMcpTransport mcpTransport, McpSchema.Implementation serverInfo,
McpSchema.ServerCapabilities serverCapabilities, List tools,
Map resources, List resourceTemplates,
Map prompts, List>> rootsChangeConsumers) {
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/server/McpServer.java b/mcp/src/main/java/org/springframework/ai/mcp/server/McpServer.java
index 63588f4..6ee01a3 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/server/McpServer.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/server/McpServer.java
@@ -28,6 +28,7 @@ import org.springframework.ai.mcp.spec.McpSchema.CallToolResult;
import org.springframework.ai.mcp.spec.McpSchema.ResourceTemplate;
import org.springframework.ai.mcp.spec.McpSchema.Tool;
import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import org.springframework.ai.mcp.util.Assert;
/**
@@ -198,7 +199,7 @@ public interface McpServer {
* @param transport The transport layer implementation for MCP communication
* @return A new builder instance
*/
- public static Builder using(McpTransport transport) {
+ public static Builder using(ServerMcpTransport transport) {
return new Builder(transport);
}
@@ -210,7 +211,7 @@ public interface McpServer {
private final static McpSchema.Implementation DEFAULT_SERVER_INFO = new McpSchema.Implementation("mcp-server",
"1.0.0");
- private final McpTransport transport;
+ private final ServerMcpTransport transport;
private McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
@@ -247,7 +248,7 @@ public interface McpServer {
private List>> rootsChangeConsumers = new ArrayList<>();
- private Builder(McpTransport transport) {
+ private Builder(ServerMcpTransport transport) {
Assert.notNull(transport, "Transport must not be null");
this.transport = transport;
}
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/server/transport/SseServerTransport.java b/mcp/src/main/java/org/springframework/ai/mcp/server/transport/SseServerTransport.java
index 88bda2e..6b27476 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/server/transport/SseServerTransport.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/server/transport/SseServerTransport.java
@@ -17,7 +17,7 @@ import reactor.core.publisher.Sinks;
import org.springframework.ai.mcp.spec.McpError;
import org.springframework.ai.mcp.spec.McpSchema;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import org.springframework.ai.mcp.util.Assert;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -33,7 +33,7 @@ import org.springframework.web.reactive.function.server.ServerResponse;
*
* @author Christian Tzolov
*/
-public class SseServerTransport implements McpTransport {
+public class SseServerTransport implements ServerMcpTransport {
private final static Logger logger = LoggerFactory.getLogger(SseServerTransport.class);
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/server/transport/StdioServerTransport.java b/mcp/src/main/java/org/springframework/ai/mcp/server/transport/StdioServerTransport.java
index c568233..5f8e78b 100644
--- a/mcp/src/main/java/org/springframework/ai/mcp/server/transport/StdioServerTransport.java
+++ b/mcp/src/main/java/org/springframework/ai/mcp/server/transport/StdioServerTransport.java
@@ -38,7 +38,7 @@ import reactor.core.scheduler.Schedulers;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.spec.McpSchema.JSONRPCMessage;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import org.springframework.ai.mcp.util.Assert;
/**
@@ -48,7 +48,7 @@ import org.springframework.ai.mcp.util.Assert;
*
* @author Christian Tzolov
*/
-public class StdioServerTransport implements McpTransport {
+public class StdioServerTransport implements ServerMcpTransport {
private static final Logger logger = LoggerFactory.getLogger(StdioServerTransport.class);
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/spec/ClientMcpTransport.java b/mcp/src/main/java/org/springframework/ai/mcp/spec/ClientMcpTransport.java
new file mode 100644
index 0000000..4b5af3b
--- /dev/null
+++ b/mcp/src/main/java/org/springframework/ai/mcp/spec/ClientMcpTransport.java
@@ -0,0 +1,25 @@
+/*
+* Copyright 2024 - 2024 the original author or authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.springframework.ai.mcp.spec;
+
+/**
+ * Marker interface for the client-side MCP transport.
+ *
+ * @author Christian Tzolov
+ */
+public interface ClientMcpTransport extends McpTransport {
+
+}
diff --git a/mcp/src/main/java/org/springframework/ai/mcp/spec/ServerMcpTransport.java b/mcp/src/main/java/org/springframework/ai/mcp/spec/ServerMcpTransport.java
new file mode 100644
index 0000000..bb3d829
--- /dev/null
+++ b/mcp/src/main/java/org/springframework/ai/mcp/spec/ServerMcpTransport.java
@@ -0,0 +1,25 @@
+/*
+* Copyright 2024 - 2024 the original author or authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.springframework.ai.mcp.spec;
+
+/**
+ * Marker interface for the server-side MCP transport.
+ *
+ * @author Christian Tzolov
+ */
+public interface ServerMcpTransport extends McpTransport {
+
+}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/MockMcpTransport.java b/mcp/src/test/java/org/springframework/ai/mcp/MockMcpTransport.java
index a41013b..034a08f 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/MockMcpTransport.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/MockMcpTransport.java
@@ -26,14 +26,13 @@ import reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks;
import reactor.core.scheduler.Schedulers;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.McpSchema;
-import org.springframework.ai.mcp.spec.McpTransport;
-import org.springframework.ai.mcp.spec.McpSchema.JSONRPCMessage;
import org.springframework.ai.mcp.spec.McpSchema.JSONRPCNotification;
import org.springframework.ai.mcp.spec.McpSchema.JSONRPCRequest;
@SuppressWarnings("unused")
-public class MockMcpTransport implements McpTransport {
+public class MockMcpTransport implements ClientMcpTransport {
private final AtomicInteger inboundMessageCount = new AtomicInteger(0);
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpAsyncClientTests.java b/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpAsyncClientTests.java
index acde147..b5a00bf 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpAsyncClientTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpAsyncClientTests.java
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import reactor.test.StepVerifier;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.spec.McpSchema.CallToolRequest;
import org.springframework.ai.mcp.spec.McpSchema.ClientCapabilities;
@@ -56,13 +57,13 @@ public abstract class AbstractMcpAsyncClientTests {
private McpAsyncClient mcpAsyncClient;
- protected McpTransport mcpTransport;
+ protected ClientMcpTransport mcpTransport;
private static final Duration TIMEOUT = Duration.ofSeconds(20);
private static final String ECHO_TEST_MESSAGE = "Hello MCP Spring AI!";
- abstract protected McpTransport createMcpTransport();
+ abstract protected ClientMcpTransport createMcpTransport();
protected void onStart() {
}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpSyncClientTests.java b/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpSyncClientTests.java
index 7a1939b..9935f7f 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpSyncClientTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/client/AbstractMcpSyncClientTests.java
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.spec.McpSchema.CallToolRequest;
import org.springframework.ai.mcp.spec.McpSchema.CallToolResult;
@@ -38,7 +39,6 @@ import org.springframework.ai.mcp.spec.McpSchema.SubscribeRequest;
import org.springframework.ai.mcp.spec.McpSchema.TextContent;
import org.springframework.ai.mcp.spec.McpSchema.Tool;
import org.springframework.ai.mcp.spec.McpSchema.UnsubscribeRequest;
-import org.springframework.ai.mcp.spec.McpTransport;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
@@ -58,9 +58,9 @@ public abstract class AbstractMcpSyncClientTests {
private static final String TEST_MESSAGE = "Hello MCP Spring AI!";
- protected McpTransport mcpTransport;
+ protected ClientMcpTransport mcpTransport;
- abstract protected McpTransport createMcpTransport();
+ abstract protected ClientMcpTransport createMcpTransport();
abstract protected void onStart();
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/client/McpAsyncClientTests.java b/mcp/src/test/java/org/springframework/ai/mcp/client/McpAsyncClientTests.java
index 9c5db68..ca37d72 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/client/McpAsyncClientTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/client/McpAsyncClientTests.java
@@ -20,7 +20,7 @@ import org.junit.jupiter.api.Timeout;
import org.springframework.ai.mcp.client.transport.ServerParameters;
import org.springframework.ai.mcp.client.transport.StdioClientTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
/**
* Tests for the {@link McpAsyncClient} with {@link StdioClientTransport}.
@@ -32,7 +32,7 @@ import org.springframework.ai.mcp.spec.McpTransport;
class McpAsyncClientTests extends AbstractMcpAsyncClientTests {
@Override
- protected McpTransport createMcpTransport() {
+ protected ClientMcpTransport createMcpTransport() {
ServerParameters stdioParams = ServerParameters.builder("npx")
.args("-y", "@modelcontextprotocol/server-everything", "dir")
.build();
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/client/McpSyncClientTests.java b/mcp/src/test/java/org/springframework/ai/mcp/client/McpSyncClientTests.java
index d23c39c..3b881d0 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/client/McpSyncClientTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/client/McpSyncClientTests.java
@@ -23,7 +23,7 @@ import org.junit.jupiter.api.Timeout;
import org.springframework.ai.mcp.client.transport.ServerParameters;
import org.springframework.ai.mcp.client.transport.StdioClientTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import static org.assertj.core.api.Assertions.assertThat;
@@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class McpSyncClientTests extends AbstractMcpSyncClientTests {
@Override
- protected McpTransport createMcpTransport() {
+ protected ClientMcpTransport createMcpTransport() {
ServerParameters stdioParams = ServerParameters.builder("npx")
.args("-y", "@modelcontextprotocol/server-everything", "dir")
.build();
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpAsyncClientTests.java b/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpAsyncClientTests.java
index 84657a6..bce1332 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpAsyncClientTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpAsyncClientTests.java
@@ -21,7 +21,7 @@ import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.springframework.ai.mcp.client.transport.SseClientTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.web.reactive.function.client.WebClient;
/**
@@ -42,7 +42,7 @@ class SseMcpAsyncClientTests extends AbstractMcpAsyncClientTests {
.waitingFor(Wait.forHttp("/").forStatusCode(404));
@Override
- protected McpTransport createMcpTransport() {
+ protected ClientMcpTransport createMcpTransport() {
return new SseClientTransport(WebClient.builder().baseUrl(host));
}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpSyncClientTests.java b/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpSyncClientTests.java
index 55632c3..a0bfacf 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpSyncClientTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/client/SseMcpSyncClientTests.java
@@ -21,7 +21,7 @@ import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.springframework.ai.mcp.client.transport.SseClientTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.web.reactive.function.client.WebClient;
/**
@@ -42,7 +42,7 @@ class SseMcpSyncClientTests extends AbstractMcpSyncClientTests {
.waitingFor(Wait.forHttp("/").forStatusCode(404));
@Override
- protected McpTransport createMcpTransport() {
+ protected ClientMcpTransport createMcpTransport() {
return new SseClientTransport(WebClient.builder().baseUrl(host));
}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpAsyncServerTests.java b/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpAsyncServerTests.java
index 16a8a73..3ecd854 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpAsyncServerTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpAsyncServerTests.java
@@ -39,6 +39,7 @@ import org.springframework.ai.mcp.spec.McpSchema.Resource;
import org.springframework.ai.mcp.spec.McpSchema.ServerCapabilities;
import org.springframework.ai.mcp.spec.McpSchema.Tool;
import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
@@ -58,7 +59,7 @@ public abstract class AbstractMcpAsyncServerTests {
private static final String TEST_PROMPT_NAME = "test-prompt";
- abstract protected McpTransport createMcpTransport();
+ abstract protected ServerMcpTransport createMcpTransport();
protected void onStart() {
}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpSyncServerTests.java b/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpSyncServerTests.java
index def8527..e9aa970 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpSyncServerTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/server/AbstractMcpSyncServerTests.java
@@ -23,11 +23,11 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.server.McpServer.PromptRegistration;
import org.springframework.ai.mcp.server.McpServer.ResourceRegistration;
import org.springframework.ai.mcp.server.McpServer.ToolRegistration;
import org.springframework.ai.mcp.spec.McpError;
+import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.mcp.spec.McpSchema.CallToolResult;
import org.springframework.ai.mcp.spec.McpSchema.GetPromptResult;
import org.springframework.ai.mcp.spec.McpSchema.Prompt;
@@ -37,6 +37,7 @@ import org.springframework.ai.mcp.spec.McpSchema.Resource;
import org.springframework.ai.mcp.spec.McpSchema.ServerCapabilities;
import org.springframework.ai.mcp.spec.McpSchema.Tool;
import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
@@ -56,7 +57,7 @@ public abstract class AbstractMcpSyncServerTests {
private static final String TEST_PROMPT_NAME = "test-prompt";
- abstract protected McpTransport createMcpTransport();
+ abstract protected ServerMcpTransport createMcpTransport();
protected void onStart() {
}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpAsyncServerTests.java b/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpAsyncServerTests.java
index 45259a8..8beda36 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpAsyncServerTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpAsyncServerTests.java
@@ -22,7 +22,7 @@ import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;
import org.springframework.ai.mcp.server.transport.SseServerTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunctions;
@@ -42,7 +42,7 @@ class SseMcpAsyncServerTests extends AbstractMcpAsyncServerTests {
private DisposableServer httpServer;
@Override
- protected McpTransport createMcpTransport() {
+ protected ServerMcpTransport createMcpTransport() {
var transport = new SseServerTransport(new ObjectMapper(), MESSAGE_ENDPOINT);
HttpHandler httpHandler = RouterFunctions.toHttpHandler(transport.getRouterFunction());
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpSyncServerTests.java b/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpSyncServerTests.java
index 2426849..af62763 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpSyncServerTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/server/SseMcpSyncServerTests.java
@@ -22,7 +22,7 @@ import reactor.netty.DisposableServer;
import reactor.netty.http.server.HttpServer;
import org.springframework.ai.mcp.server.transport.SseServerTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunctions;
@@ -44,7 +44,7 @@ class SseMcpSyncServerTests extends AbstractMcpSyncServerTests {
private SseServerTransport transport;
@Override
- protected McpTransport createMcpTransport() {
+ protected ServerMcpTransport createMcpTransport() {
transport = new SseServerTransport(new ObjectMapper(), MESSAGE_ENDPOINT);
return transport;
}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpAsyncServerTests.java b/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpAsyncServerTests.java
index 8d8a31d..9f15658 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpAsyncServerTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpAsyncServerTests.java
@@ -19,7 +19,7 @@ package org.springframework.ai.mcp.server;
import org.junit.jupiter.api.Timeout;
import org.springframework.ai.mcp.server.transport.StdioServerTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
/**
* Tests for {@link McpAsyncServer} using {@link StdioServerTransport}.
@@ -30,7 +30,7 @@ import org.springframework.ai.mcp.spec.McpTransport;
class StdioMcpAsyncServerTests extends AbstractMcpAsyncServerTests {
@Override
- protected McpTransport createMcpTransport() {
+ protected ServerMcpTransport createMcpTransport() {
return new StdioServerTransport();
}
diff --git a/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpSyncServerTests.java b/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpSyncServerTests.java
index 2e02f0d..6bcc4be 100644
--- a/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpSyncServerTests.java
+++ b/mcp/src/test/java/org/springframework/ai/mcp/server/StdioMcpSyncServerTests.java
@@ -19,7 +19,7 @@ package org.springframework.ai.mcp.server;
import org.junit.jupiter.api.Timeout;
import org.springframework.ai.mcp.server.transport.StdioServerTransport;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
/**
* Tests for {@link McpSyncServer} using {@link StdioServerTransport}.
@@ -30,7 +30,7 @@ import org.springframework.ai.mcp.spec.McpTransport;
class StdioMcpSyncServerTests extends AbstractMcpSyncServerTests {
@Override
- protected McpTransport createMcpTransport() {
+ protected ServerMcpTransport createMcpTransport() {
return new StdioServerTransport();
}
diff --git a/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java b/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java
index 69904b6..c1af31d 100644
--- a/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java
+++ b/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java
@@ -18,6 +18,7 @@ package org.springframework.ai.mcp.sample.client;
import java.util.Map;
import org.springframework.ai.mcp.client.McpClient;
+import org.springframework.ai.mcp.spec.ClientMcpTransport;
import org.springframework.ai.mcp.spec.McpSchema.CallToolRequest;
import org.springframework.ai.mcp.spec.McpSchema.CallToolResult;
import org.springframework.ai.mcp.spec.McpSchema.GetPromptRequest;
@@ -32,9 +33,9 @@ import org.springframework.ai.mcp.spec.McpTransport;
public class SampleClient {
- private final McpTransport transport;
+ private final ClientMcpTransport transport;
- public SampleClient(McpTransport transport) {
+ public SampleClient(ClientMcpTransport transport) {
this.transport = transport;
}
diff --git a/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java b/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java
index d0b9e44..eee55a0 100644
--- a/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java
+++ b/spring-ai-mcp-sample/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java
@@ -21,7 +21,7 @@ import org.springframework.ai.mcp.spec.McpSchema.LoggingMessageNotification;
import org.springframework.ai.mcp.spec.McpSchema.PromptMessage;
import org.springframework.ai.mcp.spec.McpSchema.Role;
import org.springframework.ai.mcp.spec.McpSchema.TextContent;
-import org.springframework.ai.mcp.spec.McpTransport;
+import org.springframework.ai.mcp.spec.ServerMcpTransport;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -55,7 +55,7 @@ public class McpServerConfig {
}
@Bean
- public McpAsyncServer mcpServer(McpTransport transport) { // @formatter:off
+ public McpAsyncServer mcpServer(ServerMcpTransport transport) { // @formatter:off
// Configure server capabilities with resource support
var capabilities = McpSchema.ServerCapabilities.builder()
diff --git a/spring-ai-mcp/README.md b/spring-ai-mcp/README.md
index 07229bd..8ba646f 100644
--- a/spring-ai-mcp/README.md
+++ b/spring-ai-mcp/README.md
@@ -2,48 +2,4 @@
Spring Integration module for Model Control Protocol (MCP) that provides Spring-specific functionality for working with MCP clients.
-## Overview
-
-The `spring-ai-mcp` module is part of the [Spring AI MCP](https://github.com/spring-projects-experimental/spring-ai-mcp) project. It provides Spring Framework integration for the Model Control Protocol (MCP), enabling seamless integration of MCP functionality within Spring applications.
-
-## Features
-
-- Spring integration for MCP clients
-- Function callback implementation for tool invocations
-- Seamless integration with Spring AI's function calling capabilities
-
-## Main Components
-
-### McpFunctionCallback
-
-The `McpFunctionCallback` class is the primary component of this module. It implements Spring AI's `FunctionCallback` interface and provides:
-
-- Integration between Spring AI's function calling system and MCP tools
-- Automatic conversion between JSON and Java objects for tool arguments
-- Synchronous tool execution support
-
-
-## Usage
-
-To use this module, add the following dependency to your Maven project:
-
-```xml
-
- org.springframework.experimental
- spring-ai-mcp
- 0.4.0-SNAPSHOT
-
-```
-
-## License
-
-This project is licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
-
-## Links
-
-- [GitHub Repository](https://github.com/spring-projects-experimental/spring-ai-mcp)
-- [Issue Tracker](https://github.com/spring-projects-experimental/spring-ai-mcp/issues)
-
-## Contributing
-
-This is an experimental Spring project. Contributions are welcome! Please refer to the main project's contribution guidelines.
+Find more at [Java MCP SDK](https://docs.spring.io/spring-ai-mcp/reference/spring-mcp.html)
\ No newline at end of file