feat: Add MCP server with Server stdio/sse transport improve MCP client

- Implement MCP server with async/sync support and builder pattern configuration
 - Add Server stdio/SSE transport layers with robust error handling
 - Convert McpClient and McpServer to interfaces for better extensibility
 - Add sampling capabilities for LLM interactions (text/image)
 - Implement dynamic root management and runtime tool management
 - Add comprehensive prompt and resource capabilities
 - Add support for dynamic root management (add/remove roots at runtime)

 Architecture Changes

 - Introduce registration records for tools, resources, and prompts
 - Improve thread safety with concurrent collections
 - Enhance resource template handling
 - Implement builder patterns for Server/Client capabilities
 - Add support for server capabilities and implementation info

Transport Layer:
 - Implement SseServerTransport with SSE endpoints
 - Add StdioServerTransport for process-based communication
 - Reorganize transport packages for better organization
 - Improve transport error handling and shutdown processes

Documentation:

 - Add detailed MCP reference documentation
 - Include architecture diagrams and API documentation
 - Add comprehensive test coverage for all components
 - Include sample projects demonstrating stdio/SSE transports

BREAKING CHANGES:

 Transport Package Reorganization

 - Move StdioClientTransport to o.s.ai.mcp.client.transport
 - Move SseClientTransport to o.s.ai.mcp.client.transport
 - Move ServerParameters to o.s.ai.mcp.client.transport
 - StdioClientTransport.errorHandler changed to private with
   setter method Migration: Use setErrorHandler() method
   instead of direct field access

 API Changes

 - Replace static factory methods with builder pattern
 - Update ServerCapabilities to use builder pattern
 - Make StdioClientTransport.errorHandler private with setter
 - Replace rootsListProvider with direct root management
 - Remove deprecated static factory methods

Resolves #27,#25,#24,#11
Related to #12
This commit is contained in:
Christian Tzolov 2024-12-19 19:38:38 +01:00
commit abd0facf4e

View file

@ -0,0 +1,138 @@
/*
* 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.server;
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.util.Assert;
/**
* Synchronous wrapper around {@link McpAsyncServer} that provides blocking operations.
* This class delegates all operations to an underlying async server instance while
* providing a synchronous API.
*
* @author Christian Tzolov
*/
public class McpSyncServer {
/**
* The async server to wrap.
*/
private final McpAsyncServer asyncServer;
/**
* Creates a new synchronous server that wraps the provided async server.
* @param asyncServer The async server to wrap
*/
public McpSyncServer(McpAsyncServer asyncServer) {
Assert.notNull(asyncServer, "Async server must not be null");
this.asyncServer = asyncServer;
}
/**
* Add a new tool handler.
* @param toolHandler The tool handler to add
*/
public void addTool(ToolRegistration toolHandler) {
this.asyncServer.addTool(toolHandler).block();
}
/**
* Remove a tool handler.
* @param toolName The name of the tool handler to remove
*/
public void removeTool(String toolName) {
this.asyncServer.removeTool(toolName).block();
}
/**
* Notify clients that the list of available tools has changed.
*/
public void notifyToolsListChanged() {
this.asyncServer.notifyToolsListChanged().block();
}
/**
* Notify clients that the list of available resources has changed.
*/
public void notifyResourcesListChanged() {
this.asyncServer.notifyResourcesListChanged().block();
}
/**
* Notify clients that the list of available prompts has changed.
*/
public void notifyPromptsListChanged() {
this.asyncServer.notifyPromptsListChanged().block();
}
/**
* Add a new resource handler.
* @param resourceHandler The resource handler to add
*/
public void addResource(ResourceRegistration resourceHandler) {
this.asyncServer.addResource(resourceHandler).block();
}
/**
* Remove a resource handler.
* @param resourceUri The URI of the resource handler to remove
*/
public void removeResource(String resourceUri) {
this.asyncServer.removeResource(resourceUri).block();
}
/**
* Add a new prompt handler.
* @param promptRegistration The prompt registration to add
*/
public void addPrompt(PromptRegistration promptRegistration) {
this.asyncServer.addPrompt(promptRegistration).block();
}
/**
* Remove a prompt handler.
* @param promptName The name of the prompt handler to remove
*/
public void removePrompt(String promptName) {
this.asyncServer.removePrompt(promptName).block();
}
/**
* Close the server gracefully.
*/
public void closeGracefully() {
this.asyncServer.closeGracefully().block();
}
/**
* Close the server immediately.
*/
public void close() {
this.asyncServer.close();
}
/**
* Get the underlying async server instance.
* @return The wrapped async server
*/
public McpAsyncServer getAsyncServer() {
return this.asyncServer;
}
}