简述

Spring AI MCP(模型上下文协议)服务器启动启动器提供了在 Spring Boot 应用程序中设置 MCP 服务器的自动配置功能。它支持 MCP 服务器功能与 Spring Boot 的自动配置系统无缝集成。
MCP 服务器启动器提供:

  • MCP 服务器组件的自动配置
  • 支持同步和异步操作模式
  • 多种传输层选项
  • 灵活的工具、资源和提示规范
  • 更改通知功能

配置信息

maven 配置

MCP STDIO服务器传输。

1
2
3
4
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>

yaml 配置

1
2
3
4
5
6
7
8
# Using spring-ai-starter-mcp-server
spring:
ai:
mcp:
server:
name: stdio-mcp-server
version: 1.0.0
type: SYNC
  • 适用于命令行和桌面工具
  • 无需额外的 Web 依赖项

启动器激活McpServerAutoConfiguration自动配置,负责:

  • 配置基本服务器组件
  • 处理工具、资源和提示规范
  • 管理服务器功能和变更通知
  • 提供同步和异步服务器实现

完整的 MCP 服务器功能支持SSE基于 Spring MVC 的(服务器发送事件)服务器传输和可选STDIO传输。

1
2
3
4
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>

yaml 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Using spring-ai-starter-mcp-server-webmvc
spring:
ai:
mcp:
server:
name: webmvc-mcp-server
version: 1.0.0
type: SYNC
instructions: "This server provides weather information tools and resources"
sse-message-endpoint: /mcp/messages
capabilities:
tool: true
resource: true
prompt: true
completion: true

启动器激活McpWebMvcServerAutoConfiguration和McpServerAutoConfiguration自动配置以提供:

  • 使用 Spring MVC 的基于 HTTP 的传输(WebMvcSseServerTransportProvider)
  • 自动配置的 SSE 端点
  • 可选STDIO传输(通过设置启用spring.ai.mcp.server.stdio=true)
  • 包含spring-boot-starter-web和mcp-spring-webmvc依赖项

完整的 MCP 服务器功能支持SSE基于 Spring WebFlux 和可选传输的(服务器发送事件)服务器传输STDIO。

1
2
3
4
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>

yaml 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Using spring-ai-starter-mcp-server-webflux
spring:
ai:
mcp:
server:
name: webflux-mcp-server
version: 1.0.0
type: ASYNC # Recommended for reactive applications
instructions: "This reactive server provides weather information tools and resources"
sse-message-endpoint: /mcp/messages
capabilities:
tool: true
resource: true
prompt: true
completion: true

启动器激活McpWebFluxServerAutoConfiguration和McpServerAutoConfiguration自动配置以提供:

  • 使用 Spring WebFlux 进行反应式传输(WebFluxSseServerTransportProvider)
  • 自动配置的反应式 SSE 端点
  • 可选STDIO传输(通过设置启用spring.ai.mcp.server.stdio=true)
  • 包含spring-boot-starter-webflux和mcp-spring-webflux依赖项

参数配置

所有属性都以 为前缀spring.ai.mcp.server:

财产 描述 默认
enabled 启用/禁用 MCP 服务器 true
stdio 启用/禁用 stdio 传输 false
name 用于识别的服务器名称 mcp-server
version 服务器版本 1.0.0
instructions 可选指令,用于指导客户端如何与该服务器交互 null
type 服务器类型(同步/异步) SYNC
capabilities.resource 启用/禁用资源功能 true
capabilities.tool 启用/禁用工具功能 true
capabilities.prompt 启用/禁用提示功能 true
capabilities.completion 启用/禁用完成功能 true
resource-change-notification 启用资源更改通知 true
prompt-change-notification 启用提示更改通知 true
tool-change-notification 启用工具更改通知 true
tool-response-mime-type (可选)每个工具名称的响应 MIME 类型。例如,将MIME 类型与工具名称spring.ai.mcp.server.tool-response-mime-type.generateImage=image/png关联image/png``generateImage() -
sse-message-endpoint 客户端用来发送消息的 Web 传输的自定义 SSE 消息端点路径 /mcp/message
sse-endpoint 用于 Web 传输的自定义 SSE 端点路径 /sse
base-url 可选 URL 前缀。例如,表示客户端应访问位于+ 的base-url=/api/v1SSE 端点,而消息端点位于+/api/v1``sse-endpoint``/api/v1``sse-message-endpoint -
request-timeout 请求超时前等待服务器响应的时长。适用于所有通过客户端发出的请求,包括工具调用、资源访问和提示操作。 20

使用MCP 创建 服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Service
public class WeatherService {

@Tool(description = "Get weather information by city name")
public String getWeather(String cityName) {
// Implementation
}
}

@SpringBootApplication
public class McpServerApplication {

private static final Logger logger = LoggerFactory.getLogger(McpServerApplication.class);

public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}

@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService) {
return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
}
}

方法作为工具

  • 声明性地,使用 Comments@Tool
  • 以编程方式使用低级实现。MethodToolCallback

声明性规范:@Tool

您可以通过使用 注释方法将方法变成工具。@Tool

1
2
3
4
5
6
7
8
class DateTimeTools {

@Tool(description = "Get the current date and time in the user's timezone")
String getCurrentDateTime() {
return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
}

}

注释允许您提供有关该工具的关键信息:@Tool

  • name:工具的名称。如果未提供,则将使用方法名称。AI 模型在调用工具时使用此名称来标识工具。因此,不允许在同一类中有两个同名的工具。该名称在模型可用于特定聊天请求的所有工具中必须是唯一的。
  • description:工具的描述,模型可以使用它来了解何时以及如何调用该工具。如果未提供,方法名称将用作工具描述。但是,强烈建议提供详细的描述,因为这对于模型理解工具的用途以及如何使用它至关重要。未能提供良好的描述可能会导致模型在应该使用的工具时没有使用或错误地使用该工具。
  • returnDirect:是将工具结果直接返回给客户端还是传递回模型。有关更多详细信息,请参阅直接退货。
  • resultConverter:用于将工具调用的结果转换为 a 以发送回 AI 模型的实现。有关更多详细信息,请参阅结果转换。ToolCallResultConverterString object

该方法可以是静态的,也可以是实例的,并且可以具有任何可见性(public、protected、package-private 或 private)。包含该方法的类可以是顶级类,也可以是嵌套类,它也可以具有任何可见性(只要它可以在您计划实例化它的位置访问)。
Spring AI为-annotated方法的AOT编译提供了内置支持,只要包含这些方法的类是Spring bean(例如)。否则,您需要向 GraalVM 编译器提供必要的配置。例如,通过使用 .@Tool@Component@RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_METHODS)

如果该方法是静态的,则可以省略该方法,因为它不需要。toolObject()

1
2
3
4
5
6
7
class DateTimeTools {

static String getCurrentDateTime() {
return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
}

}
1
2
3
4
5
6
7
Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolCallback toolCallback = MethodToolCallback.builder()
.toolDefinition(ToolDefinitions.builder(method)
.description("Get the current date and time in the user's timezone")
.build())
.toolMethod(method)
.build();

Spring AI 将自动为方法的输入参数生成 JSON 模式。模型使用架构来了解如何调用工具并准备工具请求。注释可用于提供有关输入参数的其他信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。@ToolParam

1
2
3
4
5
6
7
8
class DateTimeTools {

void setAlarm(@ToolParam(description = "Time in ISO-8601 format") String time) {
LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
System.out.println("Alarm set for " + alarmTime);
}

}

注释允许您提供有关工具参数的关键信息:@ToolParam

  • description:参数的描述,模型可以使用它来更好地理解如何使用它。例如,参数应采用什么格式、允许使用哪些值等。
  • required:参数是必填还是可选。默认情况下,所有参数都被视为必需参数。

如果参数被注释为 ,则该参数将被视为可选,除非使用注释显式标记为必需。@Nullable@ToolParam
除了注释之外,您还可以使用 Swagger 或 Jackson 的注释。有关更多详细信息,请参阅 JSON 架构。@ToolParam@Schema@JsonProperty

将工具添加到ChatClient
使用声明式规范方法时,可以在调用 .此类工具仅适用于添加它们的特定聊天请求。tools()ChatClient

1
2
3
4
5
ChatClient.create(chatModel)
.prompt("What day is tomorrow?")
.tools(new DateTimeTools())
.call()
.content();

在后台,将从工具类实例中的每个 -annotated 方法生成一个方法,并将它们传递给模型。如果您更喜欢自己生成 (s),则可以使用实用程序类。ChatClientToolCallback@ToolToolCallbackToolCallbacks

1
ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());

将默认工具添加到ChatClient
使用声明式规范方法时,可以通过将工具类实例传递给方法来将默认工具添加到 。 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。ChatClient.BuilderdefaultTools()
默认工具在从同一 .它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。ChatClientChatClient.Builder

1
2
3
4
5
6
7
ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());
ChatModel chatModel = OllamaChatModel.builder()
.ollamaApi(OllamaApi.builder().build())
.defaultOptions(ToolCallingChatOptions.builder()
.toolCallbacks(dateTimeTools)
.build())
.build();

将工具添加到ChatModel
使用声明式规范方法时,可以将工具类实例传递给用于调用 .此类工具仅适用于添加它们的特定聊天请求。toolCallbacks()ToolCallingChatOptionsChatModel

1
2
3
4
5
6
7
ChatModel chatModel = ...
ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());
ChatOptions chatOptions = ToolCallingChatOptions.builder()
.toolCallbacks(dateTimeTools)
.build();
Prompt prompt = new Prompt("What day is tomorrow?", chatOptions);
chatModel.call(prompt);

程序化规范:MethodToolCallback

您可以通过以编程方式构建函数类型 (、 、 或 ) 转换为工具。FunctionSupplierConsumerBiFunctionFunctionToolCallback

1
2
3
4
5
6
7
8
9
public class WeatherService implements Function<WeatherRequest, WeatherResponse> {
public WeatherResponse apply(WeatherRequest request) {
return new WeatherResponse(30.0, Unit.C);
}
}

public enum Unit { C, F }
public record WeatherRequest(String location, Unit unit) {}
public record WeatherResponse(double temp, Unit unit) {}

允许您构建实例并提供有关该工具的关键信息:FunctionToolCallback.BuilderFunctionToolCallback

  • name:工具的名称。AI 模型在调用工具时使用此名称来标识工具。因此,不允许在同一上下文中使用两个具有相同名称的工具。该名称在模型可用于特定聊天请求的所有工具中必须是唯一的。必填。

  • toolFunction:表示工具方法(、、或)的功能对象。必填。FunctionSupplierConsumerBiFunction

  • description:工具的描述,模型可以使用它来了解何时以及如何调用该工具。如果未提供,方法名称将用作工具描述。但是,强烈建议提供详细的描述,因为这对于模型理解工具的用途以及如何使用它至关重要。未能提供良好的描述可能会导致模型在应该使用的工具时没有使用或错误地使用该工具。

  • inputType:函数输入的类型。必填。

  • inputSchema:工具输入参数的 JSON 架构。如果未提供,则将根据 自动生成架构。您可以使用注释提供有关输入参数的其他信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。有关更多详细信息,请参阅 JSON 架构。inputType@ToolParam

  • toolMetadata:定义其他设置的实例,例如是否应将结果直接返回给客户端,以及要使用的结果转换器。您可以使用类构建它。ToolMetadataToolMetadata.Builder

  • toolCallResultConverter:用于将工具调用结果转换为对象以发送回 AI 模型的实例。如果未提供,将使用默认转换器 ()。ToolCallResultConverterStringDefaultToolCallResultConverter

允许您构建实例并为该工具定义其他设置:ToolMetadata.BuilderToolMetadata

  • returnDirect:是将工具结果直接返回给客户端还是传递回模型。
1
2
3
4
5
ToolCallback toolCallback = FunctionToolCallback
.builder("currentWeather", new WeatherService())
.description("Get the weather in location")
.inputType(WeatherRequest.class)
.build();

函数输入和输出可以是 POJO。输入和输出 POJO 必须是可序列化的,因为结果将被序列化并发送回模型。函数以及输入和输出类型必须是公共的。Void

将工具添加到ChatClient
使用编程规范方法时,可以将实例传递给 的方法。该工具仅适用于添加它的特定聊天请求。FunctionToolCallbacktoolCallbacks()ChatClient

1
2
3
4
5
6
ToolCallback toolCallback = ...
ChatClient.create(chatModel)
.prompt("What's the weather like in Copenhagen?")
.toolCallbacks(toolCallback)
.call()
.content();

将默认工具添加到ChatClient
使用编程规范方法时,可以通过将实例传递给方法来将默认工具添加到 。 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。ChatClient.BuilderFunctionToolCallbackdefaultToolCallbacks()

1
2
3
4
5
ChatModel chatModel = ...
ToolCallback toolCallback = ...
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultToolCallbacks(toolCallback)
.build();

将工具添加到ChatModel
使用编程规范方法时,可以将实例传递给 的方法。该工具仅适用于添加它的特定聊天请求。FunctionToolCallbacktoolCallbacks()ToolCallingChatOptions

1
2
3
4
5
6
7
ChatModel chatModel = ...
ToolCallback toolCallback = ...
ChatOptions chatOptions = ToolCallingChatOptions.builder()
.toolCallbacks(toolCallback)
.build():
Prompt prompt = new Prompt("What's the weather like in Copenhagen?", chatOptions);
chatModel.call(prompt);

将默认工具添加到ChatModel
使用编程规范方法时,可以通过将实例传递给用于创建 . 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。ChatModelFunctionToolCallbacktoolCallbacks()ToolCallingChatOptionsChatModel

1
2
3
4
5
6
7
ToolCallback toolCallback = ...
ChatModel chatModel = OllamaChatModel.builder()
.ollamaApi(OllamaApi.builder().build())
.defaultOptions(ToolCallingChatOptions.builder()
.toolCallbacks(toolCallback)
.build())
.build();

动态规格:@Bean

您可以将工具定义为 Spring bean,并让 Spring AI 在运行时使用接口(通过实现)动态解析它们,而不是以编程方式指定工具。此选项使您可以使用任何 、 、 或 bean 作为工具。bean 名称将用作工具名称,Spring Framework 中的注释可用于提供工具的描述,模型使用它来了解何时以及如何调用该工具。如果未提供说明,则方法名称将用作工具说明。但是,强烈建议提供详细的描述,因为这对于模型理解工具的用途以及如何使用它至关重要。未能提供良好的描述可能会导致模型在应该使用的工具时没有使用或错误地使用该工具。ToolCallbackResolverSpringBeanToolCallbackResolverFunctionSupplierConsumerBiFunction@Description

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration(proxyBeanMethods = false)
class WeatherTools {

WeatherService weatherService = new WeatherService();

@Bean
@Description("Get the weather in location")
Function<WeatherRequest, WeatherResponse> currentWeather() {
return weatherService;
}

}

将自动生成工具输入参数的 JSON 模式。您可以使用注释提供有关输入参数的其他信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。有关更多详细信息,请参阅 JSON 架构。@ToolParam

1
record WeatherRequest(@ToolParam(description = "The name of a city or a country") String location, Unit unit) {}

这种工具规范方法的缺点是不能保证类型安全,因为工具解析是在运行时完成的。为了缓解这种情况,您可以使用批注显式指定工具名称,并将值存储在常量中,以便可以在聊天请求中使用它,而不是对工具名称进行硬编码。@Bean

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration(proxyBeanMethods = false)
class WeatherTools {

public static final String CURRENT_WEATHER_TOOL = "currentWeather";

@Bean(CURRENT_WEATHER_TOOL)
@Description("Get the weather in location")
Function<WeatherRequest, WeatherResponse> currentWeather() {
...
}

}

将工具添加到ChatClient
使用动态规范方法时,可以将工具名称(即函数 bean 名称)传递给 的方法。 该工具仅适用于添加它的特定聊天请求。tools()ChatClient

1
2
3
4
5
ChatClient.create(chatModel)
.prompt("What's the weather like in Copenhagen?")
.toolNames("currentWeather")
.call()
.content();

将默认工具添加到ChatClient
使用动态规范方法时,可以通过将工具名称传递给方法来将默认工具添加到 中。 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。ChatClient.BuilderdefaultToolNames()

默认工具在从同一 .它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。ChatClientChatClient.Builder

1
2
3
4
ChatModel chatModel = ...
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultToolNames("currentWeather")
.build();

将工具添加到ChatModel
使用动态规范方法时,可以将工具名称传递给用于调用 .该工具仅适用于添加它的特定聊天请求。toolNames()ToolCallingChatOptionsChatModel

1
2
3
4
5
6
ChatModel chatModel = ...
ChatOptions chatOptions = ToolCallingChatOptions.builder()
.toolNames("currentWeather")
.build();
Prompt prompt = new Prompt("What's the weather like in Copenhagen?", chatOptions);
chatModel.call(prompt);

将默认工具添加到ChatModel
使用动态规范方法时,可以通过将工具名称传递给用于创建 的实例的方法,在构造时将默认工具添加到 . 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。ChatModeltoolNames()ToolCallingChatOptionsChatModel

默认工具在该实例执行的所有聊天请求中共享。它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。ChatModel

1
2
3
4
5
6
ChatModel chatModel = OllamaChatModel.builder()
.ollamaApi(OllamaApi.builder().build())
.defaultOptions(ToolCallingChatOptions.builder()
.toolNames("currentWeather")
.build())
.build();