使用说明
数字货币管理代理
与MCP(模型上下文协议)集成
作者 Ramanjaneya Reddy S
版本: 1.0.0
堆栈: Java 21·Spring Boot 3.3.7·Spring AI 1.0.0·Azure OpenAI·MCP
目录
1.工程概况
这个项目是 开发就绪的AI Agent 基于Spring Boot构建,可管理 数字货币数据,并通过Azure OpenAI提供人工智能驱动的投资智能。
随后,它被扩展为 MCP(模型上下文协议) --创建了一个开放标准 通过Anthropic-展示代理商作为标准化、可发现的API的能力 任何兼容MCP的AI客户端都可以连接和使用。
系统做什么
- 在数据库中存储和管理数字货币数据(价格、市值、时间戳)
- 为货币管理提供完整的CRUD REST API
- 通过Azure OpenAI GPT提供三种基于AI的分析功能:
- 个别货币投资分析
- 整个投资组合的市场趋势预测
- 投资组合优化建议
- 将所有AI功能公开为 MCP工具 --允许克劳德桌面, 其他AI代理和IDE插件以编程方式调用它们
为什么MCP很重要
在MCP之前,每个AI集成都需要双方的自定义代码。 MCP对合同进行标准化:
Without MCP: Agent A <--custom code--> Agent B <--different custom code--> Agent C
With MCP: Agent A <--MCP protocol--> Agent B <--MCP protocol--> Agent C
这与REST为web服务所做的转变相同——一种通用协议 每个参与者都在发言,而不是到处定制集成。
屏幕截图:
2.技术栈
| 层 | 技术 | 版本 | 目的 |
|---|---|---|---|
| 语言 | Java | 21 | 主要语言 |
| 框架 | Spring Boot | 3.3.7 | 应用框架 |
| AI框架 | Spring AI | 1.0.0 | MCP服务器,工具注册 |
| LLM提供商 | Azure OpenAI(GPT) | SDK 1.0.0-beta13 | 人工智能分析和预测 |
| HTTP客户端 | OkHttp(通过azure core HTTP OkHttp) | 由BOM管理 | 阻止HTTP,无Netty冲突 |
| 持久性 | Spring Data JPA | 由Boot管理 | ORM和存储库层 |
| 数据库 | H2(内存中) | 由Boot管理 | 开发数据库 |
| 验证 | 雅加达验证 | 由Boot管理 | 请求验证 |
| 构建 | Maven | 3.x | 构建和依赖关系管理 |
| 协议 | MCP over SSE | 1.0.0 | AI工具互操作性 |
密钥依赖设计决策——Netty上的OkHttp
Azure OpenAI SDK默认使用Netty进行HTTP传输。Spring AI MCP服务器 还使用Reactor Netty。当两者都在类路径上时,它们共享一个Netty事件 跨不兼容的线程上下文循环注册表(Spring MVC servlet线程vs 反应堆NIO线程),导致运行时失败。
解决方案: 排除 azure-core-http-netty 和使用 azure-core-http-okhttp
相反。OkHttp是纯阻塞的,没有事件循环——它在任何
线程,包括Spring MVC的servlet线程。
3.系统架构
高级体系结构
+------------------------------------------------------------------+
| CLIENT LAYER |
| |
| REST Clients MCP Clients |
| (Postman, browser, (Claude Desktop, other Spring AI agents, |
| frontend apps) IDE plugins like Cursor/VS Code) |
+--------+-----------------------+----------------------------------+
| |
| HTTP REST | MCP over SSE (HTTP)
| |
+--------v-----------------------v----------------------------------+
| SPRING BOOT APPLICATION |
| (port 8080) |
| |
| +------------------+ +--------------------------------+ |
| | REST Controllers | | MCP Server Layer | |
| | | | (Spring AI MCP) | |
| | /api/currencies | | GET /sse (connect) | |
| | /api/ai | | POST /mcp/message (tool call) | |
| | /api/mcp/info | | GET /api/mcp/info | |
| +--------+---------+ +---------------+----------------+ |
| | | |
| +--------------------------------+ |
| | |
| +-------------v--------------+ |
| | Service Layer | |
| | | |
| | DigitalCurrencyService | |
| | AzureAiService | |
| | CurrencyMcpTools | |
| +------+-----------+---------+ |
| | | |
| +--------v---+ +---v-----------+ |
| | Repository | | Azure OpenAI | |
| | (JPA) | | Client | |
| +--------+---+ | (OkHttp) | |
| | +---+-----------+ |
| +--------v---+ | |
| | H2 Database| | HTTPS |
| | (in-memory)| | |
| +------------+ +---v---------------------------+ |
| | Azure OpenAI Service (cloud) | |
| | GPT deployment | |
| +-------------------------------+ |
+------------------------------------------------------------------+
包结构
com.azure.digitalcurrency
|
+-- AzureAiCurrencyApplication.java Spring Boot entry point
|
+-- config/
| +-- DataInitializer.java Seeds 5 sample currencies on startup
|
+-- model/
| +-- DigitalCurrency.java JPA entity (id, code, name, value, marketCap)
|
+-- repository/
| +-- DigitalCurrencyRepository.java JPA repository with custom queries
|
+-- service/
| +-- DigitalCurrencyService.java Business logic + orchestration
| +-- AzureAiService.java Azure OpenAI client wrapper
|
+-- controller/
| +-- DigitalCurrencyController.java CRUD REST endpoints (/api/currencies)
| +-- AiAnalysisController.java AI REST endpoints (/api/ai)
| +-- McpInfoController.java MCP info endpoint (/api/mcp/info)
|
+-- mcp/
+-- CurrencyMcpTools.java @Tool definitions — MCP tool implementations
+-- McpServerConfig.java Registers tools with Spring AI MCP server
4.组件设计
4.1数字货币(实体)
核心域对象,映射到 digital_currency 桌子。
| 字段 | 类型 | 约束 | 描述 |
|---|---|---|---|
| id | Long | PK,自动生成 | 内部标识符 |
| currencyCode | String | 唯一,不为空 | 例如“BTC”、“ETH” |
| currencyName | String | 非空 | 例如“比特币” |
| currentValue | BigDecimal | 非空、正、精度(25.2) | 价格(美元) |
| marketCap | BigDecimal | 非空、正、精度(25.2) | 市值(美元) |
| createdAt | LocalDateTime | 持久化时自动 | 创建时间戳 |
| updatedAt | LocalDateTime | 更新时自动 | 上次更新时间戳 |
BigDecimal 故意用于货币价值-- double 和 float
不能精确地表示小数(IEEE 754二进制浮点),
这会导致财务计算中的舍入误差。
4.2数字货币存储库
扩展 JpaRepository<DigitalCurrency, Long> 并补充道:
Optional<DigitalCurrency> findByCurrencyCode(String currencyCode);
List<DigitalCurrency> findByCurrencyNameContainingIgnoreCase(String name);
@Query("SELECT dc FROM DigitalCurrency dc ORDER BY dc.marketCap DESC")
List<DigitalCurrency> findAllOrderByMarketCapDesc();
@Query("SELECT dc FROM DigitalCurrency dc ORDER BY dc.currentValue DESC")
List<DigitalCurrency> findAllOrderByCurrentValueDesc();
Spring Data JPA在运行时根据方法名生成SQL实现 和JPQL注释——不需要样板SQL。
4.3 AzureAiService
封装Azure OpenAI SDK,并提供三种AI操作。 每种方法都遵循相同的模式:
1. Build system message (defines AI persona/role)
2. Build user prompt (injects currency data from DB)
3. Call Azure OpenAI (getChatCompletions with deployment name)
4. Extract response text (choices[0].message.content)
5. Return or handle error with descriptive message
关键设计选择——可配置部署名称:
Azure OpenAI使用部署名称(由用户在Azure门户中设置),
不是型号名称。将其作为财产(azure.openai.deployment-name)
避免了硬编码,并使服务在Azure订阅之间可移植。
4.4数字货币服务
控制器/MCP工具和存储库/AI服务之间的编排层。 责任:
- 所有存储库访问都通过此服务进行(没有来自控制器的直接存储库调用)
- 构造传递给AI提示的数据上下文
- 将AI调用限制在前5种货币,以控制代币使用
4.5数据初始化器
实现 CommandLineRunner --种子5种货币(BTC、ETH、ADA、DOT、SOL)
如果表为空,则在首次启动时使用实际值。这意味着
应用程序在启动后立即可用,无需手动输入数据。
5.MCP集成设计
5.1什么是MCP?
模型上下文协议(MCP)是由Anthropic创建的开放标准 定义AI代理如何在 结构化、可发现的方式。
将其视为AI工具集成的REST标准:
- REST标准化了系统如何通过HTTP公开数据
- MCP规范了AI代理如何向LLM公开可调用工具
5.2本项目的MCP架构
此应用程序充当 MCP服务器。它暴露了任何工具 MCP客户端(Claude Desktop,另一个Spring AI代理,IDE插件)可以 发现并呼叫。
MCP Client MCP Server (this app)
| |
|-- GET /sse --------------------------->| (1) Establish SSE connection
|<-- SSE stream opened ------------------|
| |
|-- POST /mcp/message |
| { method: "tools/list" } ---------->| (2) Discover available tools
|<-- { tools: [...6 tools...] } ---------|
| |
|-- POST /mcp/message |
| { method: "tools/call", |
| name: "analyze_investment", |
| arguments: {currencyCode:"BTC"}} ->| (3) Call a tool
| |
| CurrencyMcpTools.analyzeInvestment("BTC")
| |
| DigitalCurrencyService.getInvestmentAnalysis("BTC")
| |
| AzureAiService.analyzeInvestmentOpportunity(...)
| |
| Azure OpenAI API call (HTTPS)
| |
|<-- { content: "analysis text..." } ----| (4) Return result
5.3@Tool注册的工作原理
Spring AI扫描 CurrencyMcpTools 启动时和每个 @Tool 方法:
- 读取方法名称,
@Tool(name=...),以及@Tool(description=...) - 读取每个带注释的参数
@ToolParam(description=...) - 使用Java反射生成 JSON 模式 对于参数
- 在MCP服务器的工具注册表中注册该工具
当客户来电时 tools/list,Spring AI返回所有注册的工具
包含它们的名称、描述和参数模式——格式为
LLM能够理解并推理决定调用哪个工具。
5.4传输:SSE(服务器发送事件)
MCP支持两种传输方式。此项目使用 基于HTTP的SSE:
| 运输 | 用例 |
|---|---|
| Stdio | 本地过程通信(例如CLI工具) |
| SSE | 基于网络,微服务友好(此处使用) |
选择SSE是因为:
- 通过标准HTTP工作——无需WebSocket升级
- 防火墙/代理友好
- 适用于微服务部署
- Spring Boot现有的HTTP服务器本机处理它
5.5 McpServerConfig
桥接的单一配置类 CurrencyMcpTools 进入
Spring AI MCP机械:
@Bean
public ToolCallbackProvider currencyToolCallbackProvider(CurrencyMcpTools tools) {
return MethodToolCallbackProvider.builder()
.toolObjects(tools)
.build();
}
MethodToolCallbackProvider 使用反射来扫描经过的物体,
查找所有 @Tool 方法,并注册它们。这是唯一需要的接线--
Spring AI处理其他一切。
6.数据模型
实体关系
+---------------------------+
| digital_currency |
+---------------------------+
| id BIGINT PK |
| currency_code VARCHAR(255) | UNIQUE
| currency_name VARCHAR(255) |
| current_value DECIMAL(25,2)|
| market_cap DECIMAL(25,2)|
| created_at TIMESTAMP |
| updated_at TIMESTAMP |
+---------------------------+
样本数据(启动时播种)
| 代码 | 名称 | 价值(美元) | 市值(美元) |
|---|---|---|---|
| BTC | 比特币 | 45000.00美元 | 850000000000美元 |
| ETH | 以太坊 | 3200.00美元 | 385000000美元 |
| SOL | 索拉纳 | 180.00美元 | 550000000美元 |
| ADA | 卡尔达诺 | 1.25美元 | 420亿美元 |
| DOT | 波尔卡多特 | 25.50美元 | 250亿美元 |
7.API参考
货币CRUD端点
| 方法 | URL | 描述 | 响应 |
|---|---|---|---|
| 得到 | /api/currencies |
列出所有货币 | 200+数组 |
| 得到 | /api/currencies/{id} |
按数据库ID获取 | 200/404 |
| 得到 | /api/currencies/code/{code} |
按货币代码获取 | 200/404 |
| 得到 | /api/currencies/search?name=bit |
按名称搜索(不区分大小写) | 200+数组 |
| 得到 | /api/currencies/top-by-market-cap |
所有货币,按市值desc | 200+数组排序 |
| 得到 | /api/currencies/top-by-value |
所有货币,按价格降序排序 | 200+数组 |
| 职位 | /api/currencies |
创建新货币 | 201/400 |
| PUT | /api/currencies/{id} |
更新现有货币 | 200/404 |
| 删除 | /api/currencies/{id} |
删除货币 | 204/404 |
POST/PUT请求体:
{
"currencyCode": "BTC",
"currencyName": "Bitcoin",
"currentValue": 45000.00,
"marketCap": 850000000000
}
AI分析端点
| 方法 | URL | 描述 |
|---|---|---|
| 得到 | /api/ai/analysis/{currencyCode} |
一种货币的人工智能投资分析 |
| 得到 | /api/ai/market-predictions |
所有货币的AI市场趋势预测 |
| 得到 | /api/ai/portfolio-optimization |
人工智能投资组合优化建议 |
示例响应--/api/ai/analysis/BTC:
{
"currencyCode": "BTC",
"analysis": "Bitcoin (BTC) Analysis:\n\n1) Market Trends: Bitcoin continues to..."
}
MCP信息端点
| 方法 | URL | 描述 |
|---|---|---|
| 得到 | /api/mcp/info |
返回MCP服务器详细信息和工具列表 |
MCP协议端点(由MCP客户端自动使用)
| 方法 | URL | 描述 |
|---|---|---|
| 得到 | /sse |
MCP客户端的SSE连接端点 |
| 职位 | /mcp/message |
MCP JSON-RPC消息处理程序 |
8.MCP工具参考
所有六个工具都通过MCP公开,并可由任何MCP客户端调用。
分析投资
说明: 为单一货币生成人工智能驱动的投资分析。
参数: currencyCode (字符串)--例如“BTC”、“ETH”、“SOL”
退货: JSON格式 currencyCode 和 analysis 领域
AI内容包括: 市场趋势、风险评估、投资建议、潜在回报、时间范围
预测市场趋势
说明: 数据库中所有货币的AI市场趋势预测。
参数: 无
退货: JSON格式 predictions 领域
AI内容包括: 短期(1-3个月)展望、中期(3-12个月)前景、价格影响因素、风险因素
优化投资组合
说明: 基于所有跟踪货币的AI投资组合优化建议。
参数: 无
退货: JSON格式 optimization 领域
AI内容包括: 资产配置、多元化战略、风险管理、再平衡频率
get_current数据
说明: 从数据库中检索货币的原始存储数据。
参数: currencyCode (字符串)
退货: JSON,包含代码、名称、当前值、市值、更新时间
list_货币
说明: 按市值顺序列出所有跟踪的货币。
参数: 无
退货: 带计数的JSON货币数组
比较货币
说明: 两种货币的并排AI比较。
参数: currencyCodeA (字符串), currencyCodeB (字符串)
退货: JSON,包含货币数据对象和 aiComparison 分析
9.请求流程图
流程1:直接REST调用——GET/api/ai/分析/BTC
Client
|
| GET /api/ai/analysis/BTC
v
AiAnalysisController.getInvestmentAnalysis("BTC")
|
v
DigitalCurrencyService.getInvestmentAnalysis("BTC")
|
+-- DigitalCurrencyRepository.findByCurrencyCode("BTC")
| |
| v
| H2 Database
| |
| Returns: DigitalCurrency{BTC, Bitcoin, 45000, 850B}
|
+-- AzureAiService.analyzeInvestmentOpportunity("BTC", "Bitcoin", 45000, 850B)
|
+-- Build ChatRequestMessages (system + user prompt with data)
|
+-- OpenAIClient.getChatCompletions(deploymentName, options)
|
| HTTPS POST (OkHttp blocking call)
v
Azure OpenAI API
|
Returns: ChatCompletions
|
Extract choices[0].message.content
|
Return analysis string
|
v
ResponseEntity { "currencyCode": "BTC", "analysis": "..." }
|
v
Client receives JSON response
流程2:MCP工具调用——通过Claude Desktop进行分析投资
Claude Desktop (MCP Client)
|
| User types: "Analyse Bitcoin from my database"
| LLM decides: call analyze_investment tool
|
| POST /mcp/message
| { "method": "tools/call",
| "params": { "name": "analyze_investment",
| "arguments": { "currencyCode": "BTC" } } }
v
Spring AI MCP Server
|
+-- Looks up registered tool "analyze_investment"
+-- Finds: CurrencyMcpTools.analyzeInvestment(String)
+-- Calls: currencyMcpTools.analyzeInvestment("BTC")
|
v
CurrencyMcpTools.analyzeInvestment("BTC")
|
v
DigitalCurrencyService.getInvestmentAnalysis("BTC")
| [same as Flow 1 from here]
v
AzureAiService → Azure OpenAI API
|
v
Returns analysis JSON string
|
v
Spring AI MCP Server wraps result in MCP response format
|
v
Claude Desktop receives result
|
v
Claude presents analysis to user in natural language
10.配置指南
所有配置都在 src/main/resources/application.properties.
必需--Azure OpenAI凭据
# Your Azure OpenAI resource endpoint (must end with /)
azure.openai.endpoint=https://YOUR-RESOURCE-NAME.openai.azure.com/
# API key from Azure Portal > Your OpenAI resource > Keys and Endpoint
azure.openai.api-key=YOUR_API_KEY_HERE
# The DEPLOYMENT NAME from Azure OpenAI Studio > Deployments
# This is the name YOU gave your deployment — NOT the model name
# e.g. if you named your deployment "gpt-35-turbo", use that exactly
azure.openai.deployment-name=YOUR_DEPLOYMENT_NAME
如何查找部署名称
- 首选https://oai.azure.com(Azure OpenAI工作室)
- 选择您的资源
- 点击 部署 在左侧菜单中
- 复制中的值 部署名称 列(不是模型列)
MCP服务器配置
spring.ai.mcp.server.enabled=true
spring.ai.mcp.server.name=digital-currency-agent
spring.ai.mcp.server.version=1.0.0
spring.ai.mcp.server.transport=SSE
数据库配置(H2——开发)
spring.datasource.url=jdbc:h2:mem:digitalcurrency
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
访问H2控制台http://localhost:8080/h2-控制台
JDBC网址: jdbc:h2:mem:digitalcurrency |用户名: sa |密码:(空)
11.项目运行
先决条件
- Java 21+
- Maven 3.6+
- 已部署GPT模型的Azure OpenAI资源
步骤
# 1. Clone or extract the project
cd cd digitalcurrency-mcp-agent
# 2. Set your Azure credentials in:
# src/main/resources/application.properties
# 3. Build
mvn clean install
# 4. Run
mvn spring-boot:run
验证它是否正在运行
# Should return list of 5 seeded currencies
curl http://localhost:8080/api/currencies
# Should return AI market predictions
curl http://localhost:8080/api/ai/market-predictions
# Should return MCP server info and tool list
curl http://localhost:8080/api/mcp/info
12.连接MCP客户端
克劳德桌面版
编辑(或创建)Claude Desktop配置文件:
- 雨衣:
~/Library/Application Support/Claude/claude_desktop_config.json - 窗户:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"digital-currency-agent": {
"transport": "sse",
"url": "http://localhost:8080/sse"
}
}
}
重新启动克劳德桌面。工具图标(🔧) 将显示6个可用工具。
然后你可以自然地问克劳德:
- “我的货币的市场预测是什么?”
- “从我的数据库对比比特币和以太坊”
- “我应该根据我的数据投资Solana吗?”
Claude将调用相应的工具,从Spring Boot中获取响应 代理,并以对话的方式呈现。
另一个Spring AI代理
将此添加到其他代理的 application.yml:
spring:
ai:
mcp:
client:
enabled: true
toolcallback:
enabled: true
sse:
connections:
digital-currency:
url: http://localhost:8080
Spring AI将自动发现并注册该代理LLM的所有6个工具。
13.工程决策和问题解决
在开发过程中解决了三个真正的工程挑战:
问题1-Java类型推理失败(编译错误)
错误:
incompatible types: Map<String, Object & Serializable & Comparable<?>>
cannot be converted to Map<String, Object>
原因: Map.of() 使用混合值类型(String+BigDecimal)会导致Java
类型推断,以生成太窄而无法分配的交集类型
Map<String, Object>.
解决方案: 替换 Map.of() 随着 new HashMap<>() +明确的 put() 电话
无论不同类型的值混合在哪里。 HashMap 没有类型推理
在建设中——它总是 HashMap<String, Object>.
问题2-Netty事件循环冲突(运行时错误)
错误:
channel not registered to an event loop
原因: Azure OpenAI SDK默认使用Netty进行HTTP传输。
MCP服务器依赖关系(spring-ai-starter-mcp-server-webmvc)也
将Reactor Netty拉到类路径中。两个Netty环境共享
全局事件循环注册表,但在不兼容的线程上下文中运行--
Spring MVC的servlet线程与Reactor的NIO线程。第一次通话
靠运气成功;来自错误线程上下文的后续调用失败。
解决方案: 两部分修复:
- 排除
azure-core-http-netty中的Azure AI依赖关系pom.xml - 添加
azure-core-http-okhttp并显式配置客户端:OkHttp是纯阻塞的——没有事件循环,没有线程上下文冲突。.httpClient(new OkHttpAsyncHttpClientBuilder().build())
问题3-Azure OpenAI 500错误
错误:
{ "code": 500, "message": "Internal Server Error" }
原因: 代码正在传递 "gpt-3.5-turbo" 作为模型标识符。
Azure OpenAI不使用OpenAI模型名称——它使用 部署名称
由用户在Azure OpenAI Studio中定义。传递未知名称的结果
在Azure的API的500中。
解决方案:
- 将部署名称设置为可配置属性:
azure.openai.deployment-name - 为每个HTTP状态码(401、404、500)添加了特定的错误消息 未来的配置错误可立即诊断
14.未来路线图
短期
- PostgreSQL --将H2替换为用于生产的持久数据库
- 实时价格 -集成CoinGecko或CoinMarketCap API以获取 实时价格和按计划自动更新数据库
- Spring Security -添加API密钥身份验证以保护终结点
中期
- 流媒体响应 -使用Azure OpenAI流API进行AI分析 逐令牌流式传输回客户端令牌,而不是等待完整响应
- 对话记忆 --使用Spring AI
ChatMemory保持上下文 在一个会话中跨越多个问题 - 其他MCP工具 —
update_price,add_currency,set_price_alert
长期
- 多代理架构 --将此代理作为工具提供程序连接到 高级编排器代理,可以将货币数据与新闻提要相结合, 监管警报和宏观经济指标
- MCP资源风险 --将货币数据库作为MCP资源公开 (不仅仅是工具),允许客户订阅价格变动通知
基于Spring Boot 3.3.7构建·Spring AI 1.0.0·Azure OpenAI·MCP