MCP企业级开发进阶技巧
当你在本地调试MCP时,一切都很顺利。但真正推向生产环境时,肯定会有各种的问题:远程服务怎么做认证?网络断了如何自动恢复?不同用户能调用的工具不一样怎么办?这篇文章就来聊聊这些企业级开发中的进阶技巧。
认证鉴权:给你的MCP服务装上门禁系统
想象一下你公司的办公楼门禁系统。普通员工刷工卡只能进入自己所在楼层,管理层可以进入更多区域,而访客则需要在前台登记换取临时卡。MCP的认证鉴权机制也是类似的思路。
本地服务的"内部通道"
如果MCP Server和Client在同一台机器上(比如使用Stdio模式),这就相当于在公司内部走动,不需要额外的身份验证。此时认证方式通常是通过环境变量传递敏感信息:
@Configuration
public class LocalMcpConfig {
@Bean
public McpSyncClient localMcpClient() {
// 本地模式下,通过环境变量传递API密钥
// 这些密钥用于Server内部调用第三方服务
return McpClient.sync(
StdioClientTransport.builder()
.command("java")
.args("-jar", "hr-assistant-server.jar")
.environment(Map.of(
"DINGTALK_APP_KEY", System.getenv("DINGTALK_APP_KEY"),
"DINGTALK_APP_SECRET", System.getenv("DINGTALK_APP_SECRET"),
"DATABASE_PASSWORD", System.getenv("DATABASE_PASSWORD")
))
.build()
).build();
}
}
这种方式的好处是敏感信息不会在网络上传输,安全性有保障。密钥从Host环境传递给Server进程,整个过程都在本地内存中完成。
本地模式的安全最佳实践
Stdio 模式下,通过环境变量向子进程传递敏感信息(API Key、数据库密码)是最安全的做法。密钥不会出现在配置文件里,也不会在网络上传输,整个生命周期在本机内存中完成。
远程服务的"访客登记"
当MCP Server部署在远程服务器上时,情况就不同了。这时候每次请求都需要携带身份凭证,就像访客每次进入都要出示临时卡一样。
最常用的方式是Bearer Token认证:
@Configuration
public class RemoteMcpConfig {
@Value("${mcp.server.token}")
private String accessToken;
@Bean
public McpSyncClient remoteMcpClient() {
// 构建带认证头的HTTP客户端
HttpClient authenticatedClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
return McpClient.sync(
HttpClientSseClientTransport.builder()
.sseUrl("https://mcp.company.com/sse")
.httpClient(authenticatedClient)
.customizeRequest(builder -> {
// 每次请求都携带Token
builder.header("Authorization", "Bearer " + accessToken);
})
.build()
).build();
}
}
服务端的验证逻辑也需要配套实现:
@Component
public class McpAuthenticationFilter implements WebFilter {
@Value("${mcp.valid-tokens}")
private Set<String> validTokens;
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String authHeader = exchange.getRequest().getHeaders()
.getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
String token = authHeader.substring(7);
if (!validTokens.contains(token)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
// 可以把用户信息放入上下文,后续工具过滤会用到
return chain.filter(exchange)
.contextWrite(ctx -> ctx.put("userId", extractUserId(token)));
}
}
更复杂的场景:OAuth2集成
企业环境中可能需要与现有的身份认证系统集成,比如接入公司的统一认证平台:
@Service
public class OAuth2McpAuthService {
private final OAuth2AuthorizedClientManager clientManager;
public String obtainAccessToken() {
OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest
.withClientRegistrationId("mcp-server")
.principal("system")
.build();
OAuth2AuthorizedClient client = clientManager.authorize(request);
return client.getAccessToken().getTokenValue();
}
}
付费内容提示
该文档的全部内容仅对「JavaUp项目实战&技术讲解」知识星球用户开放
加入星球后,你可以获得:
- 超级八股文:100万+字的全栈技术知识库,涵盖技术核心、数据库、中间件、分布式等深度剖析的讲解
- 讲解文档:超级AI智能体、黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的从0到1的详细文档
- 讲解视频:超级AI智能体、黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的核心业务详细讲解
- 1 对 1 解答:可以对我进行1对1的问题提问,而不仅仅只限于项目
- 针对性服务:有没理解的地方,文档或者视频还没有讲到可以提出,本人会补充
- 面试与简历指导:提供面试回答技巧,项目怎样写才能在简历中具有独特的亮点
- 中间件环境:对于项目中需要使用的中间件,可直接替换成我提供的云环境
- 面试后复盘:小伙伴去面试后,如果哪里被面试官问住了,可以再找我解答
- 远程的解决:如果在启动项目遇到问题,本人可以帮你远程解决
进入星球后,即可享受上述所有服务,保证不会再有其他隐藏费用。
