找回密码
 立即注册
首页 业界区 业界 Java MCP 鉴权设计与实现指南

Java MCP 鉴权设计与实现指南

洪思思 2025-7-10 09:14:38
一、MCP 鉴权概述

MCP (Model Context Protocol) 旨在为大语言模型(LLM)与外部数据源、工具和服务提供标准化、安全的集成方式(相当于一种专用的 RPC 协议)。广泛应用于 AI 开发中的工具服务(Tool)、提示语服务(Prompt)和资源服务(Resource)。在实际应用中,确保 MCP 服务的安全性至关重要,因此需要合理的鉴权机制。
根据提供的资料,MCP 鉴权主要涉及以下几个方面:

  • 服务端鉴权设计
  • 客户端鉴权配置
  • 不同通讯通道(stdio/SSE)的鉴权实现
  • 与 Web API 互通的鉴权处理
本案基于 Solon AI MCP 进行鉴权方面的探讨:
  1. <dependency>
  2.     <groupId>org.noear</groupId>
  3.     solon-ai-mcp</artifactId>
  4.     <version>最新版本</version>
  5. </dependency>
复制代码
可支持 java8, java11, java17, java21, java24 。可支持 solon,springboot,vert.x,jFinal 等框架集成。
二、MCP 服务端鉴权设计

1、基于过滤器的鉴权方案

MCP 服务端可以通过过滤器或路由拦截器实现鉴权,特别是对于 HTTP SSE 通道的服务:
  1. @Component
  2. public class McpFilter implements Filter {
  3.     @Override
  4.     public void doFilter(Context ctx, FilterChain chain) throws Throwable {
  5.         //message 端点,不需要鉴权
  6.         if (ctx.pathNew().startsWith("/mcp/") && ctx.pathNew().endsWith("/message") == false) {
  7.             String authStr = ctx.header("Authorization");
  8.             if (Utils.isEmpty(authStr)) {
  9.                 ctx.status(401);
  10.                 return;
  11.             }
  12.             // 业务检测逻辑
  13.             if (!checkAuth(authStr)) {
  14.                 ctx.status(403);
  15.                 return;
  16.             }
  17.         }
  18.         
  19.         chain.doFilter(ctx);
  20.     }
  21.    
  22.     private boolean checkAuth(String authStr) {
  23.         // 实现具体的鉴权逻辑
  24.         return true;
  25.     }
  26. }
复制代码
2、基于注解的端点级鉴权

对于使用 @McpServerEndpoint 注解的服务端点,可以通过 @Header 注解或者 上下文对象(Context) 获取用户身份或鉴权信息:
  1. @McpServerEndpoint(sseEndpoint = "/mcp/sse")
  2. public class McpAuthService {
  3.    
  4.     @ToolMapping(description = "需要鉴权的天气预报查询")
  5.     public String getWeather(@Param(description = "城市位置") String location, @Header("user") user, Context ctx) {
  6.         // 根据用户隔离数据: user
  7.         
  8.         // 从上下文中获取鉴权或身份信息: ctx
  9.         
  10.         return "晴,14度";
  11.     }
  12. }
复制代码
在方法里鉴权时不能输出状态码,要改为异常抛出。
三、MCP 客户端鉴权配置

1、Basic Authentication
  1. McpClientProvider toolProvider = McpClientProvider.builder()
  2.     .apiUrl("https://localhost:8080/mcp/sse")
  3.     .apiKey("sk-xxxxx") // 自动转换为Authorization头
  4.     .build();
复制代码
2、自定义 Header 鉴权
  1. McpClientProvider toolProvider = McpClientProvider.builder()
  2.     .apiUrl("https://localhost:8080/mcp/sse")
  3.     .header("X-API-KEY", "your-api-key")
  4.     .header("X-API-SECRET", "your-api-secret")
  5.     .header("X-USER", "your-user")
  6.     .build();
复制代码
3、QueryString 参数鉴权(比较常见)
  1. McpClientProvider toolProvider = McpClientProvider.builder()
  2.     .apiUrl("https://localhost:8080/mcp/sse?token=xxxx")
  3.     .build();
复制代码
四、不同通道的鉴权实现

1、HTTP SSE 通道鉴权

HTTP SSE 通道的鉴权可以利用 HTTP 协议本身的特性:
  1. @Configuration
  2. public class McpSseAuthConfig {
  3.    
  4.     @Bean
  5.     public McpClientProvider sseClient() {
  6.         return McpClientProvider.builder()
  7.             .apiUrl("http://localhost:8080/mcp/sse")
  8.             .header("X-Auth-Token", "your-token")
  9.             .httpTimeout(HttpTimeout.builder()
  10.                 .connectTimeout(Duration.ofSeconds(10))
  11.                 .readTimeout(Duration.ofSeconds(60))
  12.                 .build())
  13.             .build();
  14.     }
  15. }
复制代码
2、2. STDIO 通道鉴权

对于 STDIO 通道,鉴权通常通过环境变量或启动参数实现:
  1. @McpServerEndpoint(channel = McpChannel.STDIO)
  2. public class StdioAuthService {
  3.    
  4.     @ToolMapping(description = "STDIO通道的鉴权服务")
  5.     public String secureOperation(@Param String input) {
  6.         String authToken = System.getenv("INTERNAL_AUTH_TOKEN");
  7.         if(!validateInternalToken(authToken)) {
  8.             throw new SecurityException("Invalid internal token");
  9.         }
  10.         
  11.         return processInput(input);
  12.     }
  13. }
复制代码
客户端调用时配置环境变量:
  1. McpClientProvider stdioClient = McpClientProvider.builder()
  2.     .channel(McpChannel.STDIO)
  3.     .serverParameters(ServerParameters.builder("java")
  4.         .args("-jar", "secure-service.jar")
  5.         .addEnvVar("INTERNAL_AUTH_TOKEN", "secure-token-value")
  6.         .build())
  7.     .build();
复制代码
五、与 Web API 互通的鉴权

MCP 服务可以与 Web API 互通,共享鉴权逻辑:
  1. @Mapping("/api/secure")
  2. @Controller
  3. @McpServerEndpoint(sseEndpoint = "/mcp/secure/sse")
  4. public class HybridAuthService {
  5.    
  6.     @ToolMapping(description = "混合鉴权服务")
  7.     @Mapping("operation")
  8.     public String hybridOperation(
  9.         @Param(description = "输入参数") String input,
  10.         @Header("Authorization") String authHeader) {
  11.         
  12.         if(!validateAuthHeader(authHeader)) {
  13.             throw new SecurityException("Unauthorized");
  14.         }
  15.         
  16.         return "Processed: " + input;
  17.     }
  18. }
复制代码
六、最佳实践与注意事项

多因素认证:对于高安全性要求的场景,可以结合多种鉴权方式
  1. McpClientProvider highSecClient = McpClientProvider.builder()
  2.     .apiUrl("https://secure.example.com/mcp/sse")
  3.     .apiKey("primary-key")
  4.     .header("X-Second-Factor", "totp-code")
  5.     .build();
复制代码
敏感信息保护:避免在日志中输出鉴权信息
  1. // 开发 stdio 服务时特别重要
  2. @McpServerEndpoint(channel = McpChannel.STDIO)
  3. public class SecureStdioService {
  4.     // 确保不打印敏感信息到控制台
  5. }
复制代码
性能考虑:对于高频调用的服务,采用高效的鉴权方案
  1. // 使用高效的JWT验证
  2. public class JwtAuthFilter implements Filter {
  3.     // 实现快速的JWT验证逻辑
  4. }
复制代码
七、完整示例:带鉴权的 MCP 服务

服务端实现
  1. // 鉴权配置类
  2. @Configuration
  3. public class McpAuthConfig {
  4.    
  5.     @Bean
  6.     public Filter mcpAuthFilter() {
  7.         return new McpAuthFilter();
  8.     }
  9. }
  10. // 鉴权过滤器
  11. public class McpAuthFilter implements Filter {
  12.     @Override
  13.     public void doFilter(Context ctx, FilterChain chain) throws Throwable {
  14.         if (ctx.pathNew().startsWith("/mcp/") && ctx.pathNew().endsWith("/message") == false) {
  15.             String token = ctx.header("X-Auth-Token");
  16.             if (!"valid-token".equals(token)) {
  17.                 ctx.status(401).output("Unauthorized");
  18.                 return;
  19.             }
  20.         }
  21.         chain.doFilter(ctx);
  22.     }
  23. }
  24. // MCP服务端点
  25. @McpServerEndpoint(sseEndpoint = "/mcp/secure/sse")
  26. public class SecureMcpService {
  27.    
  28.     @ToolMapping(description = "安全操作")
  29.     public String secureOp(@Param(description = "输入") String input) {
  30.         return "Secure result for: " + input;
  31.     }
  32. }
复制代码
客户端实现
  1. public class SecureMcpClient {
  2.    
  3.     private final McpClientProvider client;
  4.    
  5.     public SecureMcpClient() {
  6.         this.client = McpClientProvider.builder()
  7.             .apiUrl("http://localhost:8080/mcp/secure/sse")
  8.             .header("X-Auth-Token", "valid-token")
  9.             .requestTimeout(Duration.ofSeconds(20))
  10.             .build();
  11.     }
  12.    
  13.     public String callSecureOp(String input) {
  14.         return client.callToolAsText("secureOp", Map.of("input", input));
  15.     }
  16. }
复制代码
总结

MCP 鉴权是保障服务安全性的重要环节,通过本文介绍的服务端过滤器、客户端配置、不同通道实现等方式,可以构建灵活安全的鉴权体系。在实际应用中,应根据具体场景选择适合的鉴权方案,并遵循安全最佳实践,确保 MCP 服务的安全可靠运行。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册