Java MCP 鉴权设计与实现指南

一、MCP 鉴权概述

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

根据提供的资料,MCP 鉴权主要涉及以下几个方面:

  • 服务端鉴权设计
  • 客户端鉴权配置
  • 不同通讯通道(stdio/SSE)的鉴权实现
  • 与 Web API 互通的鉴权处理

本案基于 Solon AI MCP 进行鉴权方面的探讨:

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai-mcp</artifactId>
    <version>最新版本</version>
</dependency>

可支持 java8, java11, java17, java21, java24 。可支持 solon,springboot,vert.x,jFinal 等框架集成。

二、MCP 服务端鉴权设计

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

MCP 服务端可以通过过滤器或路由拦截器实现鉴权,特别是对于 HTTP SSE 通道的服务:

@Component
public class McpFilter implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        //message 端点,不需要鉴权
        if (ctx.pathNew().startsWith("/mcp/") && ctx.pathNew().endsWith("/message") == false) { 
            String authStr = ctx.header("Authorization");
            if (Utils.isEmpty(authStr)) {
                ctx.status(401);
                return;
            }
            // 业务检测逻辑
            if (!checkAuth(authStr)) {
                ctx.status(403);
                return;
            }
        }
        
        chain.doFilter(ctx);
    }
    
    private boolean checkAuth(String authStr) {
        // 实现具体的鉴权逻辑
        return true;
    }
}

2、基于注解的端点级鉴权

对于使用 @McpServerEndpoint 注解的服务端点,可以通过 @Header 注解或者 上下文对象(Context) 获取用户身份或鉴权信息:

@McpServerEndpoint(sseEndpoint = "/mcp/sse")
public class McpAuthService {
    
    @ToolMapping(description = "需要鉴权的天气预报查询")
    public String getWeather(@Param(description = "城市位置") String location, @Header("user") user, Context ctx) {
        // 根据用户隔离数据: user
        
        // 从上下文中获取鉴权或身份信息: ctx
        
        return "晴,14度";
    }
}

在方法里鉴权时不能输出状态码,要改为异常抛出。

三、MCP 客户端鉴权配置

1、Basic Authentication

McpClientProvider toolProvider = McpClientProvider.builder()
    .apiUrl("https://localhost:8080/mcp/sse")
    .apiKey("sk-xxxxx") // 自动转换为Authorization头
    .build();

2、自定义 Header 鉴权

McpClientProvider toolProvider = McpClientProvider.builder()
    .apiUrl("https://localhost:8080/mcp/sse")
    .header("X-API-KEY", "your-api-key")
    .header("X-API-SECRET", "your-api-secret")
    .header("X-USER", "your-user")
    .build();

3、QueryString 参数鉴权(比较常见)

McpClientProvider toolProvider = McpClientProvider.builder()
    .apiUrl("https://localhost:8080/mcp/sse?token=xxxx")
    .build();

四、不同通道的鉴权实现

1、HTTP SSE 通道鉴权

HTTP SSE 通道的鉴权可以利用 HTTP 协议本身的特性:

@Configuration
public class McpSseAuthConfig {
    
    @Bean
    public McpClientProvider sseClient() {
        return McpClientProvider.builder()
            .apiUrl("http://localhost:8080/mcp/sse")
            .header("X-Auth-Token", "your-token")
            .httpTimeout(HttpTimeout.builder()
                .connectTimeout(Duration.ofSeconds(10))
                .readTimeout(Duration.ofSeconds(60))
                .build())
            .build();
    }
}

2、2. STDIO 通道鉴权

对于 STDIO 通道,鉴权通常通过环境变量或启动参数实现:

@McpServerEndpoint(channel = McpChannel.STDIO)
public class StdioAuthService {
    
    @ToolMapping(description = "STDIO通道的鉴权服务")
    public String secureOperation(@Param String input) {
        String authToken = System.getenv("INTERNAL_AUTH_TOKEN");
        if(!validateInternalToken(authToken)) {
            throw new SecurityException("Invalid internal token");
        }
        
        return processInput(input);
    }
}

客户端调用时配置环境变量:

McpClientProvider stdioClient = McpClientProvider.builder()
    .channel(McpChannel.STDIO)
    .serverParameters(ServerParameters.builder("java")
        .args("-jar", "secure-service.jar")
        .addEnvVar("INTERNAL_AUTH_TOKEN", "secure-token-value")
        .build())
    .build();

五、与 Web API 互通的鉴权

MCP 服务可以与 Web API 互通,共享鉴权逻辑:

@Mapping("/api/secure")
@Controller
@McpServerEndpoint(sseEndpoint = "/mcp/secure/sse")
public class HybridAuthService {
    
    @ToolMapping(description = "混合鉴权服务")
    @Mapping("operation")
    public String hybridOperation(
        @Param(description = "输入参数") String input,
        @Header("Authorization") String authHeader) {
        
        if(!validateAuthHeader(authHeader)) {
            throw new SecurityException("Unauthorized");
        }
        
        return "Processed: " + input;
    }
}

六、最佳实践与注意事项

多因素认证:对于高安全性要求的场景,可以结合多种鉴权方式

McpClientProvider highSecClient = McpClientProvider.builder()
    .apiUrl("https://secure.example.com/mcp/sse")
    .apiKey("primary-key")
    .header("X-Second-Factor", "totp-code")
    .build();

敏感信息保护:避免在日志中输出鉴权信息

// 开发 stdio 服务时特别重要
@McpServerEndpoint(channel = McpChannel.STDIO)
public class SecureStdioService {
    // 确保不打印敏感信息到控制台
}

性能考虑:对于高频调用的服务,采用高效的鉴权方案

// 使用高效的JWT验证
public class JwtAuthFilter implements Filter {
    // 实现快速的JWT验证逻辑
}

七、完整示例:带鉴权的 MCP 服务

服务端实现

// 鉴权配置类
@Configuration
public class McpAuthConfig {
    
    @Bean
    public Filter mcpAuthFilter() {
        return new McpAuthFilter();
    }
}

// 鉴权过滤器
public class McpAuthFilter implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        if (ctx.pathNew().startsWith("/mcp/") && ctx.pathNew().endsWith("/message") == false) {
            String token = ctx.header("X-Auth-Token");
            if (!"valid-token".equals(token)) {
                ctx.status(401).output("Unauthorized");
                return;
            }
        }
        chain.doFilter(ctx);
    }
}

// MCP服务端点
@McpServerEndpoint(sseEndpoint = "/mcp/secure/sse")
public class SecureMcpService {
    
    @ToolMapping(description = "安全操作")
    public String secureOp(@Param(description = "输入") String input) {
        return "Secure result for: " + input;
    }
}

客户端实现

public class SecureMcpClient {
    
    private final McpClientProvider client;
    
    public SecureMcpClient() {
        this.client = McpClientProvider.builder()
            .apiUrl("http://localhost:8080/mcp/secure/sse")
            .header("X-Auth-Token", "valid-token")
            .requestTimeout(Duration.ofSeconds(20))
            .build();
    }
    
    public String callSecureOp(String input) {
        return client.callToolAsText("secureOp", Map.of("input", input));
    }
}

总结

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

<think>我们正在讨论MCP(Model ContextProtocol)的机制。根据引用内容,MCPAI提供了统一的工具调用规范和外部系统连接能力。是确保只有合法用户或系统可以访问MCP服务的关键部分。机制通常涉及验证请求方的身份和限。在MCP中,可能包括以下步骤:1.客户端(如AI应用)向MCP服务发送请求时,需要携带认证信息(如APIKey、令牌等)。2. MCP服务接收到请求后,会验证认证信息的有效性(如检查签名、令牌有效期等)。3.验证通过后,MCP服务会检查该客户端是否有限执行请求的操作(如访问特定资源、调用特定工具等)。4.如果成功,请求将被处理;否则返回错误。实现方法可能包括:-使用APIKey:客户端在请求头中携带APIKey,服务端验证该Key是否合法且有访问请求的资源。- OAuth2.0:客户端先通过授服务器获取访问令牌,然后用该令牌访问MCP服务。MCP服务验证令牌的有效性和限范围。 -JWT(JSONWeb Token):客户端使用JWT,服务端通过验证签名和声明(如过期时间、限等)来。根据引用[2],MCP服务器地址配置中并没有直接体现信息,但在实际请求中,信息可能通过HTTP头部或其他安全方式传递。因此,在实现MCP时,需要:1.在MCP服务端配置中间件,用于拦截和验证请求。2.定义限模型(如基于角色的访问控制RBAC),明确不同客户端的限。3.安全地存储和管理凭证(如API Key)或密钥(用于验证签名)。例如,一个简单的APIKey实现可能如下(伪代码):```middlewareAuthMiddleware:defhandle(request):api_key= request.headers.get('X-API-KEY')if notapi_key:return401,"Unauthorized"ifnot validate_api_key(api_key):#验证api_key是否有效return403, "Forbidden"#验证通过,继续处理请求return next(request) ```其中,`validate_api_key`函数会检查数据库或配置文件中是否存在该APIKey,并检查其状态(是否有效、是否有限等)。对于更高级的安全需求,可以采用OAuth2.0或JWT,这些协议提供了更细粒度的限控制和令牌生命周期管理。注意:在实际部署时,应使用HTTPS来保护传输中的凭证,防止被截获。相关问题:1.MCP中如何安全地存储和管理APIKey?2.如何实现基于角色的访问控制(RBAC)MCP集成?3. MCP如何支持多租户场景?</think>### MCP 机制详解 #### 工作原理 MCP 机制的核心是**基于令牌的身份验证**(Token-based Authentication),通过数字签名确保请求的完整性和来源可信性[^1]。其工作流程如下: 1. **身份认证** 客户端(如AI应用)向服务器发送认证请求,包含身份凭证(如API Key/Secret)。 $$ \text{Client} \xrightarrow{\text{ID+Secret}} \text{Auth Server} $$ 2. **令牌发放** 服务器验证凭证有效性,生成带时效的访问令牌(Access Token)和刷新令牌(Refresh Token),使用非对称加密算法(如RSA)签名: $$ \text{Token} = \text{Sign}_{private\_key}(\text{ClientID} + \text{ExpiryTime}) $$ 3. **请求** 客户端在后续请求的`Authorization`头部携带令牌: ```http Authorization: Bearer <Access_Token> ``` MCP服务端用公钥验证签名和有效期,确认限范围[^2]。 4. **令牌刷新** 令牌过期前,客户端使用Refresh Token获取新Access Token,避免频繁认证。 #### 实现方法 1. **JWT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值