AI购物助手

一款AI驱动的购物助手,支持在多电商平台搜索、比较并购买三星Galaxy手机,通过自然语言交互完成交易。

  • by harshgupta59
  • Java
  • 本地部署
  • 更新于
在 GitHub 查看 harshgupta59/spring-ai-mcp-demo

使用说明

📱 三星Galaxy S系列——人工智能购物助手

比较亚马逊、Flipkart、三星和Croma的三星Galaxy手机,然后通过AP2协议安全购买

由...驱动 春季AI + MCP(模型上下文协议) + AP2(代理支付协议) + 奥拉马LLM


📖 目录

  1. 这是什么?
  2. 关键技术概念(为初学者讲解)
  3. 架构概述
  4. 完成请求流(逐步)
  5. MCP协议详细信息
  6. AP2安全支付流
  7. 聊天记忆系统
  8. 产品数据
  9. 项目结构
  10. 每个文件的作用
  11. 入门指南
  12. API终点
  13. 配置参考
  14. 故障排除
  15. 技术栈

🎯 这是什么?

一款基于人工智能的购物助手,让您 搜索、比较和购买 三星Galaxy手机通过自然对话。问以下问题 “比较所有平台的S24 Ultra价格” --LLM自动搜索4个电子商务平台,比较价格,推荐购买地点,并通过谷歌的 AP2(代理支付协议) 通过加密授权验证。

主要特点

  • 🔍 4平台搜索 --亚马逊印度、Flipkart、Samsung.com印度、Croma
  • 📊 并排比较 --价格、MRP、折扣%、银行优惠、EMI、赠品、交货、保修
  • 🔒 AP2安全支付 --三步加密授权链(意图→ Cart → 付款)
  • 💬 会话记忆 --具有上下文保留功能的多回合对话(最后20条消息)
  • 🎨 高级暗聊天用户界面 --打字指示器、建议芯片、响应式设计
  • 🤖 完全本地化 --无需云API,完全在使用Ollama的机器上运行

你能说什么

• "Compare S24 Ultra prices"           → Searches all 4 platforms
• "Search on Amazon for S24"           → Searches Amazon only
• "What's on Flipkart?"               → Searches Flipkart
• "Details for FK-S24U-256"            → Gets full product specs
• "Buy the Flipkart S24 Ultra"        → Starts AP2 payment flow

📚 关键技术概念(为初学者讲解)

什么是LLM?

LLM(大型语言模型) 是一个基于大量文本数据训练的人工智能模型。它可以理解自然语言(比如“在S24 Ultra上为我找到最好的交易”),并产生类似人类的反应。在这个项目中,我们使用 奥拉玛 运行 llama3.2:3b 模型 本地在您的计算机上 -不需要互联网或API密钥。

示例:当您键入“Compare S24 Ultra prices”时,LLM知道您想要进行价格比较,并决定调用 comparePrices 工具。

Ollama是什么?

奥拉玛 是一个允许您在自己的计算机上运行LLM(如Llama、Mistral等)的应用程序。将其视为本地ChatGPT。它在上公开了一个API http://localhost:11434 我们的Java应用程序与之对话。

# Install Ollama from https://ollama.com
# Then download the model:
ollama pull llama3.2:3b    # Downloads a 2GB model
ollama serve               # Starts the API server

什么是Spring AI?

春季AI 是一个框架(Spring生态系统的一部分),可以轻松地将AI/LLM功能集成到Java应用程序中。它提供:

  • ChatClient --向LLM(Ollama、OpenAI等)发送提示的Java客户端
  • 工具调用 --让LLM在需要数据时调用Java方法
  • 聊天记忆 --记住对话中以前的消息
  • MCP集成 --连接到MCP服务器以查找工具
// Example: Send a message to the LLM with tools
String response = chatClient.prompt()
    .user("Compare S24 Ultra prices")     // User's question
    .call()                                // Send to Ollama
    .content();                            // Get the response text

什么是MCP(模型上下文协议)?

MCP(模型上下文协议) 是LLM的标准化协议↔ 工具通信。把它想象成 “用于AI工具的USB” --通用即插即用标准。

我们为什么需要它? LLM可以理解语言,但他们不能自己访问数据库、调用API或搜索网络。MCP允许他们“调用工具”——获取真实数据的Java方法。

它是如何工作的:

  1. MCP服务器 公开工具(Java方法注释为 @Tool)
  2. MCP客户端 连接到服务器,发现可用工具
  3. 当 LLM 需要数据,它告诉客户端“使用这些参数调用此工具”
  4. 这 客户端 将请求发送到服务器,获取结果,并将其传递回LLM

运输: 在这个项目中,MCP使用 SSE(服务器发送事件) 传输--客户端连接到 http://localhost:8081/sse 以建立用于实时通信的持久连接。

MCP Client ──SSE──→ MCP Server
   (port 8080)         (port 8081)

什么是AP2(代理支付协议)?

AP2(代理支付协议) 是谷歌用于安全人工智能代理主导支付的开放协议。传统的支付流程假设人类点击“购买”。但当人工智能代理代表您进行购买时,我们需要额外的安全保障:

  • 授权 --证明用户允许代理人花钱
  • 真实性 --确保订单符合用户的实际需求
  • 问责 --如果出现问题,创建审计跟踪

AP2通过一个 三步加密授权链 (详细解释 在......下面).

什么是工具(在AI环境中)?

A. 工具 是LLM可以调用以获取真实世界数据的函数。LLM不直接执行该工具,它生成一个 工具调用请求 (“请致电 searchAmazon 有争论 S24 Ultra),框架(Spring AI)实际执行Java方法并将结果反馈给LLM。

@Tool(description = "Search for Samsung phones on Amazon India")
public String searchAmazon(@ToolParam(description = "Phone name") String productName) {
    // This method runs on the MCP Server when the LLM calls it
    List<Product> products = mockDataProvider.searchAmazon(productName);
    return formatResults(products);
}

什么是SSE(服务器发送事件)?

上海证券交易所 是一种web技术,允许服务器通过单个HTTP连接将数据推送到客户端。与常规HTTP(请求→ SSE保持连接打开以进行连续通信。MCP使用SSE,因此客户端可以有效地接收工具响应。

什么是JSON-RPC?

JSON-RPC 是一种用于调用远程函数的轻量级协议。MCP对所有工具调用使用JSON-RPC 2.0格式:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "searchAmazon",
    "arguments": { "productName": "S24 Ultra" }
  }
}

🏗️ 架构概述

应用程序以如下方式运行 3个单独的过程 它们相互通信:

┌────────────────────────────────────────────────────────────────────┐
│  BROWSER (index.html)                                              │
│  Dark-themed chat UI with suggestion cards                         │
│  Sends user messages via POST /api/shop                            │
└─────────────────┬──────────────────────────────────────────────────┘
                  │ POST /api/shop {message, conversationId}
                  │ (Standard REST/JSON)
                  ▼
┌────────────────────────────────────────────────────────────────────┐
│  MCP CLIENT (port 8080) — The Orchestrator                         │
│                                                                    │
│  ShoppingController ─→ ShoppingAssistant ─→ Ollama LLM            │
│  (REST API)             (ChatClient +        (llama3.2:3b          │
│                          Memory + Tools)      localhost:11434)      │
│                                                                    │
│  What it does:                                                     │
│  1. Receives user messages via REST API                            │
│  2. Injects system prompt (Samsung expert persona)                 │
│  3. Loads conversation history (last 20 messages)                  │
│  4. Sends prompt + tool definitions to LLM                         │
│  5. When LLM requests a tool call → routes it via MCP to server   │
│  6. Feeds tool result back to LLM                                  │
│  7. Returns LLM's final response to browser                       │
└─────────────────┬──────────────────────────────────────────────────┘
                  │ MCP (SSE Transport)
                  │ JSON-RPC 2.0 over SSE at /sse
                  ▼
┌────────────────────────────────────────────────────────────────────┐
│  MCP SERVER (port 8081) — The Tool Provider                        │
│                                                                    │
│  ┌─────────────┬──────────────┬──────────────┬──────────────┐     │
│  │ AmazonTool  │ FlipkartTool │ SamsungStore │ CromaTool    │     │
│  │             │              │ Tool         │              │     │
│  ├─────────────┼──────────────┼──────────────┴──────────────┤     │
│  │ PriceCompar │ OrderTool    │ AP2PaymentTool              │     │
│  │ ator        │ (details,    │ (intent, cart, payment)     │     │
│  │             │  status)     │                             │     │
│  ├─────────────┴──────────────┴─────────────────────────────┤     │
│  │ McpToolConfig (registers all 10 tools explicitly)        │     │
│  ├──────────────────────────────────────────────────────────┤     │
│  │ MockDataProvider (28 products) │ PaymentService (AP2 PSP)│     │
│  └──────────────────────────────────────────────────────────┘     │
│                                                                    │
│  What it does:                                                     │
│  • Exposes @Tool methods over MCP (SSE transport)                  │
│  • Searches mock product data across 4 platforms                   │
│  • Compares prices with grouping and sorting                       │
│  • Manages AP2 mandate chain for secure payments                   │
│  • Returns formatted text results to the LLM                      │
└────────────────────────────────────────────────────────────────────┘

流程总结

进程 端口 角色
奥拉玛 11434 跑步 llama3.2:3b LLM本地。决定调用哪些工具。生成自然语言响应。
MCP服务器 8081 通过MCP公开产品搜索+AP2支付工具。这里没有LLM,只有Java方法。
MCP客户端 8080 编排器:桥接用户↔ LLM↔ MCP工具。将聊天UI提供给浏览器。

他们如何相互交谈

Browser ──HTTP/JSON──→ MCP Client ──HTTP──→ Ollama (LLM)
                            │
                            └──SSE/JSON-RPC──→ MCP Server (Tools)
  1. 浏览器→ MCP客户端:标准REST(POST /api/shop JSON正文)
  2. MCP客户端→ 奥拉玛:HTTP到 /api/chat (Spring AI会自动处理此问题)
  3. MCP客户端→ MCP服务器:基于SSE传输的MCP协议(Spring AI也处理此问题)

🔄 完成请求流(逐步)

流程1:产品搜索和比较

当用户键入 “比较S24 Ultra价格”,具体情况如下:

第一步——浏览器→ 控制器

POST http://localhost:8080/api/shop
{"message": "Compare S24 Ultra prices", "conversationId": "session-abc123"}

ShoppingController 接收此信息,提取 message 和 conversationId,呼叫 shoppingAssistant.chat().

步骤2——ShoppingAssistant构建LLM提示

组装了三件事:

  1. 系统提示 --“你是三星Galaxy S系列购物助理…”(定义角色和指导方针)
  2. 对话历史 --来自的最后20条消息 MessageWindowChatMemory (所以LLM会记住之前的回合)
  3. 用户消息 --“比较S24 Ultra价格”

另外: 10工具定义 (名称、描述、参数模式)被发送给Ollama,以便LLM知道它可以调用哪些工具。

步骤3--向Ollama LLM发送提示

完整提示转到 http://localhost:11434/api/chat (Ollama的API)。LLM读取用户的意图并决定调用工具。它返回:

{
  "tool_calls": [{
    "function": {
      "name": "spring_ai_mcp_client_s_comparePrices",
      "arguments": {"productName": "S24 Ultra"}
    }
  }]
}

重要提示: LLM不执行任何操作,它只决定调用哪个工具以及使用什么参数。Spring AI处理实际执行。

关于工具名称的说明: Spring AI添加前缀 spring_ai_mcp_client_s_ 所有MCP工具名称。这 s 来源于中的MCP连接名称 application.yml此前缀对用户不可见,但对刀具布线很重要。

步骤4-Spring AI将工具调用路由到MCP服务器

Spring AI拦截 tool_calls,抬头看 comparePrices 并通过SSE向MCP服务器发送JSON-RPC请求:

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "comparePrices",
    "arguments": {"productName": "S24 Ultra"}
  }
}

步骤5-MCP服务器执行该工具

PriceComparator.comparePrices("S24 Ultra") 在服务器上运行:

  1. 呼叫 mockDataProvider.searchAllPlatforms("S24 Ultra")
  2. 从每个平台获取2个产品(256GB+512GB)=总共8个
  3. 按型号+存储进行分组,以便进行公平比较
  4. 按价格对每组进行排序(最便宜的先)
  5. 格式化一个丰富的比较,显示每个平台的价格、MRP、折扣%、报价、交付、保修
  6. 返回格式化字符串(≈5000个字符的比较数据)

步骤6——工具结果返回LLM

Spring AI将工具输出作为 tool_response 消息。LLM现在拥有真实的产品数据,并生成自然语言摘要:

Based on the comparison, here's the best deal for Samsung Galaxy S24 Ultra:

**Best Price:** ₹127,999 (MRP: ₹149,999, 15% off) on Flipkart
  with ₹8,000 off on Axis Bank Card + ₹1,000 off with SuperCoins

Other Options:
• Amazon India: ₹129,999 (13% off)
• Croma: ₹129,999 (13% off)
• Samsung.com India: ₹131,999 (12% off)

Would you like to buy from Flipkart?

步骤7——响应返回给用户

LLM响应→ ChatClient 保存到内存→ ShoppingAssistant 返回字符串→ ShoppingController 用JSON封装→ 浏览器在聊天UI中呈现它。


流程2:AP2安全支付

当用户决定购买时 AP2(代理支付协议) 开始。请参阅专用部分 在......下面.


🔗 MCP协议详细信息

MCP做什么

MCP(模型上下文协议) 是LLM的标准化协议↔ 工具通信。没有MCP,您需要为每个工具编写自定义集成代码。使用MCP,可以通过标准协议发现和调用工具。

传输:SSE(服务器发送事件)

此项目使用 SSE运输。客户端连接到 http://localhost:8081/sse 以建立持久连接。所有工具调用和响应都通过此连接进行。

# Client configuration (application.yml)
spring.ai.mcp.client:
  type: SYNC
  sse:
    connections:
      s:                            # Short name → keeps tool name prefixes short
        url: http://localhost:8081   # MCP Server address

为什么连接名称只是 s? Spring AI在所有工具名称前加上 spring_ai_mcp_client_{connection-name}_一个简短的名字,比如 s 产生较短的工具名称(例如。, spring_ai_mcp_client_s_searchAmazon),这有助于小型LLM可靠地处理工具调用。长名字会让小模特感到困惑。

工具发现(启动时)

  1. MCP客户端连接到 http://localhost:8081/sse
  2. 发送 initialize 然后握手 tools/list 请求
  3. 服务器以全部10个响应 @Tool-带注释的方法——参数的名称、描述和JSON模式
  4. 客户端将它们包装为 SyncMcpToolCallback 对象并将其注册到 ChatClient

工具执行(聊天期间)

  1. LLM决定致电 searchFlipkart("S24 Ultra")
  2. Spring AI发送 tools/call JSON-RPC通过SSE连接到MCP服务器
  3. 服务器执行 FlipkartTool.searchFlipkart("S24 Ultra")
  4. 通过JSON-RPC响应返回格式化的结果字符串
  5. Spring AI将结果作为工具响应消息传递回LLM

工具注册:McpToolConfig

Spring AI @Tool 注释本身并不能在MCP服务器上自动注册工具。我们需要…… 明确注册 所有使用工具bean MethodToolCallbackProvider:

@Configuration
public class McpToolConfig {
    @Bean
    public ToolCallbackProvider toolCallbackProvider(
            AmazonTool amazonTool, FlipkartTool flipkartTool, /* ... */) {
        return MethodToolCallbackProvider.builder()
            .toolObjects(amazonTool, flipkartTool, cromaTool, samsungStoreTool,
                         priceComparator, orderTool, ap2PaymentTool)
            .build();
    }
}

这个类很关键——没有它,MCP服务器报告0个工具,一切都不起作用。

全部10个注册工具

# 工具 类 参数 用途
1 searchAmazon AmazonTool productName 在亚马逊印度搜索三星手机
2 searchFlipkart FlipkartTool productName 在Flipkart上搜索三星手机
3 searchSamsungStore SamsungStoreTool productName 搜索Samsung.com印度
4 searchCroma CromaTool productName Search Croma(塔塔集团所有)
5 comparePrices PriceComparator productName 同时比较所有4个平台
6 getProductDetails OrderTool productId 按ID获取特定产品的完整详细信息
7 checkOrderStatus OrderTool orderId 检查订单或AP2交易的状态
8 createIntentMandate AP2PaymentTool intent, budget, platform AP2步骤1:捕捉用户意图
9 createCartMandate AP2PaymentTool intentId, productId, qty AP2第二步:锁车
10 processPayment AP2PaymentTool cartId, method, name, addr AP2步骤3:处理付款

🔒 AP2安全支付流

为什么选择AP2?

传统支付假设人为点击“购买”。随着人工智能代理进行购买,我们需要额外的保障措施:

  • 授权 --证明用户允许代理人花钱
  • 真实性 --确保订单符合用户的真实意图
  • 问责 --如果出现问题,请维护加密审计跟踪

三步授权链

每一步都会创建一个 加密签名记录 与前一步骤相关联,形成一条牢不可破的链:

User says: "Buy the Flipkart S24 Ultra 256GB"

  ┌─────────────────────────────────────────────────────────────┐
  │ STEP 1: createIntentMandate                                  │
  │                                                              │
  │ What:  Captures user's shopping intent + budget              │
  │ Input: intent="Buy Galaxy S24 Ultra from Flipkart"           │
  │        maxBudget=150000, platform="Flipkart"                 │
  │ Output: IM-A1B2C3D4 (SHA-256 signed, timestamped)           │
  │                                                              │
  │ Why:   Creates verifiable proof that the user                │
  │        authorized this purchase with these constraints       │
  └──────────────────────────┬──────────────────────────────────┘
                             │ links to
  ┌──────────────────────────▼──────────────────────────────────┐
  │ STEP 2: createCartMandate                                    │
  │                                                              │
  │ What:  Locks EXACT product, price, quantity                  │
  │ Input: intentMandateId="IM-A1B2C3D4"                        │
  │        productId="FK-S24U-256", quantity=1                   │
  │ Validates:                                                   │
  │   ✅ Intent mandate exists and is valid                      │
  │   ✅ Product exists and is in stock                          │
  │   ✅ Total (₹127,999) doesn't exceed budget (₹150,000)     │
  │ Output: CM-E5F6G7H8 (SHA-256 signed, linked to IM)          │
  │                                                              │
  │ Why:   "What you see is what you pay for"                   │
  │        Price is locked — can't be changed later             │
  └──────────────────────────┬──────────────────────────────────┘
                             │ links to
  ┌──────────────────────────▼──────────────────────────────────┐
  │ STEP 3: processPayment                                       │
  │                                                              │
  │ What:  Validates full chain + processes payment              │
  │ Input: cartMandateId="CM-E5F6G7H8"                          │
  │        paymentMethod="UPI", name, address                    │
  │ Validates:                                                   │
  │   ✅ Cart mandate exists                                     │
  │   ✅ Intent mandate chain is unbroken                        │
  │   ✅ Payment method is valid (UPI/Card/Wallet/NetBanking)   │
  │ Output: TXN-X1Y2Z3A4B5C6 (COMPLETED, full audit trail)     │
  │                                                              │
  │ Audit Trail:                                                 │
  │   IM-A1B2C3D4 → CM-E5F6G7H8 → TXN-X1Y2Z3A4B5C6            │
  │   (intent)       (cart)         (payment)                    │
  │   All cryptographically signed ✅                            │
  └─────────────────────────────────────────────────────────────┘

AP2输入消毒

小型LLM有时会传递额外的格式化字符(换行符、方框图字符,如 ├─)在授权ID中。这 AP2PaymentTool 包括a sanitizeId() 使用正则表达式提取干净ID的方法(例如。, IM-A1B2C3D4 从 IM-A1B2C3D4\n├─ ...).

AP2对话示例

User: "I want to buy the S24 Ultra from Flipkart, 256GB"

Bot:  🔒 Intent Mandate created: IM-A1B2C3D4
      Intent: "Buy Galaxy S24 Ultra 256GB from Flipkart"
      Budget: ₹150,000 | Signature: 4f8a2b1c... ✅

      🛒 Cart locked: CM-E5F6G7H8
      Product: Samsung Galaxy S24 Ultra (Titanium Gray, 256GB)
      Platform: Flipkart | Price: ₹127,999
      Intent Link: IM-A1B2C3D4 ✅

      Please confirm and tell me:
      • Payment method: UPI / Credit Card / Debit Card
      • Your full name
      • Delivery address with pincode

User: "Confirm. UPI, Harsh Gupta, Bangalore 560001"

Bot:  ✅ PAYMENT SUCCESSFUL (AP2)
      Transaction ID: TXN-X1Y2Z3A4B5C6
      Product: Samsung Galaxy S24 Ultra (256GB)
      Platform: Flipkart | Amount: ₹127,999 | Via: UPI

      🔐 AP2 Audit Trail:
         Intent: IM-A1B2C3D4 ✅
         Cart:   CM-E5F6G7H8 ✅
         Payment: 7c3d9e... ✅

🧠 聊天记忆系统

运作原理

// Sliding window — keeps the last 20 messages per conversation
MessageWindowChatMemory.builder().maxMessages(20).build();
  1. 在每次LLM呼叫之前, MessageChatMemoryAdvisor 加载给定消息的最后20条消息 conversationId
  2. 这些消息作为对话历史记录注入到提示符中
  3. 法学硕士可以“记住”前面讨论的内容
  4. LLM响应后,用户消息和AI响应都会保存到内存中

多回合对话示例

Turn 1: "Compare S24 Ultra prices"     → LLM calls comparePrices, gets data
Turn 2: "Buy the Flipkart one"         → LLM remembers Flipkart had the best price, starts AP2
Turn 3: "UPI, Harsh, Bangalore 560001" → LLM remembers the cart, processes payment

对话隔离

每个浏览器会话都有一个唯一的 conversationId (自动生成的UUID)。不同的用户不共享内存。您可以通过以下方式清除内存:

POST http://localhost:8080/api/clear
{"conversationId": "session-abc123"}

📊 产品数据

所有产品数据 嘲笑 (对电子商务网站没有真正的API调用)。这使得演示具有自包含性和可重复性。

28个产品(7部手机×4个平台)

型号 存储 关键规格
Galaxy S24 Ultra 256GB、512GB 骁龙8代3,200MP,S笔,6.8英寸QHD+
Galaxy S24+ 256GB Exynos 2400,50MP,6.7英寸FHD+
Galaxy S24 128GB、256GB Exynos 2400、50MP、6.2英寸FHD+
Galaxy S23 FE 128GB、256GB Exynos 2200、50MP、6.4英寸FHD+

每个产品字段(27)

类别 字段
身份 id, name, platform, category
变体 color, storage, ram
规格 processor, display, camera, battery, os
定价 price, mrp,自动计算 discountPercent()
优惠 offers, emiOption, exchangeValue, freebie
交付 deliverySpeed, deliveryDate, deliveryCharge, codAvailable, deliveryPartner
信任 seller, rating, reviewCount, warranty, returnPolicy, inStock, stockCount

平台定价和差异

平台 S24 Ultra 256GB 独特优惠 交货 COD
亚马逊 ₹129,999(13%折扣) HDFC/SBI/IICII卡折扣 1-3天 ✅
Flipkart ₹127,999(15%折扣) 安讯士银行₹8K off+超级硬币 第二天! ✅
三星网 ₹131,999(12%折扣) 免费Galaxy Buds2 Pro+三星护理+ 3-5天 ❌
八分音符 ₹129,999(13%折扣) HDFC+Croma奖励,店内兑换 2-3天 ❌

📁 项目结构

spring-ai-mcp-demo/
├── pom.xml                              # Parent POM (multi-module Maven project)
│
├── mcp-server/                          # PORT 8081 — MCP Tool Server
│   ├── pom.xml                         # Server dependencies + maven-compiler-plugin with -parameters
│   └── src/main/java/.../mcpserver/
│       ├── McpServerApplication.java    # Spring Boot entry point
│       ├── McpToolConfig.java          # ★ Explicitly registers all 10 tools via MethodToolCallbackProvider
│       ├── model/
│       │   └── Product.java             # 27-field product model (Lombok @Builder)
│       ├── mock/
│       │   └── MockDataProvider.java    # 28 products, search logic, orders
│       ├── ap2/                         # ★ AP2 Protocol Implementation
│       │   ├── IntentMandate.java       # Step 1: signed user intent (Java record)
│       │   ├── CartMandate.java         # Step 2: signed locked cart (Java record)
│       │   ├── PaymentResult.java       # Step 3: transaction receipt + audit trail (Java record)
│       │   └── PaymentService.java      # Mock PSP with mandate chain validation
│       └── tools/
│           ├── AmazonTool.java          # @Tool: searchAmazon
│           ├── FlipkartTool.java        # @Tool: searchFlipkart
│           ├── SamsungStoreTool.java     # @Tool: searchSamsungStore
│           ├── CromaTool.java           # @Tool: searchCroma
│           ├── PriceComparator.java     # @Tool: comparePrices (searches all 4 platforms)
│           ├── OrderTool.java           # @Tool: getProductDetails, checkOrderStatus
│           ├── AP2PaymentTool.java      # @Tool: createIntentMandate, createCartMandate, processPayment
│           └── ToolOutputHelper.java    # Shared formatting utility for product results
│
└── mcp-client/                          # PORT 8080 — User-facing App
    ├── pom.xml                         # Client dependencies (Spring AI Ollama + MCP Client)
    └── src/main/
        ├── resources/
        │   ├── application.yml          # Ollama + MCP client config
        │   └── static/index.html        # Chat UI (dark theme, suggestion chips)
        └── java/.../mcpclient/
            ├── McpClientApplication.java
            ├── controller/
            │   └── ShoppingController.java  # REST: /api/shop, /api/clear, /api/health
            └── service/
                └── ShoppingAssistant.java   # ChatClient + Memory + System Prompt + MCP Tools

📋 每个文件的作用

MCP客户端(端口8080)

文件 它的作用
ShoppingController.java REST API-接收 /api/shop POST请求,委托 ShoppingAssistant,返回JSON响应。提供 /api/clear (重置对话)和 /api/health (服务器状态)。日志请求计时。
ShoppingAssistant.java 核心服务——构建 ChatClient 具有:(1)系统提示定义助手的角色,(2)MCP工具通过 SyncMcpToolCallbackProvider, (3) MessageWindowChatMemory 对话历史。向Ollama发送提示并返回响应。
application.yml 配置--Ollama URL(localhost:11434),型号(llama3.2:3b),上下文窗口(num-ctx: 8192),MCP客户端SSE连接到 localhost:8081.
index.html 聊天UI——深色主题、打字指示器、建议芯片、markdown渲染。向发送获取请求 /api/shop。自动生成对话ID。

MCP服务器(端口8081)

文件 它的作用
McpToolConfig.java 关键配置 --使用以下命令显式注册所有7个toolbean类 MethodToolCallbackProvider如果没有这个,MCP服务器将暴露0个工具。
Product.java 数据模型——27个字段,涵盖身份、变体、规格、定价、报价、交付、信任。使用龙目岛 @Builder.有 toDetailedCard() 丰富的格式。
MockDataProvider.java 内存数据库——28个产品(7部手机×4个平台),按搜索词索引。模糊搜索匹配:精确→ 子字符串→ 产品名称。还管理订单记录。
ToolOutputHelper.java 共享格式化程序——为所有4个平台工具使用的产品列表生成一致的富文本输出。显示规格、MRP/折扣定价、优惠、交货详情。
AmazonTool.java MCP工具-- searchAmazon(productName) → 搜索亚马逊模拟数据→ 返回格式化的结果。
FlipkartTool.java MCP工具-- searchFlipkart(productName) → Flipkart的模式相同。
SamsungStoreTool.java MCP工具-- searchSamsungStore(productName) → Samsung.com印度。
CromaTool.java MCP工具-- searchCroma(productName) → 克罗玛。
PriceComparator.java MCP工具-- comparePrices(productName) → 搜索所有4个平台,按型号+存储进行分组,按价格排序,显示价格差异和每组的最佳交易。
OrderTool.java MCP工具-- getProductDetails(productId) 返回完整的产品卡。 checkOrderStatus(orderId) 查找订单或AP2交易。
AP2PaymentTool.java MCP工具——3个AP2工具: createIntentMandate, createCartMandate, processPayment。包括 sanitizeId() 以处理授权ID中的LLM格式化工件。
IntentMandate.java AP2记录——捕获用户意图(查询、预算、平台)。生成模拟SHA-256签名。不可变Java记录。
CartMandate.java AP2记录——锁定产品/价格/数量,链接到意向授权。SHA-256签名。根据意图验证预算。
PaymentResult.java AP2记录——具有完整审计跟踪的交易收据(意图→ Cart → 付款签名)。
PaymentService.java 模拟支付服务提供商(PSP)——管理授权商店(ConcurrentHashMap),在每一步验证链的完整性,处理付款。记录AP2流的每一步。

🚀 入门指南

先决条件

  1. Java 17+ --检查: java -version
  2. 奥拉玛 --从以下位置安装 ollama.com

设置和运行

# 1. Install the LLM model (2GB download, one-time)
ollama pull llama3.2:3b

# 2. Make sure Ollama is running
ollama serve

# 3. Clone the project
git clone <repo-url>
cd spring-ai-mcp-demo

# 4. Start the MCP Server (port 8081) — opens a new terminal
cd mcp-server && ../mvnw spring-boot:run

# 5. Start the MCP Client (port 8080) — in another terminal
cd mcp-client && ../mvnw spring-boot:run

# 6. Open the chat UI in your browser
open http://localhost:8080

验证它是否正常工作

您应该看到这些日志:

MCP服务器:

🔧 [CONFIG] Registering MCP tools...
   → AmazonTool: searchAmazon
   → FlipkartTool: searchFlipkart
   ...
   = 10 tools total
Registered tools: 10
Started McpServerApplication on port 8081

MCP客户端:

🔧 [SERVICE] MCP tool provider resolved 10 tool callbacks:
   📌 Tool: spring_ai_mcp_client_s_searchAmazon
   📌 Tool: spring_ai_mcp_client_s_comparePrices
   ...
✅ [SERVICE] ShoppingAssistant ready!
Started McpClientApplication on port 8080

📡 API终点

与助手聊天

curl -X POST http://localhost:8080/api/shop \
  -H "Content-Type: application/json" \
  -d '{"message": "Compare S24 Ultra prices", "conversationId": "test-1"}'

答复:

{
  "response": "Here are the best deals for Samsung Galaxy S24 Ultra:\n\n**Best Price:** ₹127,999 on Flipkart...",
  "conversationId": "test-1"
}

健康检查

curl http://localhost:8080/api/health

清除对话记忆

curl -X POST http://localhost:8080/api/clear \
  -H "Content-Type: application/json" \
  -d '{"conversationId": "test-1"}'

⚙️ 配置参考

客户端配置(mcp-client/src/main/resources/application.yml)

server:
  port: 8080                          # Client web server port

spring:
  application:
    name: mcp-shopping-client

  ai:
    ollama:
      base-url: http://localhost:11434  # Ollama API endpoint
      chat:
        model: llama3.2:3b              # LLM model to use
        options:
          temperature: 0.7              # Creativity level (0=deterministic, 1=creative)
          num-ctx: 8192                 # Context window size (tokens). Must be large
                                        # enough to fit system prompt + 10 tool definitions
                                        # + conversation history + user message

    mcp:
      client:
        type: SYNC                      # Synchronous MCP client
        sse:
          connections:
            s:                          # ★ Connection name — keep SHORT!
              url: http://localhost:8081 # MCP Server URL

⚠️ 重要提示: 连接名称(s)成为发送到LLM的每个工具名称的一部分: spring_ai_mcp_client_{name}_toolName。保持简短(1-3个字符),以便小LLM可以正确处理工具调用。

服务器配置(mcp-server/src/main/resources/application.yml)

server:
  port: 8081                          # MCP Server port

spring:
  application:
    name: mcp-shopping-server
  ai:
    mcp:
      server:
        name: shopping-tools-server   # Server identity in MCP handshake
        version: 1.0.0
        type: SYNC                    # Synchronous MCP server

Maven编译器配置(mcp-server/pom.xml)

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.11.0</version>
    <configuration>
        <parameters>true</parameters>   <!-- ★ Preserves parameter names at runtime -->
    </configuration>                     <!-- Without this, @ToolParam args become arg0, arg1 -->
</plugin>

⚠️ 严重: 这 -parameters 旗帜是必不可少的。没有它,Java会编译掉参数名,Spring AI无法正确映射工具参数,导致 NullPointerException.


🔧 故障排除

常见问题

问题 原因 修复
MCP服务器:“已注册0个工具” @Tool 未自动发现方法 确保 McpToolConfig.java 通过以下方式存在并注册所有工具bean MethodToolCallbackProvider
客户端:404 on/mcp 错误的MCP传输类型 使用 sse 客户端传输 application.yml,不 streamable-http
服务器:工具参数上出现NullPointerException Java擦除参数名称 添加 <parameters>true</parameters> 到 maven-compiler-plugin 在服务器中 pom.xml
LLM输出原始JSON而不是调用工具 工具名称前缀太长 缩短MCP连接名称(例如。, shopping-server → s).还要确保 num-ctx 足够大(8192+)
AP2:“未找到购物车授权” LLM在授权ID中传递了额外的格式化字符 sanitizeId() 在 AP2PaymentTool 处理这个。如果仍然失败,请清除对话记忆并重试
Ollama:“找不到模型” 模型未下载 运行 ollama pull llama3.2:3b
Ollama:连接被拒绝 Ollama不跑 ollama serve

调试提示

  1. 检查服务器日志 --两台服务器都使用表情符号记录每次工具调用,以便于扫描:

    • 🛒 [MCP TOOL] searchAmazon called with: 'S24 Ultra'
    • 🔒 [AP2] Intent Mandate created: IM-A1B2C3D4
    • ✅ [AP2] Payment COMPLETED! Transaction: TXN-...
  2. 检查刀具分辨率 --客户端在启动时记录所有10个工具:

    🔧 [SERVICE] MCP tool provider resolved 10 tool callbacks:
       📌 Tool: spring_ai_mcp_client_s_searchAmazon
    
  3. 直接测试Olama -如果LLM没有调用工具,请测试Ollama的API:

    curl http://localhost:11434/api/chat -d '{
      "model": "llama3.2:3b",
      "messages": [{"role": "user", "content": "Search for S24 Ultra"}],
      "tools": [{"type":"function","function":{"name":"searchAmazon","description":"Search Amazon","parameters":{"type":"object","properties":{"productName":{"type":"string"}}}}}],
      "stream": false
    }'
    

🛡️ 技术栈

组件 技术 为什么
语言 Java 17 Spring生态系统、记录类型、模式匹配
框架 Spring Boot 3.4.1 自动配置、依赖注入、嵌入式Tomcat
人工智能框架 Spring AI 1.0.0-SNAPSHOT 聊天客户端、工具调用、MCP客户端/服务器集成
LLM Ollama(llama3.2:3b) 本地、免费、私有-无API密钥或云依赖性
MCP传输 SSE(服务器发送事件) 通过HTTP进行实时双向通信
支付协议 AP2(代理支付协议) 通过加密授权实现安全的代理主导支付
前端 普通HTML/CSS/JS 单文件,无构建步骤,深色主题聊天UI
构建 Maven(多模块) 服务器+客户端作为单独的模块, -parameters 旗帜
数据 内存模拟数据 4个平台上的28个产品,没有外部数据库

关键依赖关系

<!-- MCP Server -->
spring-boot-starter-web              <!-- REST endpoints + Tomcat -->
spring-ai-starter-mcp-server-webmvc  <!-- MCP server with SSE transport -->
lombok                               <!-- @Builder, @Getter for Product model -->

<!-- MCP Client -->
spring-boot-starter-web              <!-- REST endpoints + Tomcat -->
spring-ai-starter-mcp-client         <!-- MCP client with SSE support -->
spring-ai-ollama-spring-boot-starter <!-- Ollama LLM integration -->

📄 许可证

该项目用于示范和教育目的。