diff --git a/mcp/README.md b/mcp/README.md new file mode 100644 index 0000000..2e5669f --- /dev/null +++ b/mcp/README.md @@ -0,0 +1,154 @@ +# Model Context Protocol (MCP) Java SDK + +A Java implementation of the [Model Context Protocol](https://modelcontextprotocol.io/docs/concepts/architecture) specification, providing both synchronous and asynchronous clients for MCP server interactions. + +## Overview + +This SDK implements the Model Context Protocol, enabling seamless integration with AI models and tools through a standardized interface. It supports both synchronous and asynchronous communication patterns, making it suitable for various use cases and integration scenarios. + +## Features + +- Synchronous and Asynchronous client implementations +- Standard MCP operations support: + - Tool discovery and execution + - Resource management + - Message creation + - Server initialization +- Stdio-based server transport +- Reactive programming support using Project Reactor + +## Installation + +Add the following dependency to your Maven project: + +```xml + + spring.ai.experimental + mcp + 1.0.0 + +``` + +## Usage + +### Async Client Example + +```java +// Create server parameters +ServerParameters params = ServerParameters.builder("npx") + .args("-y", "@modelcontextprotocol/server-everything", "dir") + .build(); + +// Initialize the async client +Duration timeout = Duration.ofSeconds(10); +McpAsyncClient client = McpClient.async( + new StdioServerTransport(params), + timeout, + new ObjectMapper() +); + +// Initialize the connection +client.initialize(); + +// List available tools +client.listTools(null).subscribe(result -> { + List tools = result.tools(); + // Process tools... +}); + +// Call a tool +CallToolRequest request = new CallToolRequest( + "echo", + Map.of("message", "Hello MCP!") +); +client.callTool(request).subscribe(result -> { + // Handle tool execution result... +}); + +// Cleanup +client.close(); +``` + +### Sync Client Example + +```java +// Create and initialize sync client +McpClient syncClient = McpClient.sync( + new StdioServerTransport(params), + timeout, + new ObjectMapper() +); + +// Initialize connection +syncClient.initialize(); + +// List tools synchronously +ListToolsResult tools = syncClient.listTools(null); + +// Call tool synchronously +CallToolResult result = syncClient.callTool("echo", Map.of("message", "Hello!")); + +// Cleanup +syncClient.close(); +``` + +## Architecture + +The SDK follows a layered architecture: + +### Core Components + +- **McpClient**: Main interface defining the synchronous operations +- **McpAsyncClient**: Async implementation using Project Reactor +- **McpSyncClient**: Synchronous wrapper around the async client +- **McpAsyncTransport**: Transport layer interface +- **DefaultMcpTransport**: Base transport implementation +- **StdioServerTransport**: Stdio-based server communication + +### Key Interactions + +1. Client initialization + - Transport setup + - Server connection establishment + - Protocol handshake + +2. Message Flow + - Request creation + - Transport layer handling + - Response processing + +3. Tool Execution + - Tool discovery + - Parameter validation + - Execution handling + - Result processing + +## Error Handling + +The SDK provides comprehensive error handling: + +- Transport-level errors +- Protocol violations +- Tool execution failures +- Timeout handling +- Resource management errors + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +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. diff --git a/spring/src/main/java/spring/ai/mcp/McpApplication.java b/spring/src/main/java/spring/ai/mcp/McpApplication.java index 6d96f76..2b40f13 100644 --- a/spring/src/main/java/spring/ai/mcp/McpApplication.java +++ b/spring/src/main/java/spring/ai/mcp/McpApplication.java @@ -28,7 +28,7 @@ public class McpApplication { return args -> { var chatClient = chatClientBuilder.defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0])) - .build(); + .build(); var response = chatClient.prompt("What is the content of the test.txt file?").call().content(); @@ -36,8 +36,8 @@ public class McpApplication { response = chatClient.prompt( "Please summarize the content of the test.txt file, covert the result in markdown format and store it into test.md") - .call() - .content(); + .call() + .content(); System.out.println("Summary:" + response); }; } @@ -46,22 +46,22 @@ public class McpApplication { public List functionCallbacks(McpSyncClient mcpClient) { return mcpClient.listTools(null) - .tools() - .stream() - .map(tool -> new McpFunctionCallback(mcpClient, tool)) - .toList(); + .tools() + .stream() + .map(tool -> new McpFunctionCallback(mcpClient, tool)) + .toList(); } @Bean(destroyMethod = "close") public McpSyncClient clientSession() { var stdioParams = ServerParameters.builder("npx") - .args("-y", "@modelcontextprotocol/server-filesystem", - "/Users/christiantzolov/Dev/projects/demo/mcp-server/dir") - .build(); + .args("-y", "@modelcontextprotocol/server-filesystem", + "/Users/christiantzolov/Dev/projects/demo/mcp-server/dir") + .build(); McpSyncClient mcpClient = null; - try { + try { mcpClient = McpClient.sync(new StdioServerTransport(stdioParams), Duration.ofSeconds(10), new ObjectMapper()); @@ -70,8 +70,7 @@ public class McpApplication { System.out.println("MCP Initialized: " + init); return mcpClient; - } - catch (Exception e) { + } catch (Exception e) { throw new RuntimeException(e); } }