MCP 服務器

0.8.x版本重大變更 ⚠️

注意: 0.8.x版本引入了幾個重大變更,包括新的基於會話的架構。 如果您正在從0.7.0升級,請參考遷移指南獲取詳細說明。

概述

MCP服務器是模型上下文協議(MCP)架構中的基礎組件,為客戶端提供工具、資源和功能。它實現了協議的服務器端,負責:

  • 暴露客戶端可以發現和執行的工具
  • 管理基於URI的資源訪問模式
  • 提供提示模板並處理提示請求
  • 支持與客戶端的能力協商
  • 實現服務器端協議操作
  • 管理併發客戶端連接
  • 提供結構化日誌和通知

服務器同時支持同步和異步API,允許在不同的應用場景中靈活集成。

// 創建具有自定義配置的服務器
McpSyncServer syncServer = McpServer.sync(transport)
    .serverInfo("my-server", "1.0.0")
    .capabilities(ServerCapabilities.builder()
        .resources(true)     // 啟用資源支持
        .tools(true)         // 啟用工具支持
        .prompts(true)       // 啟用提示支持
        .logging()           // 啟用日誌支持
        .build())
    .build();

// 註冊工具、資源和提示
syncServer.addTool(syncToolRegistration);
syncServer.addResource(syncResourceRegistration);
syncServer.addPrompt(syncPromptRegistration);

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

// 完成後關閉服務器
syncServer.close();
// 創建具有自定義配置的異步服務器
McpAsyncServer asyncServer = McpServer.async(transport)
    .serverInfo("my-server", "1.0.0") 
    .capabilities(ServerCapabilities.builder()
        .resources(true)     // 啟用資源支持
        .tools(true)         // 啟用工具支持
        .prompts(true)       // 啟用提示支持
        .logging()           // 啟用日誌支持
        .build())
    .build();

// 註冊工具、資源和提示
asyncServer.addTool(asyncToolRegistration);
asyncServer.addResource(asyncResourceRegistration);
asyncServer.addPrompt(asyncPromptRegistration);

// 發送日誌通知
asyncServer.loggingNotification(LoggingMessageNotification.builder()
    .level(LoggingLevel.INFO)
    .logger("custom-logger")
    .data("服務器已初始化")
    .build());

// 完成後關閉服務器
asyncServer.close();

服務器傳輸

創建基於進程的傳輸:

StdioServerTransport transport = new StdioServerTransport(new ObjectMapper());

提供基於標準輸入/輸出流的雙向JSON-RPC消息處理,具有非阻塞消息處理、序列化/反序列化和優雅關閉支持。

主要特性:

  • 通過stdin/stdout進行雙向通信
  • 支持基於進程的集成
  • 簡單的設置和配置
  • 輕量級實現

創建基於WebFlux的SSE服務器傳輸。 需要 mcp-spring-webflux 依賴。

@Configuration
class McpConfig {
    @Bean
    WebFluxSseServerTransport webFluxSseServerTransport(ObjectMapper mapper) {
        return new WebFluxSseServerTransport(mapper, "/mcp/message");
    }

    @Bean
    RouterFunction<?> mcpRouterFunction(WebFluxSseServerTransport transport) {
        return transport.getRouterFunction();
    }
}

實現了帶SSE傳輸規範的MCP HTTP,提供:

  • 基於WebFlux的響應式HTTP流
  • 通過SSE端點的併發客戶端連接
  • 消息路由和會話管理
  • 優雅關閉功能

創建基於WebMvc的SSE服務器傳輸。 需要 mcp-spring-webmvc 依賴。

@Configuration
@EnableWebMvc
class McpConfig {
    @Bean
    WebMvcSseServerTransport webMvcSseServerTransport(ObjectMapper mapper) {
        return new WebMvcSseServerTransport(mapper, "/mcp/message");
    }

    @Bean
    RouterFunction<ServerResponse> mcpRouterFunction(WebMvcSseServerTransport transport) {
        return transport.getRouterFunction();
    }
}

實現了帶SSE傳輸規範的MCP HTTP,提供:

  • 服務器端事件流
  • 與Spring WebMVC的集成
  • 支持傳統Web應用
  • 同步操作處理

創建基於Servlet的SSE服務器傳輸。包含在核心mcp模塊中。 HttpServletSseServerTransport可以與任何Servlet容器一起使用。 要在Spring Web應用程序中使用它,你可以將其註冊為Servlet bean:

@Configuration
@EnableWebMvc
public class McpServerConfig implements WebMvcConfigurer {

    @Bean
    public HttpServletSseServerTransport servletSseServerTransport() {
        return new HttpServletSseServerTransport(new ObjectMapper(), "/mcp/message");
    }

    @Bean
    public ServletRegistrationBean customServletBean(HttpServletSseServerTransport servlet) {
        return new ServletRegistrationBean(servlet);
    }
}

使用傳統Servlet API實現MCP HTTP與SSE傳輸規範,提供:

  • 使用Servlet 6.0異步支持的異步消息處理
  • 多客戶端連接的會話管理
  • 兩種類型的端點:
    • SSE端點(/sse)用於服務器到客戶端的事件
    • 消息端點(可配置)用於客戶端到服務器的請求
  • 錯誤處理和響應格式化
  • 優雅關閉支持

服務器功能

服務器可以配置多種功能來支持不同的使用場景。以下是主要的服務器功能:

工具支持

工具允許服務器向客戶端暴露可執行的功能。每個工具都有一個唯一的名稱和一組參數:

// 定義同步工具
var calculator = new SyncToolRegistration(
    "calculator",                    // 工具名稱
    "簡單的計算器工具",              // 描述
    Map.of(                         // 參數定義
        "operation", ParameterType.STRING,
        "a", ParameterType.NUMBER,
        "b", ParameterType.NUMBER
    ),
    request -> {                    // 執行邏輯
        var operation = request.getParameter("operation");
        var a = request.getParameter("a", Double.class);
        var b = request.getParameter("b", Double.class);
        
        double result = switch(operation) {
            case "add" -> a + b;
            case "subtract" -> a - b;
            case "multiply" -> a * b;
            case "divide" -> a / b;
            default -> throw new IllegalArgumentException("未知操作");
        };
        
        return new ToolResult(Map.of("result", result));
    }
);

// 註冊工具
syncServer.addTool(calculator);
// 定義異步工具
var calculator = new AsyncToolRegistration(
    "calculator",                    // 工具名稱
    "簡單的計算器工具",              // 描述
    Map.of(                         // 參數定義
        "operation", ParameterType.STRING,
        "a", ParameterType.NUMBER,
        "b", ParameterType.NUMBER
    ),
    request -> Mono.fromCallable(() -> {
        var operation = request.getParameter("operation");
        var a = request.getParameter("a", Double.class);
        var b = request.getParameter("b", Double.class);
        
        double result = switch(operation) {
            case "add" -> a + b;
            case "subtract" -> a - b;
            case "multiply" -> a * b;
            case "divide" -> a / b;
            default -> throw new IllegalArgumentException("未知操作");
        };
        
        return new ToolResult(Map.of("result", result));
    })
);

// 註冊工具
asyncServer.addTool(calculator);

資源支持

資源允許客戶端通過URI模板訪問服務器端數據。每個資源都有唯一的URI模式和相關的元數據:

// 定義同步資源
var fileResource = new SyncResourceRegistration(
    "file",                         // 資源名稱
    "文件系統資源",                  // 描述
    Map.of(                        // URI參數定義
        "path", ParameterType.STRING
    ),
    request -> {                   // 訪問邏輯
        var path = request.getParameter("path");
        var content = Files.readString(Path.of(path));
        return new ResourceResult(content);
    }
);

// 註冊資源
syncServer.addResource(fileResource);
// 定義異步資源
var fileResource = new AsyncResourceRegistration(
    "file",                         // 資源名稱
    "文件系統資源",                  // 描述
    Map.of(                        // URI參數定義
        "path", ParameterType.STRING
    ),
    request -> Mono.fromCallable(() -> {
        var path = request.getParameter("path");
        var content = Files.readString(Path.of(path));
        return new ResourceResult(content);
    })
);

// 註冊資源
asyncServer.addResource(fileResource);

提示支持

提示系統允許服務器定義可複用的提示模板。每個提示模板都有一個名稱和一組參數:

// 定義同步提示
var echoPrompt = new SyncPromptRegistration(
    "echo",                         // 提示名稱
    "回顯輸入文本",                  // 描述
    Map.of(                        // 參數定義
        "text", ParameterType.STRING
    ),
    request -> {                   // 執行邏輯
        var text = request.getParameter("text");
        return new PromptResult(text);
    }
);

// 註冊提示
syncServer.addPrompt(echoPrompt);
// 定義異步提示
var echoPrompt = new AsyncPromptRegistration(
    "echo",                         // 提示名稱
    "回顯輸入文本",                  // 描述
    Map.of(                        // 參數定義
        "text", ParameterType.STRING
    ),
    request -> Mono.fromCallable(() -> {
        var text = request.getParameter("text");
        return new PromptResult(text);
    })
);

// 註冊提示
asyncServer.addPrompt(echoPrompt);

日誌支持

服務器提供結構化日誌功能,允許使用不同嚴重級別向客戶端發送日誌消息:

// 向客戶端發送日誌消息
server.loggingNotification(LoggingMessageNotification.builder()
    .level(LoggingLevel.INFO)
    .logger("custom-logger")
    .data("自定義日誌消息")
    .build());

客戶端可以通過mcpClient.setLoggingLevel(level)請求控制他們接收的最低日誌級別。低於設置級別的消息將被過濾掉。 支持的日誌級別(按嚴重程度遞增排序):DEBUG (0)、INFO (1)、NOTICE (2)、WARNING (3)、ERROR (4)、CRITICAL (5)、ALERT (6)、EMERGENCY (7)

錯誤處理

SDK通過McpError類提供全面的錯誤處理,涵蓋:

  • 協議兼容性問題
  • 傳輸通信錯誤
  • JSON-RPC消息傳遞異常
  • 工具執行錯誤
  • 資源管理問題
  • 提示處理異常
  • 超時和連接問題

這種統一的錯誤處理方法確保了同步和異步操作中一致且可靠的錯誤管理。