Spring Boot AI MCP服务器
生产准备就绪 模型上下文协议(MCP)服务器 采用Spring Boot构建,具有反应式架构、带滑动过期的JWT身份验证和完整的Docker容器化,可实现无缝部署。
特性
核心能力
- MCP服务器发送事件(SSE) 实时人工智能模型通信的传输
- GitHub API集成 使用反应式WebClient进行非阻塞拉取请求管理
- 高级安全:
- 双层认证(API密钥+JWT) - 滑动窗口令牌刷新用于连续会话 - 无状态设计,支持水平扩展
- 反应式体系结构:基于Spring WebFlux构建,用于高性能、非阻塞操作
- 生产监控:带有健康检查和指标的执行器端点
Docker部署
- 完全码头化:使用Docker Compose进行单命令部署
- 多阶段构建:通过分离的构建和运行时环境优化了图像大小
- 基于环境的配置:通过以下方式进行安全的凭据管理
.env文件 - 零停机:自动重启策略和优雅的关机处理
- 便携的:在开发、暂存和生产环境中一致运行
开发者体验
- 专业测井:使用性能指标进行结构化请求/响应跟踪
- 错误处理:具有优雅降级的全面错误恢复
- 热重新加载:即时代码更改的开发模式(非Docker)
- 整洁架构:将关注点与服务层、控制器层和配置层分离
先决条件
- Docker&Docker编写 (推荐)
- Docker引擎20.10+ - Docker Compose 2.0+
- 或用于当地发展:
- Java 21+ - Maven 3.9+
快速开始
选项1:Docker部署(推荐)
- 克隆仓库
git clone https://github.com/yourusername/spring_boot_ai_mcp_server.git
cd spring_boot_ai_mcp_server- 配置环境变量
cp .env.example .env
# Edit .env with your credentials
nano .env- 使用Docker Compose构建和运行
docker-compose up -d --build- 验证部署
docker-compose logs -f
curl http://localhost:8088/actuator/health就是这样! 您的MCP服务器正在运行 http://localhost:8088
方案2:地方发展
- 设置环境变量
export GITHUB_API_BEARER_TOKEN=your_github_token
export MCP_SERVER_SHARED_API_KEY=your_api_key
export MCP_AUTH_JWT_SECRET=your_jwt_secret_min_32_chars- 构建并运行
mvn clean install
mvn spring-boot:run配置
环境变量
创建一个 .env 项目根目录中的文件:
# GitHub API Configuration
GITHUB_API_BEARER_TOKEN=ghp_your_github_personal_access_token
# MCP Server Authentication
MCP_SERVER_SHARED_API_KEY=your-secure-api-key
MCP_AUTH_JWT_SECRET=your-jwt-secret-at-least-32-characters-long️ 安全说明:从不承诺.env版本控制。使用.env.example对于模板。
应用程序属性
关键配置 application.properties:
# Server
server.port=8088
# MCP Server
spring.ai.mcp.server.enabled=true
spring.ai.mcp.server.transport=sse
# GitHub Repository
github.owner=your-github-username
github.repo=your-repository-name
# JWT Configuration
mcp.auth.jwt-ttl-seconds=3600
mcp.auth.refresh-window-seconds=300身份验证体系结构
双层安全模型
此MCP服务器实现了 纵深防御 结合API密钥和JWT令牌认证的认证策略:
┌─────────────────────────────────────────────────────────────────┐
│ Authentication Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Initial Authentication (API Key) │
│ Client → POST /mcp/auth/token │
│ Header: X-API-KEY: shared-secret │
│ ↓ │
│ Server validates API key │
│ ↓ │
│ Server generates JWT token │
│ ↓ │
│ Response: { "accessToken": "eyJ..." } │
│ │
│ 2. Subsequent Requests (JWT) │
│ Client → POST /mcp/tools/call │
│ Header: Authorization: Bearer │
│ ↓ │
│ Server validates JWT signature & expiration │
│ ↓ │
│ Server processes request │
│ ↓ │
│ Server generates NEW JWT (sliding window) │
│ ↓ │
│ Response: Data + Header: X-Refresh-Token: │
│ │
│ 3. Token Refresh (Automatic) │
│ Client stores new token from X-Refresh-Token header │
│ Next request uses the refreshed token │
│ Active sessions never expire! │
│ │
└─────────────────────────────────────────────────────────────────┘为什么选择双层身份验证?
| 层次 | 目的 | 好处 |
|---|---|---|
| API密钥 | 初始身份验证 | 简单、可撤销、跨团队共享 |
| JWT代币 | 按请求授权 | 无状态、可扩展、自动过期 |
滑动窗口令牌刷新
问题:固定过期令牌需要重新身份验证,从而中断用户体验。
解决方案:滑动窗口刷新使活动会话无限期保持活动状态。
它是如何工作的:
- JWT的有效期为1小时(可配置)
- 刷新窗口(最后5分钟)内的每个有效请求都会获得一个新令牌
- 客户端自动将新令牌用于后续请求
- 非活动会话在1小时后自然过期
- 活动会话无限期继续,无需重新身份验证
配置:
mcp.auth.jwt-ttl-seconds=3600 # Token lifetime: 1 hour
mcp.auth.refresh-window-seconds=300 # Refresh if " \
-H "Content-Type: application/json" \
-d '{
"name": "getAllPullRequests",
"arguments": {"state": "open"}
}'答复:
HTTP/1.1 200 OK
X-Refresh-Token: refershedToken... ← New token!
{
"status": "success",
"result": [...]
}3.自动令牌刷新
服务器在 X-Refresh-Token 刷新窗口内每个成功请求的标头。活动会话永远不会过期。
4.令牌到期处理
如果令牌过期(在1小时不活动后),请重新进行身份验证:
# Token expired (401 Unauthorized)
curl http://localhost:8088/mcp/tools/call \
-H "Authorization: Bearer "
# Response:
{
"error": "JWT token expired",
"status": 401
}
# Re-authenticate
curl -X POST http://localhost:8088/mcp/auth/token \
-H "X-API-KEY: your-api-key"API终点
健康与监测
GET /actuator/health # Health check
GET /actuator/info # Application info
GET /actuator/metrics # Performance metrics认证
POST /mcp/auth/token # Obtain JWT token
Header: X-API-KEY: MCP工具
POST /mcp/tools/call # Execute MCP tools
Header: Authorization: Bearer
Body: {
"name": "getAllPullRequests",
"arguments": {"state": "open|closed|all"}
}SSE流
GET /mcp/sse # Server-Sent Events stream
Header: Authorization: Bearer 优点:
- 较小的图像:运行时映像~270MB(使用构建工具时为500MB+)
- 更快的部署:优化了层缓存
- 安全:生产映像中没有构建工具
- 可重复性:跨环境的一致构建
Docker编写管理
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Rebuild after code changes
docker-compose up -d --build
# View running containers
docker-compose ps性能优化
- 响应式WebFlux:高并发的非阻塞I/O
- 连接池:高效的HTTP客户端连接重用
- 超时配置:防止资源耗尽
- Docker层缓存:3分钟→ 30秒重建时间
- Docker先生:655 MB→ 5MB构建上下文(减少100倍)
测量性能:
- 服务器处理时间:500-800ms
- GitHub API延迟:400-600ms
- 总响应时间:\<2秒(p95)
监控和记录
结构化日志记录
10:28:01.911 INFO ▶ REQUEST: tool=getAllPullRequests, args={state=open}
10:28:02.450 INFO → GitHub API: Fetching PRs state=open
10:28:02.996 INFO ← GitHub API: Retrieved 24 PRs, api=546ms, total=546ms
10:28:02.996 INFO ✓ SUCCESS: tool=getAllPullRequests, items=24, duration=1085ms健康检查
# Application health
curl http://localhost:8088/actuator/health
# Detailed metrics
curl http://localhost:8088/actuator/metrics/http.server.requests部署场景
发展
docker-compose up --build暂存
docker-compose -f docker-compose.yml -f docker-compose.staging.yml up -d生产
# With custom environment
docker-compose -f docker-compose.prod.yml up -d
# Or with Kubernetes
kubectl apply -f k8s/deployment.yml安全最佳实践
- 基于环境的秘密(从未硬编码)
.env排除在版本控制之外- 带滑动过期窗口的JWT
- API密钥认证层
- HTTPS就绪(配置反向代理)
- 已启用安全标头
- 在所有端点上进行输入验证
技术栈
| 技术 | 目的 |
|---|---|
| 弹簧靴3.4.2 | 应用框架 |
| Spring WebFlux | 反应式web堆栈 |
| Spring Security | 身份验证和授权 |
| JWT(jjwt 0.11.5) | 基于令牌的身份验证 |
| 春季AI MCP | 模型上下文协议集成 |
| 网络客户端 | 非阻塞HTTP客户端 |
| 执行器 | 生产监控 |
| 码头工人 | 集装箱化 |
| 梅文 | 构建自动化 |
许可证
此项目根据MIT许可证获得许可-请参阅 许可证 文件以获取详细信息。
故障排除
Docker构建失败
问题: error: release version 21 not supported
解决方案: 确保Dockerfile使用Java 21:
FROM maven:3.9-eclipse-temurin-21 AS build
FROM eclipse-temurin:21-jre端口已在使用中
问题: Bind for 0.0.0.0:8088 failed: port is already allocated
解决方案: 更改端口 docker-compose.yml:
ports:
- "8089:8088" # Change external port环境变量未加载
问题: 应用程序找不到环境变量
解决方案: 验证 .env 文件存在并重新启动:
docker-compose down
docker-compose up -d______________________________________________________________________
使用Spring Boot和Docker制作
