Remove the spring-ai-mcp module from the MCP Java SDK

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
Christian Tzolov 2025-01-24 20:24:08 +01:00
commit 25ad5ed052
6 changed files with 0 additions and 351 deletions

View file

@ -54,12 +54,6 @@
<version>${project.version}</version>
</dependency>
<!-- Spring AI MCP -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-ai-mcp</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View file

@ -107,7 +107,6 @@
<module>mcp</module>
<module>mcp-transport/mcp-webflux-sse-transport</module>
<module>mcp-transport/mcp-webmvc-sse-transport</module>
<module>spring-ai-mcp</module>
<module>mcp-docs</module>
<module>mcp-test</module>
</modules>

View file

@ -1,5 +0,0 @@
# Spring AI MCP Spring
Spring Integration module for Model Control Protocol (MCP) that provides Spring-specific functionality for working with MCP clients.
Find more at [Java MCP SDK](https://docs.spring.io/spring-ai-mcp/reference/spring-mcp.html)

View file

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.experimental</groupId>
<artifactId>mcp-parent</artifactId>
<version>0.7.0-SNAPSHOT</version>
</parent>
<artifactId>spring-ai-mcp</artifactId>
<name>Spring AI MCP</name>
<description>Spring Framework integration for Model Context Protocol (MCP), providing Spring AI function calling capabilities and Spring-friendly abstractions for MCP clients and MCP servers</description>
<url>https://github.com/spring-projects-experimental/spring-ai-mcp</url>
<scm>
<url>https://github.com/spring-projects-experimental/spring-ai-mcp</url>
<connection>git://github.com/spring-projects-experimental/spring-ai-mcp.git</connection>
<developerConnection>git@github.com:spring-projects-experimental/spring-ai-mcp.git</developerConnection>
</scm>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-core</artifactId>
<version>${spring-ai.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>mcp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
</dependencies>
</project>

View file

@ -1,68 +0,0 @@
/*
* 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.spring;
import java.util.Map;
import org.springframework.ai.mcp.client.McpSyncClient;
import org.springframework.ai.mcp.spec.McpSchema.CallToolRequest;
import org.springframework.ai.mcp.spec.McpSchema.CallToolResult;
import org.springframework.ai.mcp.spec.McpSchema.Tool;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallback;
/**
* @author Christian Tzolov
*/
public class McpFunctionCallback implements FunctionCallback {
// TODO: revisit function calling as well to handle the async case
private final McpSyncClient mcpClient;
private final Tool tool;
public McpFunctionCallback(McpSyncClient clientSession, Tool tool) {
this.mcpClient = clientSession;
this.tool = tool;
}
@Override
public String getName() {
return this.tool.name();
}
@Override
public String getDescription() {
return this.tool.description();
}
@Override
public String getInputTypeSchema() {
return ModelOptionsUtils.toJsonString(this.tool.inputSchema());
}
@Override
public String call(String functionInput) {
Map<String, Object> arguments = ModelOptionsUtils.jsonToMap(functionInput);
CallToolResult response = this.mcpClient.callTool(new CallToolRequest(this.getName(), arguments));
// Todo handle errors
return ModelOptionsUtils.toJsonString(response.content());
}
}

View file

@ -1,218 +0,0 @@
/*
* 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.spring;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.mcp.server.McpServer;
import org.springframework.ai.mcp.server.McpServerFeatures;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.util.ClassUtils;
/**
* Utility class that provides helper methods for working with Model Context Protocol
* (MCP) tools in a Spring AI environment. This class facilitates the integration between
* Spring AI's function callbacks and MCP's tool system.
*
* <p>
* The MCP tool system enables servers to expose executable functionality to language
* models, allowing them to interact with external systems, perform computations, and take
* actions in the real world. Each tool is uniquely identified by a name and includes
* metadata describing its schema.
*
* <p>
* This helper class provides methods to:
* <ul>
* <li>Convert Spring AI's {@link FunctionCallback} instances to MCP tool
* registrations</li>
* <li>Generate JSON schemas for tool input validation</li>
* </ul>
*
* @author Christian Tzolov
* @see org.springframework.ai.model.function.FunctionCallback
* @see org.springframework.ai.mcp.server.McpServer.ToolRegistration
* @see org.springframework.ai.mcp.spec.McpSchema.Tool
*/
public final class ToolHelper {
private ToolHelper() {
}
public static List<McpServerFeatures.SyncToolRegistration> toSyncToolRegistration(
List<FunctionCallback> functionCallbacks) {
return functionCallbacks.stream().map(ToolHelper::toSyncToolRegistration).toList();
}
@Deprecated
public static List<McpServer.ToolRegistration> toToolRegistration(List<FunctionCallback> functionCallbacks) {
return functionCallbacks.stream().map(ToolHelper::toToolRegistration).toList();
}
public static List<McpServerFeatures.SyncToolRegistration> toSyncToolRegistration(
FunctionCallback... functionCallbacks) {
return toSyncToolRegistration(List.of(functionCallbacks));
}
@Deprecated
public static List<McpServer.ToolRegistration> toToolRegistration(FunctionCallback... functionCallbacks) {
return toToolRegistration(List.of(functionCallbacks));
}
/**
* Converts a Spring AI FunctionCallback to an MCP SyncToolRegistration. This enables
* Spring AI functions to be exposed as MCP tools that can be discovered and invoked
* by language models.
*
* <p>
* The conversion process:
* <ul>
* <li>Creates an MCP Tool with the function's name and input schema</li>
* <li>Wraps the function's execution in a SyncToolRegistration that handles the MCP
* protocol</li>
* <li>Provides error handling and result formatting according to MCP
* specifications</li>
* </ul>
*
* You can use the FunctionCallback builder to create a new instance of
* FunctionCallback using either java.util.function.Function or Method reference.
* @param functionCallback the Spring AI function callback to convert
* @return an MCP SyncToolRegistration that wraps the function callback
* @throws RuntimeException if there's an error during the function execution
*/
public static McpServerFeatures.SyncToolRegistration toSyncToolRegistration(FunctionCallback functionCallback) {
var tool = new McpSchema.Tool(functionCallback.getName(), functionCallback.getName(),
functionCallback.getInputTypeSchema());
return new McpServerFeatures.SyncToolRegistration(tool, request -> {
try {
String callResult = functionCallback.call(ModelOptionsUtils.toJsonString(request));
return new McpSchema.CallToolResult(List.of(new McpSchema.TextContent(callResult)), false);
}
catch (Exception e) {
return new McpSchema.CallToolResult(List.of(new McpSchema.TextContent(e.getMessage())), true);
}
});
}
/**
* Converts a Spring AI FunctionCallback to an MCP ToolRegistration. This enables
* Spring AI functions to be exposed as MCP tools that can be discovered and invoked
* by language models.
*
* <p>
* The conversion process:
* <ul>
* <li>Creates an MCP Tool with the function's name and input schema</li>
* <li>Wraps the function's execution in a ToolRegistration that handles the MCP
* protocol</li>
* <li>Provides error handling and result formatting according to MCP
* specifications</li>
* </ul>
*
* You can use the FunctionCallback builder to create a new instance of
* FunctionCallback using either java.util.function.Function or Method reference.
* @param functionCallback the Spring AI function callback to convert
* @return an MCP ToolRegistration that wraps the function callback
* @throws RuntimeException if there's an error during the function execution
* @deprecated Use {@link #toSyncToolRegistration(FunctionCallback)}.
*/
@Deprecated
public static McpServer.ToolRegistration toToolRegistration(FunctionCallback functionCallback) {
var tool = new McpSchema.Tool(functionCallback.getName(), functionCallback.getName(),
functionCallback.getInputTypeSchema());
return new McpServer.ToolRegistration(tool, request -> {
try {
String callResult = functionCallback.call(ModelOptionsUtils.toJsonString(request));
return new McpSchema.CallToolResult(List.of(new McpSchema.TextContent(callResult)), false);
}
catch (Exception e) {
return new McpSchema.CallToolResult(List.of(new McpSchema.TextContent(e.getMessage())), true);
}
});
}
/**
* Generates a JSON schema for a map of named classes using the default ObjectMapper.
* This schema can be used to validate tool inputs according to the MCP specification.
* @param namedClasses a map of class names to their corresponding Class objects
* @return a JSON schema string that describes the structure of the named classes
* @throws RuntimeException if schema generation fails
* @see #generateJsonSchema(Map, ObjectMapper)
*/
public static String generateJsonSchema(Map<String, Class<?>> namedClasses) {
return generateJsonSchema(namedClasses, new ObjectMapper());
}
/**
* Generates a JSON schema for a map of named classes using a custom ObjectMapper. The
* generated schema follows the JSON Schema Draft 2020-12 specification and describes
* the structure of the provided classes.
*
* <p>
* This method:
* <ul>
* <li>Creates a schema that validates the structure of tool inputs</li>
* <li>Excludes ToolContext class from schema generation</li>
* <li>Uses Jackson's JsonSchemaGenerator for accurate type representation</li>
* </ul>
* @param namedClasses a map of class names to their corresponding Class objects
* @param mapper the ObjectMapper to use for JSON processing
* @return a JSON schema string that describes the structure of the named classes
* @throws RuntimeException if schema generation fails
*/
public static String generateJsonSchema(Map<String, Class<?>> namedClasses, ObjectMapper mapper) {
try {
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
ObjectNode rootNode = mapper.createObjectNode();
rootNode.put("$schema", "https://json-schema.org/draft/2020-12/schema");
rootNode.put("type", "object");
ObjectNode propertiesNode = rootNode.putObject("properties");
for (Map.Entry<String, Class<?>> entry : namedClasses.entrySet()) {
String className = entry.getKey();
Class<?> clazz = entry.getValue();
if (ClassUtils.isAssignable(clazz, ToolContext.class)) {
// Skip the ToolContext class from the schema generation.
continue;
}
JsonSchema schema = schemaGen.generateSchema(clazz);
JsonNode schemaNode = mapper.valueToTree(schema);
propertiesNode.set(className, schemaNode);
}
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}