使用说明
模拟电子商务MCP服务器
通用型 模拟MCP(模型上下文协议)服务器 建于 Java 21+Spring Boot 3.3.6+Spring AI 1.0.0-M6.
一个使用此服务器的AI聊天机器人可以为跨平台的用户提供服务 杂货、时尚、电子、美容和家居 类别,以及 外卖 (旋转风格的餐厅)。暴露 40+MCP工具 任何兼容MCP的AI客户端(Claude、GPT、Gemini等)都可以发现和调用。
目录
- 需求
- 建筑
- 代码结构
- 本地运行时--快速入门
- Web UI——数据浏览器
- 本地端点
- 28种电子商务MCP工具
- 餐厅和Swiggy刮刀工具
- 种子数据管道
- LLM产品数据生成
- 测试用例
- 在本地运行测试
- 生产部署
- 连接MCP客户端
- 状态 & 全部
需求
功能需求
- 暴露 28个MCP工具 通过HTTP/SSE实现AI聊天机器人集成
- 支持 5个产品类别:杂货、时尚、电子、美容、家居
- 完整的电子商务流程:搜索→ cart → 结账→ 支付→ 订单→ 装运→ 审查
- 通过电话号码+平台密码进行基于会话的身份验证
- 模拟数据生成——不需要真正的数据库种子;产品按需生成
- 支持门票和愿望清单管理
非功能性需求
- Java 21 最小
- 用于本地/dev的内存H2数据库;PostgreSQL用于生产
- 所有工具均以结构化JSON字符串进行响应
- 会话TTL:24小时
- 分页:默认10个项目,最多50个
- 异步生成产品以避免阻止搜索响应
先决条件
| 工具 | 版本 |
|---|---|
| Java(JDK) | 21+ |
| Maven | 3.8+ |
| Docker+Docker Compose | 任何最新版本(用于prod模式) |
建筑
┌─────────────────────────────────────────────────────────────┐
│ MCP Client │
│ (Claude Desktop / VS Code / Custom App) │
└─────────────────────┬───────────────────────────────────────┘
│ HTTP/SSE (MCP Protocol)
▼
┌─────────────────────────────────────────────────────────────┐
│ Spring Boot MCP Server :8080 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ MCP Tool Layer (12 Tool Classes, 28 Tools) │ │
│ │ ProductSearch · ProductDetail · Delivery · Auth │ │
│ │ Cart · Address · Payment · Order · Shipment │ │
│ │ Ticket · Review · Wishlist │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ ┌──────────────────────▼───────────────────────────────┐ │
│ │ Service Layer (12 Services) │ │
│ │ Auth · Product · Cart · Checkout · Order · Payment │ │
│ │ Address · Delivery · Review · Ticket · Wishlist │ │
│ │ MockDataGenerator │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ ┌──────────────────────▼───────────────────────────────┐ │
│ │ Repository Layer (16 Spring Data JPA Repos) │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ ┌──────────────────────▼───────────────────────────────┐ │
│ │ Database: H2 (dev/test) │ PostgreSQL (prod) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
数据流——端到端购物之旅
Login (phone) → sessionId
→ searchProducts / filterProducts
→ addToCart (sessionId)
→ checkout (cartId, sessionId)
→ selectAddress (checkoutId, addressId, sessionId)
→ initiatePayment (checkoutId, method, sessionId)
→ orderId created automatically
→ getOrderDetails / getShipments
→ submitProductReview / createTicket
关键设计决策
- 按需模拟数据 --产品是从搜索关键字+类别中确定地生成的;无需人工播种
- SSE运输 --工具通过服务器发送事件公开,以提供实时流媒体支持
- 内存中的H2 对于dev意味着零设置;模式在启动时创建,在退出时删除
- 异步生成 --当搜索没有返回结果时,将在后台异步生成8个产品
代码结构
src/
├── main/java/com/mock/ecom/mcpserver/
│ ├── MockEcomMcpServerApplication.java # Entry point (@EnableAsync)
│ ├── config/
│ │ ├── AppProperties.java # App config (session TTL, secret, pagination)
│ │ ├── AsyncConfig.java # Thread pool (5 core, 20 max, 100 queue)
│ │ └── McpToolsConfig.java # Registers all 12 tool classes with MCP
│ ├── entity/ # 16 JPA entities
│ │ ├── Customer, Session, Address
│ │ ├── Product, ProductAttribute
│ │ ├── Cart, CartItem, Checkout
│ │ ├── Order, OrderItem, Payment
│ │ ├── Shipment, Review
│ │ ├── Ticket, TicketComment, WishlistItem
│ ├── repository/ # 16 Spring Data JPA repositories
│ ├── service/ # 12 business services
│ │ ├── AuthService.java # Session create/validate, customer lookup
│ │ ├── ProductService.java # Search, filter, reviews, lazy generation
│ │ ├── MockDataGeneratorService.java # Deterministic mock data for 5 categories
│ │ ├── CartService.java # Add to cart, recalculate totals, checkout
│ │ ├── CheckoutService.java # Checkout lifecycle
│ │ ├── OrderService.java # Order creation and status transitions
│ │ ├── PaymentService.java # Payment initiation and status
│ │ ├── AddressService.java # Address CRUD
│ │ ├── DeliveryService.java # Delivery estimate by pincode
│ │ ├── ReviewService.java # Product and shipment reviews
│ │ ├── TicketService.java # Support tickets and comments
│ │ └── WishlistService.java # Wishlist add/view
│ └── tools/ # 12 MCP tool classes
│ ├── ProductSearchTools.java # Tools 1-4
│ ├── ProductDetailTools.java # Tools 5-6
│ ├── DeliveryTools.java # Tool 7
│ ├── AuthTools.java # Tool 8
│ ├── CartTools.java # Tools 9-10
│ ├── AddressTools.java # Tools 11-12
│ ├── PaymentTools.java # Tools 13-14
│ ├── OrderTools.java # Tools 15-19
│ ├── ShipmentTools.java # Tool 20
│ ├── TicketTools.java # Tools 21-24
│ ├── ReviewTools.java # Tools 25-26
│ ├── WishlistTools.java # Tools 27-28
│ └── ToolResponseHelper.java # JSON serialization utility
└── main/resources/
├── application.yml # Dev profile (H2, port 8080)
├── application-test.yml # Test profile (H2, separate DB)
└── application-prod.yml # Prod profile (PostgreSQL, env vars)
src/test/java/com/mock/ecom/mcpserver/
├── MockEcomMcpServerApplicationTests.java
└── integration/
├── EndToEndShoppingJourneyTest.java # Full 28-tool flow
├── AuthAndCartFlowTest.java # Tools 8-14
├── ProductToolsIntegrationTest.java # Tools 1-7
├── OrderManagementTest.java # Tools 15-20
├── TicketAndReviewTest.java # Tools 21-26
├── WishlistTest.java # Tools 27-28
└── MockDataGeneratorTest.java # Data generation logic
实体关系
Customer ──< Session
Customer ──< Address
Customer ──< Cart ──< CartItem >── Product
Customer ──< WishlistItem >── Product
Cart ──── Checkout ──── Order ──< OrderItem >── Product
Checkout ──< Payment
Order ──< Shipment ──< OrderItem
Order ──< Ticket ──< TicketComment
Shipment ──< Review (DELIVERY type)
Product ──< Review (PRODUCT type)
Product ──< ProductAttribute
枚举参考
| 实体 | 状态值 |
|---|---|
| 购物车 | ACTIVE, CHECKED_OUT, ABANDONED |
| 结账 | PENDING, ADDRESS_SELECTED, PAYMENT_INITIATED, COMPLETED, CANCELLED |
| 订购 | PLACED, PROCESSING, PARTIALLY_SHIPPED, SHIPPED, DELIVERED, CANCELLED, PARTIALLY_RETURNED, RETURNED |
| 订单项目 | ORDERED, PROCESSING, PACKED, SHIPPED, OUT_FOR_DELIVERY, DELIVERED, CANCELLED, RETURN_INITIATED, RETURNED, REFUNDED |
| 付款方式 | PENDING, PROCESSING, SUCCESS, FAILED, REFUND_INITIATED, REFUNDED, PARTIALLY_REFUNDED |
| 装运 | PENDING, PROCESSING, PACKED, SHIPPED, OUT_FOR_DELIVERY, DELIVERED, RETURNED, CANCELLED |
| 门票 | OPEN, IN_PROGRESS, AWAITING_CUSTOMER, RESOLVED, CLOSED |
| tickettype | DELIVERY_ISSUE, RETURN_REQUEST, PAYMENT_ISSUE, PRODUCT_QUALITY, CANCELLATION, OTHER |
| 地址类型 | HOME, WORK, OTHER |
| 审核类型 | PRODUCT, DELIVERY |
| 付款方式 | UPI, CARD, COD, NETBANKING, WALLET |
本地运行时--快速入门
选项1:一个命令脚本(推荐)
这 run-local.sh 脚本会自动查找空闲端口,更新配置,构建并启动服务器。
chmod +x run-local.sh
./run-local.sh
它的作用:
- 检查端口8080是否可用;如果没有,则查找下一个空闲端口(8081、8082、…)
- 更新
server.port在application.yml暂时 - 使用Maven构建(跳过速度测试)
- 启动Spring Boot应用程序
- 打印具有实际端口的所有端点URL
选项2:手动步骤
# 1. Build
mvn clean package -DskipTests
# 2. Run (H2 in-memory, dev profile)
mvn spring-boot:run
# Or run the JAR directly
java -jar target/mcp-server-1.0.0-SNAPSHOT.jar
选项3:自定义端口
java -jar target/mcp-server-1.0.0-SNAPSHOT.jar --server.port=9090
选项4:Docker+PostgreSQL
# Build and start all services
mvn clean package -DskipTests
docker-compose up --build
# Stop
docker-compose down
# Stop and remove data volume
docker-compose down -v
环境变量(Docker/生产环境)
| 变量 | 默认值 | 描述 |
|---|---|---|
SPRING_PROFILES_ACTIVE |
dev |
设置为 prod 对于PostgreSQL |
DB_URL |
jdbc:postgresql://localhost:5432/mockecomdb |
JDBC URL |
DB_USERNAME |
postgres |
数据库用户名 |
DB_PASSWORD |
postgres |
数据库密码 |
SERVER_PORT |
8080 |
HTTP侦听端口 |
ANTHROPIC_API_KEY |
(空) | Anthropic API密钥-在设置时启用LLM产品生成 |
Web UI——数据浏览器
React单页应用程序被捆绑到JAR中,并在根URL处自动提供服务。它允许您使用实时的分层过滤器直观地浏览所有抓取和生成的数据。
访问UI
启动服务器(请参阅 本地运行时),然后打开:
http://localhost:8080
不需要额外的设置——预构建的UI已经包含在 src/main/resources/static/ 由Spring Boot供应。
页面
| 页面 | URL | 描述 |
|---|---|---|
| 主页/仪表板 | http://localhost:8080/#/ |
实时统计数据(城市、餐厅、菜单项)、进度条、快速导航 |
| 餐厅探索者 | http://localhost:8080/#/restaurants |
使用分层过滤器和菜单查看器浏览所有餐厅 |
| 产品浏览器 | http://localhost:8080/#/products |
按类别、品牌、子类别浏览模拟生成的产品 |
餐厅资源管理器功能
- 城市过滤器 (左侧边栏)——列出了每个有餐馆的城市,并附有计数徽章。单击以缩小结果范围。
- 美食过滤器 --根据所选城市的餐厅数据自动填充。单击一个或多个菜肴进行筛选。
- 纯素食开关 --仅显示素食餐厅。
- 搜索栏 --按餐厅名称进行反发音搜索。
- 菜单项搜索模式 --切换到在所选城市的所有餐厅中搜索特定菜肴(例如“biryani”、“dosa”)。
- 餐厅卡 --评级徽章、美食标签、双人价格、配送时间、折扣优惠、关闭/打开指示器。
- 餐厅详图面板 --从卡片右侧滑入,单击:
- 完整信息:评级、评级计数、交货时间、成本、城市、折扣
- 按类别分组的完整菜单,带有可折叠的部分
- 类别选项卡可跳转到Starters/Biryani/Desserts等。
- 每项:蔬菜/非蔬菜指标,⭐ 畅销徽章、价格、缺货标签
产品浏览器功能
- 类别筛选器 (左侧边栏)--电子、时尚、杂货、美容、家居。
- 子类别筛选器 -从API为当前搜索/类别动态加载。
- 品牌过滤器 --动态加载产品计数的品牌。
- 搜索栏 --在产品名称和描述之间进行取消发音的全文搜索。
- 产品卡片 --品牌、标题、星级、价格(带有原始MRP删除线)、折扣%徽章。
- 产品详情面板 --从卡片右侧滑入,单击:
- 完整描述,类别面包屑,价格优惠
- 规格表(所有产品属性)
- 客户评论(可扩展,分页)
构建/重建UI
已建输出(src/main/resources/static/)已提交,因此应用程序可以开箱即用。如果在中修改任何UI源 ui/src/,运行前重建:
先决条件: Node.js 18+和npm。
# Install dependencies (first time only)
cd ui
npm install
# Build — outputs to src/main/resources/static/
npm run build
# Then rebuild the JAR so Spring Boot picks up the new assets
cd ..
mvn clean package -DskipTests
java -jar target/mcp-server-1.0.0-SNAPSHOT.jar
然后可以在以下位置访问UI http://localhost:8080.
热重载UI开发
要在不每次重建JAR的情况下迭代UI,请在Spring Boot服务器旁边运行Vite-dev服务器:
# Terminal 1 — start the backend
java -jar target/mcp-server-1.0.0-SNAPSHOT.jar
# Terminal 2 — start the Vite dev server
cd ui
npm run dev
打开 http://localhost:5173 在您的浏览器中。Vite-dev服务器代理所有 /api 请求 http://localhost:8080,因此UI与实时后端通信。更改为 ui/src/ 通过热模块更换立即反映出来。
开发完成后,重建并提交:
cd ui && npm run build
cd ..
git add src/main/resources/static/
git commit -m "chore: update UI build"
UI技术栈
| 工具 | 版本 | 目的 |
|---|---|---|
| React | 18 | 用户界面框架 |
| TypeScript | 5 | 类型安全 |
| Vite | 5 | 构建工具+开发服务器 |
| 顺风CSS | 3 | 实用优先样式 |
| TanStack查询 | 5 | 数据提取、缓存、自动刷新 |
| Axios | 1 | HTTP客户端 |
| React Router | 6 | 客户端路由(HashRouter) |
| Lucide React | -- | 图标 |
REST API端点(由UI使用)
以下所有端点 /api/v1/ 也可直接使用(curl、Postman、其他客户端)。
| 方法 | 端点 | 参数 | 描述 |
|---|---|---|---|
| 得到 | /api/v1/stats |
-- | 总计数(城市、餐馆、菜单项) |
| 得到 | /api/v1/cities |
-- | 所有拥有餐厅数量和刮擦状态的城市 |
| 得到 | /api/v1/cuisines |
cityName (可选) |
一个城市(或所有城市)的独特美食列表 |
| 得到 | /api/v1/restaurants |
cityName, cuisine, name, isPureVeg, page, size |
分页餐厅搜索 |
| 得到 | /api/v1/restaurants/{swiggyId} |
-- | Swiggy ID的单餐厅 |
| 得到 | /api/v1/restaurants/{swiggyId}/menu |
-- | 按类别分组的完整菜单 |
| 得到 | /api/v1/menu-items |
q (必填), cityName, page, size |
在所有餐厅按名称搜索菜肴 |
| 得到 | /api/v1/products |
q, category, subCategory, brand, page, size |
分页产品搜索 |
| 得到 | /api/v1/products/filters |
q |
查询的可用类别、子类别、品牌 |
| 得到 | /api/v1/products/{productId} |
-- | 包含属性的完整产品详细信息 |
| 得到 | /api/v1/products/{productId}/reviews |
page, size |
分页的产品评论 |
| 得到 | /api/v1/scraper/status |
-- | 刮板运行状态+计数 |
curl调用示例:
# All cities with restaurants
curl http://localhost:8080/api/v1/cities
# Restaurants in Bangalore
curl "http://localhost:8080/api/v1/restaurants?cityName=Bangalore"
# Veg restaurants in Mumbai
curl "http://localhost:8080/api/v1/restaurants?cityName=Mumbai&isPureVeg=true"
# Cuisines available in Hyderabad
curl "http://localhost:8080/api/v1/cuisines?cityName=Hyderabad"
# Full menu for Paradise Biryani
curl "http://localhost:8080/api/v1/restaurants/400001/menu"
# Search for "biryani" across all restaurants
curl "http://localhost:8080/api/v1/menu-items?q=biryani"
# Search for "biryani" in Bangalore only
curl "http://localhost:8080/api/v1/menu-items?q=biryani&cityName=Bangalore"
# Electronics products
curl "http://localhost:8080/api/v1/products?category=Electronics&size=5"
# Laptop products
curl "http://localhost:8080/api/v1/products?q=laptop"
本地端点
所有端点均已打开 http://localhost:<PORT> (默认值 8080).
| 端点 | 描述 |
|---|---|
GET / |
网页用户界面 --React数据浏览器(餐厅、产品、scraper仪表板) |
GET /api/v1/** |
REST API --由UI使用;也可直接卷曲/邮递员使用 |
GET /sse |
MCP SSE端点 --在此处连接您的MCP客户端 |
POST /mcp/message |
MCP消息端点(由SSE传输内部使用) |
GET /actuator/health |
健康检查-退货 {"status":"UP"} |
GET /actuator/info |
申请信息 |
GET /actuator/metrics |
指标列表 |
GET /actuator/metrics/{name} |
具体度量值 |
GET /h2-console |
H2数据库浏览器 (仅限DEV,用户名:SA,无密码) |
GET /swagger-ui.html |
Swagger UI-交互式API文档 (要求 -Pswagger) |
GET /v3/api-docs |
OpenAPI 3.0 JSON规范 (要求 -Pswagger) |
API 文档
| 资源 | 位置 | 备注 |
|---|---|---|
| Swagger 用户界面 | http://localhost:8080/swagger-ui.html |
实时交互式文档,使用构建 mvn package -Pswagger |
| OpenAPI JSON | http://localhost:8080/v3/api-docs |
机器可读规格,要求 -Pswagger |
| OpenAPI YAML | docs/openapi.yaml |
静态规范,始终可用(不需要构建标志) |
| 邮差收藏 | docs/postman_collection.json |
导入邮递员;所有28个工具均已预先配置 |
启用Swagger UI
构建与 swagger Maven配置文件用于激活实时Swagger UI:
# Build with Swagger
mvn clean package -Pswagger -DskipTests
# Run
java -jar target/mcp-server-1.0.0-SNAPSHOT.jar
# Open in browser
open http://localhost:8080/swagger-ui.html
导入邮差收藏
- 打开邮递员→ 导入 → 选择
docs/postman_collection.json - 设置
baseUrl集合变量(默认值:http://localhost:8080) - 跑 认证→ serverToServerLogin 第一——
sessionId自动保存 - 使用已保存的
sessionId在所有后续请求中
H2控制台连接
URL: http://localhost:8080/h2-console
JDBC URL: jdbc:h2:file:./data/mockecomdb
Username: sa
Password: (leave blank)
健康检查示例
curl http://localhost:8080/actuator/health
# {"status":"UP","components":{"db":{"status":"UP"},"diskSpace":{"status":"UP"}}}
28种MCP工具
产品发现--无需授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 1 | searchProducts |
query, page, pageSize |
所有类别的全文搜索。如果没有找到,则生成模拟产品。 |
| 2 | filterProducts |
query, category, subCategory, brand, page, pageSize |
按类别/子类别/品牌的任意组合过滤产品。 |
| 3 | getFilters |
query |
返回可用的过滤器方面(类别、子类别、品牌)和计数。 |
| 4 | getSortOptions |
query |
返回6个排序选项: price_asc, price_desc, rating_desc, newest, popularity, delivery_asc. |
| 5 | getProductDetails |
productId |
完整的产品——标题、描述、品牌、型号、价格、MRP、评级、属性、图片。 |
| 6 | getProductReviews |
productId, page, pageSize |
评分摘要+带有评分分布的分页评论。 |
| 7 | getDeliveryTime |
productId, pincode |
给定夹码的交货预估和日期范围。 |
身份验证--服务器到服务器
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 8 | serverToServerLogin |
phone, platform, secret |
获取 sessionId.秘密= mock-platform-secret-key。如果是新客户,则创建客户。 |
购物车--需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 9 | addToCart |
productId, quantity, sessionId |
将产品添加到活动购物车。如果不存在购物车,则创建购物车。重新计算总数。 |
| 10 | checkout |
cartId, sessionId |
将购物车转换为结账。退货 checkoutId 总计。 |
地址--需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 11 | getAddresses |
sessionId |
列出客户的所有已保存地址。 |
| 12 | selectAddress |
checkoutId, addressId, sessionId |
将收货地址附加到收银台。 |
付款--需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 13 | initiatePayment |
checkoutId, paymentMethod, sessionId |
启动付款。方法: UPI, CARD, COD, NETBANKING, WALLET。创建订单。 |
| 14 | getPaymentStatus |
paymentId, sessionId |
返回付款状态和相关信息 orderId. |
订单--需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 15 | getOrderDetails |
orderId, sessionId |
包含所有项目、状态和装运信息的完整订单。 |
| 16 | getOrders |
sessionId, page, pageSize |
分页的订单历史。 |
| 17 | getShipments |
sessionId, page, pageSize |
带有跟踪号的分页装运清单。 |
| 18 | cancelOrder |
orderId, itemId, sessionId |
取消整个订单或特定项目。 |
| 19 | returnOrderItem |
orderItemId, reason, sessionId |
启动特定项目的退货。 |
发货--需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 20 | sendDeliveryOtp |
shipmentId, sessionId |
生成并发送装运的交货OTP。 |
支持票--需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 21 | getTickets |
sessionId, page, pageSize |
客户支持票的分页列表。 |
| 22 | getTicketDetails |
ticketId, sessionId |
带有完整评论线程的工单详细信息。 |
| 23 | addTicketComment |
ticketId, comment, sessionId |
在工单上添加客户评论。 |
| 24 | createTicket |
subject, description, type, orderId, orderItemId, sessionId |
创建新票证。类型: DELIVERY_ISSUE, RETURN_REQUEST, PAYMENT_ISSUE, PRODUCT_QUALITY, CANCELLATION, OTHER. |
评论-需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 25 | submitProductReview |
productId, rating, title, description, sessionId |
对产品进行评分和评价(1-5颗星)。如果之前订购,则标记为已验证购买。 |
| 26 | submitShipmentReview |
shipmentId, rating, title, description, sessionId |
对交付体验进行评分。 |
愿望清单--需要授权
| # | 工具 | 参数 | 说明 |
|---|---|---|---|
| 27 | addToWishlist |
productId, sessionId |
将产品添加到愿望清单中。复制安全。 |
| 28 | getWishlist |
sessionId, page, pageSize |
返回带有产品详细信息的分页愿望清单。 |
身份验证流程
# Step 1 — Get a session
sessionId = serverToServerLogin(
phone = "9999999999",
platform = "WEB",
secret = "mock-platform-secret-key"
)
# Step 2 — Use sessionId in all authenticated tools
addToCart(productId=<id>, quantity=1, sessionId=<sessionId>)
餐厅和Swiggy刮刀工具
该服务器包括一个完整的Swiggy数据抓取器和餐厅查询层,增加了 12个新的MCP工具 用于食品配送用例。
它在创业中是如何运作的
| 订单 | 组件 | 操作 |
|---|---|---|
| 1 | CityDataInitializer |
用lat/lng(幂等)为印度50个主要城市播种 |
| 2 | SeedDataLoader |
如果 classpath:db/seed/seed-data.json 存在,餐厅桌子是空的,加载刮餐厅+菜单 |
| 3 | ProductSeedLoader |
如果 classpath:db/seed/products-seed.json 存在,产品表为空,加载70个预生成的产品 |
| 4 | SampleRestaurantDataSeeder |
如果餐厅桌子仍然是空的,则加载10个硬编码的演示餐厅作为后备 |
| 5 | ScraperAutoStartRunner |
如果 app.scraper.auto-start=true,异步启动实时抓取 |
餐厅查询工具(6个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
listRestaurantCities |
-- | 印度所有50个拥有餐厅数量和刮擦状态的城市 |
searchRestaurants |
cityName, cuisine, name, isPureVeg, page, pageSize |
按任意组合搜索;按评级排序的结果 |
getRestaurantBySwiggyId |
swiggyId |
餐厅详细信息 |
getRestaurantMenu |
swiggyId |
按类别分组的完整菜单,包括项目价格(以印度卢比计) |
searchMenuItems |
query, cityName, page, pageSize |
按名称查找城市中所有餐厅的菜肴 |
filterRestaurantMenuItems |
swiggyId, isVeg, inStock |
按蔬菜/非蔬菜、可用性筛选餐厅菜单 |
刮板控制工具(6个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
getScraperStatus |
-- | 城市/餐厅/菜单计数;刮擦是否正在运行 |
startRestaurantScraping |
-- | 对所有未被抓取的城市开始异步抓取(跳过已完成) |
scrapeRestaurantsForCity |
cityName |
同步报废单个城市;返回新餐厅数量 |
startMenuScraping |
-- | 为所有没有菜单的餐厅启动异步菜单抓取 |
scrapeRestaurantMenu |
swiggyId |
同步删除一家餐厅的菜单 |
exportSeedData |
-- | 将所有数据导出到 ./seed-export/seed-data.json 为承诺 |
从Swiggy抓取实时数据
要求: 网络访问
www.swiggy.com.服务器必须在能够访问Swiggy的API的计算机上运行。
第1步-取消所有餐厅:
{ "name": "startRestaurantScraping", "arguments": {} }
监视器 getScraperStatus每个城市大约需要30-120秒(速率限制为1.5秒)。所有50个城市都需要1~2个小时。
步骤2–废弃菜单:
{ "name": "startMenuScraping", "arguments": {} }
数千家餐厅可能需要几个小时。两个刮刀都是 渐进的 –可以随时中断和恢复。
步骤3–检查进度:
{ "name": "getScraperStatus", "arguments": {} }
退货 totalCities, scrapedCities, totalRestaurants, restaurantsWithMenu以及奔跑的旗帜。
种子数据管道
种子数据管道允许您将抓取的数据提交到git,这样每次新部署都会满载启动,不需要重新抓取。
导出抓取的数据
刮完之后,打电话给 exportSeedData MCP工具:
{ "name": "exportSeedData", "arguments": {} }
这写道 ./seed-export/seed-data.json --一个包含所有餐厅及其完整菜单的便携式JSON文件。
提交种子文件
cp seed-export/seed-data.json src/main/resources/db/seed/seed-data.json
git add src/main/resources/db/seed/seed-data.json
git commit -m "chore: add scraped Swiggy restaurant seed data (N restaurants)"
git push
重建和部署
mvn clean package -DskipTests
java -jar target/mcp-server-1.0.0-SNAPSHOT.jar
在首次使用新数据库启动时, SeedDataLoader 检测种子文件并自动导入所有数据。 SampleRestaurantDataSeeder 当数据已经存在时跳过。
重新抓取后的增量更新
当你重新运行刮刀来挑选新餐厅时:
- 城市:
scrapeRestaurantsForCitySwiggy ID的更新——更新现有餐厅,插入新餐厅 - 菜单:
startMenuScraping跳过以下餐厅menuScraped = true;使用scrapeRestaurantMenu强制刷新一家餐厅 - 重新抓取后,致电
exportSeedData再次复制新文件,并提交
数据持久性(开发)
开发H2数据库持续存在 ./data/mockecomdb.* (基于文件的H2)。数据在服务器重启后仍然有效。这 ./data/ 目录是 .gitignored——仅出口 seed-data.json 在 src/main/resources/db/seed/ 承诺。
LLM产品数据生成
服务器可以使用Anthropic LLM(Claude)来生成 按需提供真实的印度市场产品数据.当产品搜索或筛选器未返回现有结果,并且配置了Anthropic API密钥时,服务器调用 claude-haiku-4-5 生成产品,将其保存到数据库,并将其返回给调用者。
运作原理
MCP call: searchProducts / filterProducts
│
▼
productRepository.searchByQuery(...) → results found?
│ no results │ yes
▼ ▼
LlmProductGeneratorService.isAvailable()? return existing data
│ yes (API key set) │ no
▼ ▼
callAnthropicAPI(...) MockDataGeneratorService (deterministic fallback)
│
▼
Parse JSON → save Products + ProductAttributes to DB
│
▼
Return newly generated products to MCP caller
生成的产品是 持久化到数据库 立即,所以:
- 对同一查询的后续调用返回已保存的产品(没有额外的API调用)
- 数据可以导出为种子JSON并提交,以便新的部署开始完全加载
设置--启用LLM生成
选项A:环境变量(推荐)
export ANTHROPIC_API_KEY=sk-ant-your-key-here
mvn spring-boot:run
选项B:application.yml
app:
llm:
api-key: sk-ant-your-key-here
model: claude-haiku-4-5-20251001 # default, any Claude model works
enabled: true
注: API密钥故意不提交给git。始终通过环境变量或局部变量传递它
.env文件已从版本控制中排除。
当 ANTHROPIC_API_KEY 未设置, LlmProductGeneratorService.isAvailable() 回报 false 服务器回退到 MockDataGeneratorService --从哈希种子生成的确定性模拟产品。不会抛出任何错误。
种子产品-Seed.json从LLM输出
通过MCP调用(或直接通过REST API)生成产品后,将其导出到种子文件:
{ "name": "exportProductSeedData", "arguments": {} }
这写道 ./seed-export/products-seed.json。将其复制到resources目录并提交:
cp seed-export/products-seed.json src/main/resources/db/seed/products-seed.json
git add src/main/resources/db/seed/products-seed.json
git commit -m "chore: add LLM-generated product seed data"
git push
在下一次新的部署中, ProductSeedLoader (@Order 3)在调用LLM之前自动加载文件。
加载产品种子的启动订单
| 订单 | 组件 | 操作 |
|---|---|---|
| 1 | CityDataInitializer |
用lat/lng(幂等)为印度50个主要城市播种 |
| 2 | SeedDataLoader |
负载 classpath:db/seed/seed-data.json (餐厅+菜单)如果DB为空 |
| 3 | ProductSeedLoader |
负载 classpath:db/seed/products-seed.json 如果产品表为空 |
| 4 | SampleRestaurantDataSeeder |
回退:如果仍为空,则加载10个硬编码的演示餐厅 |
| 5 | ScraperAutoStartRunner |
如果 app.scraper.auto-start=true,开始实时抓取 |
预加载种子数据
承诺 src/main/resources/db/seed/products-seed.json 包含 70产品 在所有类别中:
| 类别 | 计数 | 品牌 |
|---|---|---|
| 电子 | 15 | 三星、OnePlus、苹果、boAt、索尼、小米、惠普、戴尔、华硕、JBL、Realme、佳能 |
| 时尚 | 15 | Fabindia、巴塔、李维斯、彪马、艾伦·索利、Manyavar、耐克、阿迪达斯、Fossil、W for Women |
| 杂货 | 15 | 塔塔、财富、阿穆尔、Aashirvaad、MDH、Haldirams、雀巢、Dabur、Patanjali、Saffola |
| 美丽 | 13 | 拉克梅、喜马拉雅、玛玛尔思、哇、欧莱雅、露得清、多芬、卡尼尔、妮维雅、李子 |
| 主页 | 12 | 威望、飞利浦、巴贾吉、大提琴、戈德雷、弥尔顿、索利莫、鸽子、尼尔卡马尔、蝴蝶 |
所有产品都使用现实的印度卢比定价,并提供有意义的折扣,并包括3-5个特定类别的属性(例如,电子产品的保修+RAM+处理器;杂货的保质期+FSSAI认证)。
环境变量摘要
| 变量 | 默认值 | 描述 |
|---|---|---|
ANTHROPIC_API_KEY |
(空) | 无烟煤API键。设置后,启用LLM产品生成。 |
app.llm.model |
claude-haiku-4-5-20251001 |
用于生成的Claude模型(设置在 application.yml) |
app.llm.enabled |
true |
主开关;着手 false 即使存在API密钥,也要强制使用模拟数据 |
测试用例
测试套件(7个文件,83个测试)
| 文件 | 涵盖的工具 | 测试计数 | 关键场景 |
|---|---|---|---|
MockEcomMcpServerApplicationTests |
-- | 1 | 成功加载Spring上下文 |
ProductToolsIntegrationTest |
1–7 | ~20 | 多类别搜索、分页、过滤器、交付时间 |
AuthAndCartFlowTest |
8–14 | ~9 | 登录有效/无效、购物车生命周期、结账、付款 |
OrderManagementTest |
15–20 | ~15 | 订单检索、取消、退货、OTP、发货跟踪 |
TicketAndReviewTest |
21–26 | ~18 | 工单创建(所有类型)、评论、产品和交付评论 |
WishlistTest |
27–28 | ~10 | 添加、查看、分页、防止重复 |
EndToEndShoppingJourneyTest |
1–28 | ~10 | 涵盖所有5个类别的完整购物之旅 |
MockDataGeneratorTest |
-- | ~10 | 类别检测、产品生成、属性生成 |
端到端流程(端到端购物旅程测试)
1. serverToServerLogin → sessionId
2. searchProducts → productId
3. filterProducts → filtered list
4. getFilters → filter facets
5. getSortOptions → sort options
6. getProductDetails → product info
7. getProductReviews → reviews
8. getDeliveryTime → estimate
9. addToWishlist → wishlistItem
10. getWishlist → wishlist
11. addToCart (x2 products) → cartId
12. checkout → checkoutId
13. getAddresses → addressId
14. selectAddress → confirmed
15. initiatePayment (UPI) → paymentId, orderId
16. getPaymentStatus → SUCCESS
17. getOrderDetails → order + items
18. getOrders → history
19. getShipments → shipmentId
20. sendDeliveryOtp → OTP sent
21. createTicket → ticketId
22. getTickets → list
23. getTicketDetails → ticket + comments
24. addTicketComment → comment added
25. submitProductReview → review saved
26. submitShipmentReview → review saved
在本地运行测试
# Run all tests (uses test profile with separate H2 DB)
mvn test
# Run a specific test class
mvn test -Dtest=EndToEndShoppingJourneyTest
# Run a specific test method
mvn test -Dtest=ProductToolsIntegrationTest#testSearchProducts
# Run with verbose output
mvn test -Dsurefire.useFile=false
# Run tests + generate coverage report (if jacoco configured)
mvn verify
# Skip tests during build
mvn clean package -DskipTests
测试配置文件
测试使用 application-test.yml:
- 在内存DB中分离H2:
jdbc:h2:mem:testdb - 为每次测试运行创建新的架构(
ddl-auto: create-drop) NON_KEYWORDS=VALUE添加以避免H2 SQL关键字冲突- 禁用SQL日志记录以获得更清晰的输出
CI(GitHub操作)
通过以下方式在每次推送/PR上自动运行测试 .github/workflows/build.yml:
- Java 21(temurin),Maven缓存
mvn clean verify -Dspring.profiles.active=test- JAR工件上传成功
生产部署
Docker Compose(推荐)
# Build the JAR
mvn clean package -DskipTests
# Start app + PostgreSQL
docker-compose up --build -d
# View logs
docker-compose logs -f app
# Stop
docker-compose down
服务已启动:
- 应用 --端口上的Spring Boot
8080,个人资料prod - Postgres --PostgreSQL 16端口
5432,DBmockecomdb
PostgreSQL数据保存在Docker卷中 pgdata.
自定义环境变量
docker-compose up \
-e DB_PASSWORD=supersecret \
-e SERVER_PORT=9000 \
--build
或者创建一个 .env 旁边的文件 docker-compose.yml:
DB_URL=jdbc:postgresql://myhost:5432/mydb
DB_USERNAME=myuser
DB_PASSWORD=mysecret
SPRING_PROFILES_ACTIVE=prod
手动JAR部署
# Build
mvn clean package -DskipTests
# Run with prod profile
java -jar target/mcp-server-1.0.0-SNAPSHOT.jar \
--spring.profiles.active=prod \
--server.port=8080 \
--DB_URL=jdbc:postgresql://localhost:5432/mockecomdb \
--DB_USERNAME=postgres \
--DB_PASSWORD=postgres
Kubernetes/云
服务器是无状态的(数据库中的所有状态),因此可以水平扩展。关键考虑因素:
- 集
spring.jpa.hibernate.ddl-auto=update(已设置application-prod.yml) - 使用托管PostgreSQL服务(RDS、Cloud SQL等)
- 将环境变量挂载为Kubernetes的秘密
- 活体探针:
GET /actuator/health - 准备就绪探针:
GET /actuator/health
连接MCP客户端
克劳德桌面
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)或 %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"mock-ecom": {
"url": "http://localhost:8080/sse",
"type": "sse"
}
}
}
重新启动克劳德桌面。您将看到28个可用工具。
克劳德代码(CLI)
# Add MCP server
claude mcp add mock-ecom --transport sse http://localhost:8080/sse
# List configured servers
claude mcp list
# Remove
claude mcp remove mock-ecom
或编辑 ~/.claude/settings.json:
{
"mcpServers": {
"mock-ecom": {
"type": "sse",
"url": "http://localhost:8080/sse"
}
}
}
VS代码(复制/继续/临床)
添加到您的VS代码 settings.json:
{
"mcp": {
"servers": {
"mock-ecom": {
"type": "sse",
"url": "http://localhost:8080/sse"
}
}
}
}
自定义MCP客户端(Python)
from mcp import ClientSession
from mcp.client.sse import sse_client
async with sse_client("http://localhost:8080/sse") as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
result = await session.call_tool("searchProducts", {
"query": "laptop",
"page": 0,
"pageSize": 10
})
自定义MCP客户端(JavaScript/TypeScript)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
const transport = new SSEClientTransport(
new URL("http://localhost:8080/sse")
);
const client = new Client({ name: "my-client", version: "1.0.0" }, {});
await client.connect(transport);
const result = await client.callTool("serverToServerLogin", {
phone: "9999999999",
platform: "WEB",
secret: "mock-platform-secret-key"
});
正在验证连接
# Test SSE endpoint is alive
curl -N http://localhost:8080/sse
# Health check
curl http://localhost:8080/actuator/health
状态 & 全部
当前状态:✅ 工作
| 功能 | 状态 |
|---|---|
| 28个MCP工具通过SSE暴露 | ✅ 完成 |
| 模拟数据生成(5类) | ✅ 完成 |
| 通过Anthropic API生成LLM产品 | ✅ 完成 |
| 70个产品种子文件(共5个类别) | ✅ 完成 |
| 新部署时自动加载产品种子 | ✅ 完成 |
| 基于H2文件的开发数据库(在重新启动后持续存在) | ✅ 完成 |
| PostgreSQL生产支持 | ✅ 完成 |
| 基于会话的身份验证 | ✅ 完成 |
| 完整的购物流程(搜索→ 顺序) | ✅ 完成 |
| 支持票和评论 | ✅ 完成 |
| 产品和装运审核 | ✅ 完成 |
| 愿望清单 | ✅ 完成 |
| Swiggy餐厅摩天大楼(50个城市) | ✅ 完成 |
| 餐厅+菜单种子数据管道 | ✅ 完成 |
| React Web UI(餐厅+产品浏览器) | ✅ 完成 |
| 用于所有数据(餐厅、产品、统计数据)的REST API | ✅ 完成 |
| 83次集成测试✅ 完成 | |
| Docker+Docker组合✅ 完成 | |
| GitHub操作CI | ✅ 完成 |
| 一个命令本地启动脚本 | ✅ 完成 |
TODO/未来增强功能
| 优先级 | 项目 |
|---|---|
| 高 | 通过可配置网关添加真正的OTP交付(短信/电子邮件) |
| 高 | 添加地址创建工具(当前地址是自动生成的) |
| 高 | 添加产品图片上传支持 |
| 中等 | 添加优惠券/折扣码工具 |
| 中等 | 添加产品库存管理工具 |
| 中等 | 添加管理工具(更新订单状态、解决工单) |
| 中等 | 基于JWT的身份验证作为平台秘密的替代方案 |
| 中等 | REST端点的Swagger/OpenAPI文档 |
| 低 | 为产品搜索结果添加Redis缓存 |
| 低 | 添加Elasticsearch以获得更好的全文搜索 |
| 低 | 多语言/多货币支持 |
| 低 | MCP工具调用的速率限制 |
| 低 | 订单状态更改的Webhook通知 |
| 低 | 将订单导出为PDF/CSV |
已知限制
- 无法通过MCP工具创建地址(可以使用自动生成的模拟地址)
- 支付处理完全模拟(UPI/CARD/NETBANKING/WALLET总是成功,COD总是成功)
- 生成交付OTP,但实际上并没有发送到任何地方
- 产品图片来源于
picsum.photos(外部依赖性) - H2数据 持续 在开发模式下跨重启(基于文件的数据库
./data/).删除./data/重置。 - Live Swiggy抓取需要无限制的互联网访问
www.swiggy.com;沙盒/受限环境必须使用提交的种子文件
