首页 / Spring AI 入门教程 / MCP 安全与注解

Spring AI 入门教程

MCP 安全与注解

本教程共 45 篇 · 第 31 篇 · 更新于 2026-08-16 · 约 8 分钟阅读

Spring AIMCP安全注解@McpToolOAuth2动态工具发现特殊参数

本节目标:了解 MCP 安全现状(官方标注 WIP),掌握服务端/客户端注解和特殊参数,最后认识动态工具发现。学完你能用注解快速开发 MCP 能力,并对安全方案有正确预期。

31.1 安全:先说结论

官方文档把 MCP Security 明确标注为 WIP(Work In Progress)。意思是文档和 API 后续可能变,生产落地前务必查最新状态。

它还不是 Spring AI 主项目的一部分,而是社区项目 spring-ai-community/mcp-security,官方尚未正式背书。依赖坐标是 org.springaicommunity 组,比如 mcp-server-security、mcp-client-security。

模块分三块:MCP Server Security(服务端)、MCP Client Security(客户端)、MCP Authorization Server(授权服务器)。下面分别介绍。

31.2 服务端安全

服务端安全支持两种方式:OAuth2 资源服务器认证,和 API Key 认证。

限制要先说清楚:只兼容 WebMVC 服务器,WebFlux 不支持;SSE 传输不支持,要用 Streamable-HTTP 或 Stateless;token 只支持 JWT,不透明 token 不支持。

OAuth2 配置用 Spring Security 标准 API,加上框架提供的 McpServerOAuth2Configurer:

@Configuration
@EnableWebSecurity
class McpServerConfiguration {

    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuerUrl;

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .with(McpServerOAuth2Configurer.mcpServerOAuth2(),
                (mcpAuthorization) -> mcpAuthorization.authorizationServer(issuerUrl))
            .build();
    }
}

这段配置让每个请求都要带有效 token。如果只想保护工具调用,可以放行 /mcp 路径,再用 @PreAuthorize(“isAuthenticated()”) 标注工具方法。方法里还能用 SecurityContextHolder 拿当前用户。

API Key 认证要自己实现 ApiKeyEntityRepository 存 key。框架附带的 InMemoryApiKeyEntityRepository 用 bcrypt 存 key,计算开销大,只适合演示,生产环境必须自己实现。

31.3 客户端安全

客户端安全模块只支持 McpSyncClient,提供三种 OAuth2 流程。

Authorization Code(授权码)适合每个请求都在用户上下文里发生。Client Credentials(客户端凭证)适合机器对机器,没有人在场。Hybrid(混合)两者结合:启动时的工具发现用客户端凭证,工具调用用授权码。用 Spring Boot 属性配置客户端时推荐 Hybrid,因为工具发现发生在启动阶段,没有用户在场。

HttpClient 版客户端配置一个定制器 Bean 加对应的请求定制器:

@Bean
McpCustomizer<McpClient.SyncSpec> syncClientCustomizer() {
    return (name, syncSpec) ->
        syncSpec.transportContextProvider(new AuthenticationMcpTransportContextProvider());
}

@Bean
McpSyncHttpClientRequestCustomizer requestCustomizer(OAuth2AuthorizedClientManager clientManager) {
    return new OAuth2AuthorizationCodeSyncHttpRequestCustomizer(clientManager, "authserver");
}

三种流程对应三个定制器类,WebClient 版则对应三个 ExchangeFilterFunction。

还有个已知问题:Spring AI 自动配置会在应用启动时就初始化客户端,用户级授权流程会因此出问题。官方文档给了两种绕法:发布一个空的 ToolCallbackResolver Bean,或者改为编程式配置客户端。这块内容复杂,真要接安全,直接读官方文档原文。

31.4 注解总览

MCP Annotations 模块用注解声明式地开发 MCP 能力,替代手写大量规范对象。所有 MCP Boot Starter 都自带 spring-ai-mcp-annotations,不需要额外依赖。注解扫描默认开启,用 spring.ai.mcp.server.annotation-scanner.enabled 或 client 对应属性控制。

服务端注解:@McpTool、@McpResource、@McpPrompt、@McpComplete。 客户端注解:@McpLogging、@McpSampling、@McpElicitation、@McpProgress、@McpToolListChanged、@McpResourceListChanged、@McpPromptListChanged。

31.5 服务端注解

@McpTool 把方法声明成工具,参数自动生成 JSON Schema:

@Component
public class CalculatorTools {

    @McpTool(name = "add", description = "Add two numbers together")
    public int add(
            @McpToolParam(description = "First number", required = true) int a,
            @McpToolParam(description = "Second number", required = true) int b) {
        return a + b;
    }
}

name 不写就用方法名。description 要写清楚,模型靠它决定何时调用。注解还支持 title、generateOutputSchema、annotations 等属性。其中 annotations 提供 readOnlyHint、destructiveHint、idempotentHint 这类客户端提示,模型和 UI 会参考它们判断调用风险。

@McpResource 用 URI 模板暴露资源,模板变量直接变成方法参数:

@McpResource(uri = "config://{key}", name = "Configuration")
public String getConfig(String key) {
    return configData.get(key);
}

@McpPrompt 提供提示词模板,返回 GetPromptResult,参数用 @McpArg 标注。@McpComplete 给提示词参数或资源 URI 提供自动补全,用 prompt 或 uri 属性指定目标,两者不能同时用。

想给工具声明附加元数据,用 metaProvider 属性。实现 MetaProvider 接口返回一个 Map,内容会写进声明的 _meta 字段,客户端能看到。不指定时,框架使用默认的 DefaultMetaProvider。

31.6 客户端注解

客户端注解处理服务器发来的通知和请求。关键约束:所有客户端注解必须带 clients 参数,值要匹配配置里的连接名。

@Component
public class McpClientHandlers {

    @McpLogging(clients = "weather-server")
    public void handleLoggingMessage(LoggingMessageNotification notification) {
        System.out.println("Received log: " + notification.level() + " - " + notification.data());
    }

    @McpProgress(clients = "weather-server")
    public void handleProgressNotification(ProgressNotification notification) {
        System.out.println("Progress: " + notification.progress());
    }
}

@McpLogging 收日志,@McpProgress 收进度,@McpToolListChanged、@McpResourceListChanged、@McpPromptListChanged 收三类列表变更通知。@McpSampling 处理服务器的采样请求:服务器没有 LLM API Key,借客户端的模型能力生成内容。@McpElicitation 处理服务器向用户追问信息的请求。都支持同步和 Mono 异步两种写法。

方法参数可以写整个通知对象,也可以拆成单个参数。比如 @McpProgress 的方法参数写 progressToken、progress、total、message,框架会逐个注入。拆开写适合只需要其中几个字段的场景。

31.7 特殊参数

注解方法还能注入框架自动填充的特殊参数。它们不参与 JSON Schema 生成,客户端看不到。

McpMeta 提供请求的 _meta 元数据,比如用户 ID、角色,用 get(key) 取值。@McpProgressToken 接收进度令牌,用于长任务进度上报。没有令牌时注入 null,记得判空。

McpSyncRequestContext / McpAsyncRequestContext 是推荐用的统一上下文。能取原始请求、会话 ID、客户端信息,还能发日志、进度、ping。检测到能力可用时,可以做 sampling、elicitation、roots 访问。

McpTransportContext 是轻量上下文,给 Stateless 服务器用,只能碰传输层信息。CallToolRequest 是完整工具请求,适合参数不确定的动态工具。

@McpTool(name = "context-tool", description = "Tool with context")
public String contextTool(
        McpSyncRequestContext context,
        @McpToolParam(description = "Input", required = true) String input) {
    context.info("Processing: " + input);
    context.progress(50);
    return "Processed: " + input;
}
Note

框架按服务器类型过滤方法:SYNC 服务器只注册同步方法,ASYNC 只注册响应式方法;Stateless 服务器会跳过(忽略)带 McpSyncRequestContext 的方法。写代码时让方法风格和服务器类型保持一致。

过滤规则可以汇总成一张表:

服务器类型接受的方法被过滤的方法
Sync Stateful非响应式返回 + 双向上下文Mono/Flux 返回
Async StatefulMono/Flux 返回 + 双向上下文非响应式返回
Sync Stateless非响应式返回 + 无双向上下文响应式返回或双向上下文参数
Async StatelessMono/Flux 返回 + 无双向上下文非响应式返回或双向上下文参数

实践建议:同步方法和异步方法分开放类,别混在同一个类里;启动时留意日志,确认方法都注册上了。

31.8 动态工具发现

工具多了,全部塞进上下文既费 token 又降低模型选工具的准确率。多个 MCP 服务器接进来,工具轻松超过 50 个,模型面对 30+ 相似名字时选择质量明显下降。

Tool Search Tool 模式解决这个问题:初始只给模型一个搜索工具,模型需要能力时先搜,再加载命中的工具定义。Spring AI 的实现基于 Recursive Advisor,实测省 34%-64% 的 token。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-tool-search-advisor</artifactId>
</dependency>
spring.ai.chat.client.tool-search-advisor.enabled=true

索引支持三种搜索策略:语义搜索用 VectorToolIndex,适合自然语言模糊匹配;关键词用 LuceneToolIndex,适合精确匹配;正则用 RegexToolIndex,适合按名字模式匹配。工具超过 20 个,或者接了多个 MCP 服务器,就值得上。

31.9 小结

MCP 安全官方仍是 WIP,生产使用要自己核实最新状态。注解开发是日常主力:服务端 @McpTool 一行声明工具,客户端注解处理通知,特殊参数注入上下文。工具多了上动态发现,省 token 又提准确率。