DDK MCP Starter
把应用用例暴露为 MCP(Model Context Protocol) 工具,AI 代理可以像浏览器调用 REST 接口一样调用业务能力。MCP server 与
@McpTool的发现来自 Spring AI 2.0,本 starter 只补 DDD 服务需要的约定。
text
AI 代理 ──MCP──► adapter.mcp.*Tools ──► 应用服务 ──► 领域
│
└─ DDK:参数校验 · 业务异常转错误码 · 隐藏内部细节 · 审计日志能做什么
| 能力 | 说明 |
|---|---|
| 默认 streamable HTTP | Spring AI 未配置 spring.ai.mcp.server.protocol 时启用已被 MCP 规范弃用的 SSE 传输;DDK 以最低优先级设为 STREAMABLE,任何配置源里显式设置都会覆盖 |
| 参数校验 | @McpTool 参数上的 Bean Validation 注解在工具执行前校验,不需要在类上标 @Validated。失败返回 VALIDATION_ERROR: username: size must be between 4 and 20 |
| 错误码 | BusinessException、SystemException 转为以错误码开头的工具错误,如 USERNAME_TAKEN: 用户名已被占用:alice,模型可以据此判断是否换个参数重试 |
| 不泄露内部细节 | 其他异常统一返回 SYSTEM_ERROR: 服务器内部错误,原始消息与堆栈只写日志 |
| 审计日志 | 每次调用一行:MCP tool [get_user] -> USER_NOT_FOUND in 3 ms。出于隐私考虑不记录参数值 |
引入方式
xml
<dependency>
<groupId>com.ddk</groupId>
<artifactId>ddk-mcp-starter</artifactId>
<version>${ddk.version}</version>
</dependency>工具类放在适配层,像控制器一样只调用应用服务:
java
@Component
@RequiredArgsConstructor
public class UserMcpTools {
private final UserService userService;
@McpTool(name = "get_user", description = "Get a user by ID. The phone number is masked.")
public UserResponse get(@McpToolParam(description = "User ID") @Positive long id) {
return userService.get(id);
}
}启动后端点是 /mcp。在 Claude Code 里接入:
bash
claude mcp add --transport http my-service http://localhost:8080/mcp配置项
| 配置项 | 默认值 | 说明 |
|---|---|---|
ddk.mcp.enabled | true | 是否为 @McpTool 方法接入上述调用拦截 |
ddk.mcp.validation | true | 是否校验工具参数 |
ddk.mcp.audit-log | true | 是否每次调用输出一行审计日志 |
spring.ai.mcp.server.* | Spring AI | 服务名、版本、端点、协议等仍由 Spring AI 配置 |
实现要点
- 拦截怎么生效:DDK 注册一个实现
Ordered的BeanPostProcessor,为含@McpTool方法的 Bean 创建 CGLIB 代理。Spring AI 的注解扫描器没有实现Ordered,排在后面,登记到 MCP server 的因此是代理对象;它按目标类上的Method反射调用,只有子类代理才能让这次调用经过拦截。 - 工具错误不带 cause:Spring AI 生成错误消息时会追溯异常链的根因,带上原始异常等于把它的消息原样交给模型。
- 约束写在接口上:工具类实现接口时,Bean Validation 规范不允许在重写方法上重新声明参数约束,约束要写在接口方法上。
架构守卫
CommonArchRules.MCP_TOOLS_MUST_RESIDE_IN_ADAPTER 要求 @McpTool 方法声明在 ..adapter.. 包里。结合分层规则,工具只能经由应用服务访问领域:模型拿不到仓储,也绕不过应用服务里的事务与业务校验。规则按注解全限定名匹配,ddk-archguard-starter 不依赖 Spring AI。
示例
用户示例的 adapter.mcp.UserMcpTools 暴露了 register_user、get_user、disable_user。UserMcpToolsTest 启动真实端口,通过 MCP 客户端验证工具列表、注册到禁用的完整流程、领域错误码与参数校验。
不适用的场景 / 已知问题
- 没有鉴权。
/mcp与其他接口一样,用 Spring Security 保护。 - 只支持 Servlet(WebMVC),不支持 WebFlux。
- 不提供
ddk-ai-starter。ChatClient配置、结构化输出(.entity(...))、Token 用量指标(gen_ai_client_token_usage_total)Spring AI 2.0 都已内置,直接使用 Spring AI 即可。