MCP 客户端注解
MCP 客户端注解通过 Java 注解提供了一种声明式方式来实现 MCP 客户端处理器。这些注解简化了服务器通知的处理以及客户端操作的实现。
MCP 客户端注解通过 Java 注解提供了一种声明式方式来实现 MCP 客户端处理器。这些注解简化了服务器通知的处理以及客户端操作的实现。
所有 MCP 客户端注解 必须 包含
clients 参数,用于将处理器与特定的 MCP 客户端连接关联。clients 的值必须与您在应用配置中设置的连接名称相匹配。客户端注解
@McpLogging
@McpLogging 注解用于处理来自 MCP 服务器的日志消息通知。
基础用法
@Component
public class LoggingHandler {
@McpLogging(clients = "my-mcp-server")
public void handleLoggingMessage(LoggingMessageNotification notification) {
System.out.println("Received log: " + notification.level() +
" - " + notification.data());
}
}
使用单独参数
@McpLogging(clients = "my-mcp-server")
public void handleLoggingWithParams(LoggingLevel level, String logger, String data) {
System.out.println(String.format("[%s] %s: %s", level, logger, data));
}
@McpSampling
@McpSampling 注解用于处理来自 MCP 服务器的采样请求(用于 LLM 完成)。
同步实现
@Component
public class SamplingHandler {
@McpSampling(clients = "llm-server")
public CreateMessageResult handleSamplingRequest(CreateMessageRequest request) {
// 处理请求并生成响应
String response = generateLLMResponse(request);
return CreateMessageResult.builder()
.role(Role.ASSISTANT)
.content(new TextContent(response))
.model("gpt-4")
.build();
}
}
异步实现
@Component
public class AsyncSamplingHandler {
@McpSampling(clients = "llm-server")
public Mono<CreateMessageResult> handleAsyncSampling(CreateMessageRequest request) {
return Mono.fromCallable(() -> {
String response = generateLLMResponse(request);
return CreateMessageResult.builder()
.role(Role.ASSISTANT)
.content(new TextContent(response))
.model("gpt-4")
.build();
}).subscribeOn(Schedulers.boundedElastic());
}
}
@McpElicitation
@McpElicitation 注解用于处理从用户收集额外信息的引导(elicitation)请求。
基本用法
@Component
public class ElicitationHandler {
@McpElicitation(clients = "interactive-server")
public ElicitResult handleElicitationRequest(ElicitRequest request) {
// 向用户展示请求并收集输入
Map<String, Object> userData = presentFormToUser(request.requestedSchema());
if (userData != null) {
return new ElicitResult(ElicitResult.Action.ACCEPT, userData);
} else {
return new ElicitResult(ElicitResult.Action.DECLINE, null);
}
}
}
带用户交互
@McpElicitation(clients = "interactive-server")
public ElicitResult handleInteractiveElicitation(ElicitRequest request) {
Map<String, Object> schema = request.requestedSchema();
Map<String, Object> userData = new HashMap<>();
// 检查请求的信息
if (schema != null && schema.containsKey("properties")) {
Map<String, Object> properties = (Map<String, Object>) schema.get("properties");
// 根据 schema 收集用户输入
if (properties.containsKey("name")) {
userData.put("name", promptUser("请输入您的姓名:"));
}
if (properties.containsKey("email")) {
userData.put("email", promptUser("请输入您的邮箱:"));
}
if (properties.containsKey("preferences")) {
userData.put("preferences", gatherPreferences());
}
}
return new ElicitResult(ElicitResult.Action.ACCEPT, userData);
}
异步引导
@McpElicitation(clients = "interactive-server")
public Mono<ElicitResult> handleAsyncElicitation(ElicitRequest request) {
return Mono.fromCallable(() -> {
// 异步收集用户输入
Map<String, Object> userData = asyncGatherUserInput(request);
return new ElicitResult(ElicitResult.Action.ACCEPT, userData);
}).timeout(Duration.ofSeconds(30))
.onErrorReturn(new ElicitResult(ElicitResult.Action.CANCEL, null));
}
@McpProgress
@McpProgress 注解用于处理长时间运行操作的进度通知。
基本用法
@Component
public class ProgressHandler {
@McpProgress(clients = "my-mcp-server")
public void handleProgressNotification(ProgressNotification notification) {
double percentage = notification.progress() * 100;
System.out.println(String.format("进度: %.2f%% - %s",
percentage, notification.message()));
}
}
使用单独参数
@McpProgress(clients = "my-mcp-server")
public void handleProgressWithDetails(
String progressToken,
double progress,
Double total,
String message) {
if (total != null) {
System.out.println(String.format("[%s] %.0f/%.0f - %s",
progressToken, progress, total, message));
} else {
System.out.println(String.format("[%s] %.2f%% - %s",
progressToken, progress * 100, message));
}
// 更新 UI 进度条
updateProgressBar(progressToken, progress);
}
针对特定客户端的进度处理
@McpProgress(clients = "long-running-server")
public void handleLongRunningProgress(ProgressNotification notification) {
// 跟踪特定服务器的进度
progressTracker.update("long-running-server", notification);
// 如果需要,发送完成通知
if (notification.progress() >= 1.0) {
notifyCompletion(notification.progressToken());
}
}
@McpToolListChanged
@McpToolListChanged 注解用于处理服务器工具列表发生变化时的通知。
基本用法
@Component
public class ToolListChangedHandler {
@McpToolListChanged(clients = "tool-server")
public void handleToolListChanged(List<McpSchema.Tool> updatedTools) {
System.out.println("工具列表已更新: " + updatedTools.size() + " 个工具可用");
// 更新本地工具注册表
toolRegistry.updateTools(updatedTools);
// 输出新工具信息
for (McpSchema.Tool tool : updatedTools) {
System.out.println(" - " + tool.name() + ": " + tool.description());
}
}
}
异步处理
@McpToolListChanged(clients = "tool-server")
public Mono<Void> handleAsyncToolListChanged(List<McpSchema.Tool> updatedTools) {
return Mono.fromRunnable(() -> {
// 异步处理工具列表更新
processToolListUpdate(updatedTools);
// 通知相关组件
eventBus.publish(new ToolListUpdatedEvent(updatedTools));
}).then();
}
针对特定客户端的工具更新
@McpToolListChanged(clients = "dynamic-server")
public void handleDynamicServerToolUpdate(List<McpSchema.Tool> updatedTools) {
// 处理来自经常更新工具的特定服务器的工具列表
dynamicToolManager.updateServerTools("dynamic-server", updatedTools);
// 重新评估工具可用性
reevaluateToolCapabilities();
}
@McpResourceListChanged
@McpResourceListChanged 注解用于处理服务器资源列表发生变化时的通知。
基本用法
@Component
public class ResourceListChangedHandler {
@McpResourceListChanged(clients = "resource-server")
public void handleResourceListChanged(List<McpSchema.Resource> updatedResources) {
System.out.println("资源已更新: " + updatedResources.size());
// 更新资源缓存
resourceCache.clear();
for (McpSchema.Resource resource : updatedResources) {
resourceCache.register(resource);
}
}
}
带资源分析
@McpResourceListChanged(clients = "resource-server")
public void analyzeResourceChanges(List<McpSchema.Resource> updatedResources) {
// 分析变更情况
Set<String> newUris = updatedResources.stream()
.map(McpSchema.Resource::uri)
.collect(Collectors.toSet());
Set<String> removedUris = previousUris.stream()
.filter(uri -> !newUris.contains(uri))
.collect(Collectors.toSet());
if (!removedUris.isEmpty()) {
handleRemovedResources(removedUris);
}
// 更新跟踪状态
previousUris = newUris;
}
@McpPromptListChanged
@McpPromptListChanged 注解用于处理服务器提示(prompt)列表发生变化时的通知。
基本用法
@Component
public class PromptListChangedHandler {
@McpPromptListChanged(clients = "prompt-server")
public void handlePromptListChanged(List<McpSchema.Prompt> updatedPrompts) {
System.out.println("提示已更新: " + updatedPrompts.size());
// 更新提示目录
promptCatalog.updatePrompts(updatedPrompts);
// 如有必要,刷新界面
if (uiController != null) {
uiController.refreshPromptList(updatedPrompts);
}
}
}
异步处理
@McpPromptListChanged(clients = "prompt-server")
public Mono<Void> handleAsyncPromptUpdate(List<McpSchema.Prompt> updatedPrompts) {
return Flux.fromIterable(updatedPrompts)
.flatMap(prompt -> validatePrompt(prompt))
.collectList()
.doOnNext(validPrompts -> {
promptRepository.saveAll(validPrompts);
})
.then();
}
Spring Boot 集成
在使用 Spring Boot 自动配置时,客户端处理器会被自动检测并注册:
@SpringBootApplication
public class McpClientApplication {
public static void main(String[] args) {
SpringApplication.run(McpClientApplication.class, args);
}
}
@Component
public class MyClientHandlers {
@McpLogging(clients = "my-server")
public void handleLogs(LoggingMessageNotification notification) {
// 处理日志
}
@McpSampling(clients = "my-server")
public CreateMessageResult handleSampling(CreateMessageRequest request) {
// 处理采样请求
}
@McpProgress(clients = "my-server")
public void handleProgress(ProgressNotification notification) {
// 处理进度通知
}
}
自动配置功能包括:
- 扫描带有 MCP 客户端注解的 Spring Bean
- 创建对应的处理规范(specifications)
- 将其注册到 MCP 客户端
- 支持同步(sync)和异步(async)实现
- 支持多个客户端以及针对不同客户端的处理器
配置属性
配置客户端注解扫描器和客户端连接:
spring:
ai:
mcp:
client:
type: SYNC # 或 ASYNC
annotation-scanner:
enabled: true
# 配置客户端连接 —— 连接名称将作为 annotations 中的 clients 值
sse:
connections:
my-server: # 在 annotations 中的 clients 值
url: http://localhost:8080
tool-server: # 另一个 clients
url: http://localhost:8081
stdio:
connections:
local-server: # 在 annotations 中的 clients 值
command: /path/to/mcp-server
args:
- --mode=production
注:注解中的
clients 参数必须与配置中定义的连接名称一致。
在上例中,合法的 clients 值为 "my-server"、"tool-server" 和 "local-server"。在 MCP 客户端中的使用
带有注解的处理器会自动与 MCP 客户端集成:
@Autowired
private List<McpSyncClient> mcpClients;
// 这些客户端将自动使用你的注解处理器
// 无需手动注册 —— 处理器会根据 clients 名称匹配客户端
对于每个 MCP 客户端连接,clients 参数匹配的处理器会被自动注册,并在对应事件发生时调用。