用SpringAI实现一个MCP Server,怎么接收客户端传递过来的env
我用cursor的settings配置了一个mcp.json,配置如下:
我的本地服务,使用SrpingAI的@Tool来注册工具,那么我这个工具怎么获取到cursor中配置的env参数PM-ID呢?
env是 stdio那种本地启动的,env就是修改你电脑的环境变量,所以sse方式,远程访问是无法获取到的
可以将环境参数设置到 version 版本字段中,这样就可以在服务端获取到你的env参数了。
stdio 直接代码 注入获取 getEnv 就行了
自定义HandlerInterceptor解析env并将其放到InheritableThreadLocal中,再讲其注册到WebMvcConfigurer的addInterceptors中;使用时从InheritableThreadLocal中获取
你但凡听一下徐庶老师我讲的 MCP鉴权你都不会问这个问题:https://www.bilibili.com/video/BV1ir55zQEsF/?spm_id_from=333.337.search-card.all.click
mcp server端直接 System.getenv("PM-ID")
你但凡听一下徐庶老师我讲的 MCP鉴权你都不会问这个问题:https://www.bilibili.com/video/BV1ir55zQEsF/?spm_id_from=333.337.search-card.all.click
mcp server端直接 System.getenv("PM-ID")
徐庶我知道,卖卖面试题可以,企业级开发就算了。
自定义HandlerInterceptor解析env并将其放到InheritableThreadLocal中,再讲其注册到WebMvcConfigurer的addInterceptors中;使用时从InheritableThreadLocal中获取
嗯,我的思路跟你一样,我自己重新封装了sse端点的处理逻辑,差不多是这么实现的,不过总觉得我碰到的这种问题(sse模式下获取客户端自定义参数的比如api_key ),spring AI 团队应该也能想到的,期待他们抓紧实现。
这个获取还是简单,如果/sse?key='***'
@Bean public RouterFunction<ServerResponse> mvcMcpRouterFunction(WebMvcSseServerTransportProvider transportProvider) { return transportProvider.getRouterFunction().filter(new HandlerFilterFunction<ServerResponse, ServerResponse>() { @Override public ServerResponse filter(ServerRequest request, HandlerFunction<ServerResponse> next) throws Exception { String path = request.path(); if ("/see".equals(path)) { Optional<String> key= request.param("key"); if (key.isPresent()) { if ("123456".equals(key.get())){ return next.handle(request); } } return ServerResponse.status(HttpStatus.FORBIDDEN).build(); } return next.handle(request); } }); }
或者说,自定义一个WebMvcSseServerTransportProvider重写里面的getRouterFunction()函数;
如何实现/sse?key='***'呢?怎么在Tool里接收到key的值?
如何实现/sse?key='***'呢?怎么在Tool里接收到key的值?
可以自定义bean
@Bean
public WebFluxStatelessServerTransport webFluxStatelessServerTransport(
ObjectProvider<ObjectMapper> objectMapperProvider, McpServerStreamableHttpProperties serverProperties) {
ObjectMapper objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new);
return WebFluxStatelessServerTransport.builder()
.jsonMapper(new JacksonMcpJsonMapper(objectMapper))
.messageEndpoint(serverProperties.getMcpEndpoint())
.contextExtractor(serverRequest -> {
// 从serverRequest提取header,path,query等参数
McpTransportContext,create(Map.of({自定义kv}))
})
.build();
}
定义Tool需要用函数式编程,不要用注解。
new McpStatelessServerFeatures.AsyncToolSpecification(
tool,
(transportContext, callToolRequest) -> {这里已经可以提取transportContext了}));
如何实现/sse?key='***'呢?怎么在Tool里接收到key的值?
可以自定义bean
@Bean public WebFluxStatelessServerTransport webFluxStatelessServerTransport( ObjectProvider<ObjectMapper> objectMapperProvider, McpServerStreamableHttpProperties serverProperties) { ObjectMapper objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new); return WebFluxStatelessServerTransport.builder() .jsonMapper(new JacksonMcpJsonMapper(objectMapper)) .messageEndpoint(serverProperties.getMcpEndpoint()) .contextExtractor(serverRequest -> { // 从serverRequest提取header,path,query等参数 McpTransportContext,create(Map.of({自定义kv})) }) .build(); }定义Tool需要用函数式编程,不要用注解。
new McpStatelessServerFeatures.AsyncToolSpecification( tool, (transportContext, callToolRequest) -> {这里已经可以提取transportContext了}));
同步可以用McpSyncRequestContext , 异步用McpAsyncRequestContext
@McpTool(name = "xxx", description = "xxx")
public String xxx(McpSyncRequestContext context, @McpToolParam String studentId) {
McpSyncServerExchange exchange = context.exchange();
McpTransportContext transportContext = exchange.transportContext();
return "";
}