5.1 KiB
xiaoqu-agent-service
面向 MCP 客户端(Kimi Code / Claude 等)的小趣业务数据服务:独立 Spring Boot 应用,只读查询现有三库(m0 权限库 / m1 商城库 / m2 业务库),以 MCP(Streamable HTTP)形式对外暴露工具。
设计方案见 ../xiaoqu-franchisee/doc/agent-mcp-service-design.md。当前为 P1 骨架:工程初始化、版本组合验证、三数据源连通、codegen 跑通、demo 工具经 MCP 调通。鉴权 / 权限引擎 / 管理后台为 P2+,未实现。
技术栈与已验证版本组合
| 组件 | 版本 |
|---|---|
| JDK | 17(Temurin 17.0.20.1) |
| Spring Boot | 3.5.16 |
| Spring AI(MCP server webmvc) | 1.1.8 |
| MyBatis-Plus | 3.5.12(mybatis-plus-spring-boot3-starter) |
| MySQL 驱动 | mysql-connector-j(Boot 管理) |
| Redis | spring-boot-starter-data-redis(db5) |
⚠️ 版本组合说明:Spring Boot 3.5.x + Spring AI 1.0.0 的 streamable 传输存在 NPE(spring-projects/spring-ai#6274),本工程选用已修复的 Spring AI 1.1.8,2026-09-03 实测 STREAMABLE 握手(initialize → tools/list → tools/call)通过。
工程结构
xiaoqu-agent-service/
├── mvnw / .mvn/wrapper/ # Maven Wrapper(本机无全局 mvn)
├── pom.xml
├── src/main/java/me/iiv/agent/
│ ├── AgentServiceApplication.java
│ ├── config/ # M0/M1/M2DataSourceConfig(独立 SqlSessionFactory + MapperScan)、McpToolConfig
│ ├── mcp/tool/ # @Tool 工具(SysTools: sys.ping;AgentTools: agent.count)
│ ├── security/ permission/ admin/ common/ # P2+ 占位包
│ ├── entity/m0、m2 mapper/m0、m1、m2 # codegen 生成物(提交进仓库)
├── src/main/resources/
│ ├── application.yml # MCP server: protocol=STREAMABLE, 端点 /mcp;默认 dev profile
│ └── application-dev.yml # 三数据源 + Redis,密码用环境变量占位符带默认值
└── src/test/java/me/iiv/agent/codegen/CodeGenerator.java # run-once 代码生成器
数据源分包约定:entity/m0|m1|m2 与 mapper/m0|m1|m2 一一对应各自的 SqlSessionFactory(@MapperScan + sqlSessionFactoryRef)。
启动
./mvnw clean package -DskipTests
java -jar target/xiaoqu-agent-service.jar
# 或
./mvnw spring-boot:run
- 默认
spring.profiles.active=dev,端口 8088,MCP 端点http://localhost:8088/mcp。 - 数据库/Redis 密码默认值仅供本地 dev,可用环境变量覆盖:
M0_DB_PASSWORD/M1_DB_PASSWORD/M2_DB_PASSWORD/REDIS_PASSWORD。
MCP 工具
| 工具名 | 说明 |
|---|---|
sys.ping |
服务自检:服务名、版本、当前时间、Redis PING |
agent.count |
查 m0 库 agent 表 soft_delete=0 总数(真实查库) |
工具名使用点号分隔(MCP 规范允许 [a-zA-Z0-9._-],实测 Spring AI 1.1.8 与握手流程均正常)。若未来接入的客户端不接受点号,改为下划线即可。
curl 验证(Streamable HTTP 握手)
# 1) initialize(从响应头取 Mcp-Session-Id)
curl -i -X POST http://localhost:8088/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
# 2) notifications/initialized(带 session id)
curl -X POST http://localhost:8088/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'Mcp-Session-Id: <上一步的session-id>' \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
# 3) tools/list
curl -X POST http://localhost:8088/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# 4) tools/call
curl -X POST http://localhost:8088/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"agent.count","arguments":{}}}'
响应为 SSE 帧(event: message / data: {...})。
codegen(run-once)
表白名单:m0 user, agent, authority, properyt, agent_manage_district_auth;m2 warehouse_agent_auth(注:物业表真实表名为老系统遗留拼写 properyt)。生成物落在 src/main/java 对应分包并提交进仓库。
# 生成(依赖已下载后执行;连 dev 库)
./mvnw -q dependency:build-classpath -Dmdep.includeScope=test -Dmdep.outputFile=target/cp.txt
javac -cp "$(cat target/cp.txt)" -d target/codegen-classes src/test/java/me/iiv/agent/codegen/CodeGenerator.java
java -cp "target/codegen-classes:$(cat target/cp.txt)" me.iiv.agent.codegen.CodeGenerator
重新生成前请先删除目标 entity/mapper 文件,避免覆盖人工改动。