跳到主要内容

MCP服务器

备注

0.8.x版本的重大变更 ⚠️

注意: 0.8.x版本引入了几个重大变更,包括新的基于会话的架构。 如果您从0.7.0版本升级,请参考迁移指南获取详细说明。

概述

MCP服务器是模型上下文协议(MCP)架构中的基础组件,向客户端提供工具、资源和功能。它实现了协议的服务器端部分,负责:

  • 暴露客户端可以发现和执行的工具
  • 使用基于URI的访问模式管理资源
  • 提供提示模板和处理提示请求
  • 支持与客户端的能力协商
  • 实现服务器端协议操作
  • 管理并发客户端连接
  • 提供结构化日志和通知
提示

Spring-AI MCP服务器集成扩展了MCP Java SDK, 为Spring Boot应用程序中的MCP服务器功能提供自动配置。

服务器支持同步和异步API,允许在不同应用程序上下文中灵活集成。

// 创建具有自定义配置的服务器
McpSyncServer syncServer = McpServer.sync(transportProvider)
    .serverInfo("my-server", "1.0.0")
    .capabilities(ServerCapabilities.builder()
        .resources(true)     // 启用资源支持
        .tools(true)         // 启用工具支持
        .prompts(true)       // 启用提示支持
        .logging()           // 启用日志支持
        .build())
    .build();

// 注册工具、资源和提示
syncServer.addTool(syncToolSpecification);
syncServer.addResource(syncResourceSpecification);
syncServer.addPrompt(syncPromptSpecification);

// 发送日志通知
syncServer.loggingNotification(LoggingMessageNotification.builder()
    .level(LoggingLevel.INFO)
    .logger("custom-logger")
    .data("服务器已初始化")
    .build());

// 完成后关闭服务器
syncServer.close();

服务器传输提供程序

MCP SDK中的传输层负责处理客户端和服务器之间的通信。 它提供不同的实现来支持各种通信协议和模式。 SDK包含几个内置的传输提供程序实现:

创建基于进程的传输:

StdioServerTransportProvider transportProvider = new StdioServerTransportProvider(new ObjectMapper());

通过标准输入/输出流提供双向JSON-RPC消息处理,支持非阻塞消息处理、序列化/反序列化和优雅关闭。

主要特性:

  • 通过stdin/stdout进行双向通信
  • 支持基于进程的集成
  • 简单的设置和配置
  • 轻量级实现

服务器功能

服务器可以配置各种功能:

var capabilities = ServerCapabilities.builder()
    .resources(false, true)  // 带列表变更通知的资源支持
    .tools(true)            // 带列表变更通知的工具支持
    .prompts(true)          // 带列表变更通知的提示支持
    .logging()              // 启用日志支持(默认启用,日志级别为INFO)
    .build();

工具支持

工具是服务器提供的可执行函数。服务器可以注册工具并处理工具执行请求:

// 定义工具规范
var toolSpec = ToolSpecification.builder()
    .name("calculator")
    .description("简单的计算器工具")
    .inputSchema(Map.of(
        "operation", Map.of(
            "type", "string",
            "enum", List.of("add", "subtract", "multiply", "divide")
        ),
        "a", Map.of("type", "number"),
        "b", Map.of("type", "number")
    ))
    .build();

// 注册工具
server.addTool(toolSpec);

// 处理工具调用
server.setToolHandler("calculator", request -> {
    var operation = (String) request.getArguments().get("operation");
    var a = (Number) request.getArguments().get("a");
    var b = (Number) request.getArguments().get("b");
    
    var result = switch (operation) {
        case "add" -> a.doubleValue() + b.doubleValue();
        case "subtract" -> a.doubleValue() - b.doubleValue();
        case "multiply" -> a.doubleValue() * b.doubleValue();
        case "divide" -> a.doubleValue() / b.doubleValue();
        default -> throw new IllegalArgumentException("未知操作: " + operation);
    };
    
    return new CallToolResult(List.of(
        new TextContent("text", String.valueOf(result))
    ));
});

资源支持

资源是服务器提供的可访问数据。服务器可以注册资源并提供资源访问:

// 定义资源规范
var resourceSpec = ResourceSpecification.builder()
    .uri("file:///path/to/resource")
    .name("示例资源")
    .description("这是一个示例资源")
    .mimeType("text/plain")
    .build();

// 注册资源
server.addResource(resourceSpec);

// 处理资源读取请求
server.setResourceHandler("file:///path/to/resource", request -> {
    var content = readResourceContent();
    return new ReadResourceResult(List.of(
        new ResourceContent(
            "file:///path/to/resource",
            "text/plain",
            content
        )
    ));
});

// 处理资源列表请求
server.setResourceListHandler(request -> {
    return new ListResourcesResult(List.of(resourceSpec));
});

提示支持

提示是预定义的模板,可以生成结构化的消息。服务器可以注册提示并处理提示请求:

// 定义提示规范
var promptSpec = PromptSpecification.builder()
    .name("greeting")
    .description("生成问候消息")
    .arguments(Map.of(
        "name", Map.of(
            "type", "string",
            "description", "要问候的人的名字",
            "required", true
        )
    ))
    .build();

// 注册提示
server.addPrompt(promptSpec);

// 处理提示请求
server.setPromptHandler("greeting", request -> {
    var name = (String) request.getArguments().get("name");
    return new GetPromptResult(
        List.of(
            new Message(
                "user",
                new TextContent("text", "你好, " + name + "!")
            )
        )
    );
});

错误处理

MCP服务器提供全面的错误处理机制:

try {
    // 执行可能失败的操作
    server.addTool(toolSpec);
} catch (McpException e) {
    // 处理MCP特定错误
    logger.error("MCP错误: " + e.getMessage());
} catch (Exception e) {
    // 处理其他错误
    logger.error("错误: " + e.getMessage());
}

对于异步API,错误处理通过错误回调进行:

server.addTool(toolSpec)
    .subscribe(
        v -> logger.info("工具已注册"),
        error -> logger.error("错误: " + error.getMessage())
    );

最佳实践

  1. 资源管理

    • 及时关闭服务器连接
    • 使用try-with-resources语句
    • 管理资源订阅的生命周期
  2. 错误处理

    • 实现适当的错误处理
    • 记录错误信息
    • 提供用户友好的错误消息
  3. 性能优化

    • 重用服务器实例
    • 适当设置超时
    • 管理并发请求
  4. 安全性

    • 验证客户端证书
    • 保护敏感数据
    • 实现适当的访问控制
  5. 监控和日志

    • 记录重要操作
    • 监控性能指标
    • 跟踪错误模式

下一步