内容
# Spring AI MCP 主机 (Java) — DSM风格的演示
一个忠实的Java/Spring Boot实现MCP架构,根据您的图表:
**一个主机应用程序**(Spring Boot + Anthropic Claude)维护**三个MCP客户端**,每个客户端
连接到一个单独的**MCP服务器**,该服务器封装了一个外部系统。
## 架构
```
┌────────────────────────────────────┐
│ MCP 主机 (端口 8080) │
│ Spring Boot + ChatClient + Claude │
│ │
│ ┌──────────┐ ┌──────────┐ ┌─────┐ │
│ │ 客户端 A │ │ 客户端 B │ │ C │ │
│ └────┬─────┘ └────┬─────┘ └──┬──┘ │
└───────┼────────────┼──────────┼────┘
│ MCP/HTTP │ MCP/HTTP │ MCP/HTTP
┌─────────▼──┐ ┌──────▼──────┐ ┌─▼─────────┐
│ 数据库服务器 │ │ 文件系统服务器 │ │ 网络服务器│
│ 端口 8090 │ │ 端口 8091 │ │ 端口 8092 │
│ │ │ │ │ │
│ 工具: │ │ 工具: │ │ 工具: │
│ - 分发 │ │ - 列出文件 │ │ - 获取网址│
│ - 卷宗 │ │ - 读取文件 │ │ │
│ - 最高商品│ │ - 写入文件 │ │ │
│ - 失败 │ │ │ │ │
└─────┬──────┘ └──────┬──────┘ └─────┬─────┘
│ │ │
┌─────▼──────┐ ┌──────▼──────┐ ┌─────▼─────┐
│ H2/PG │ │ ./sandbox │ │ httpbin, │
│ (事务数据库) │ │ (文件系统) │ │ 维基百科 │
└────────────┘ └─────────────┘ └───────────┘
```
映射到您分享的图表:
- 图表的 **MCP 主机** = `host/` 模块
- 每个 **MCP 客户端** = 由 Spring AI 的 MCP 客户端启动器自动创建,每个 `streamable-http.connections.*` 条目在 `application.yml` 中
- 每个 **MCP 服务器** = `db-server/`、`fs-server/`、`web-server/` 中的一个
- 客户端和服务器之间的传输 = **Streamable HTTP** (现代 MCP 传输,替换 SSE)
## 项目布局
```
mcp-host/
├── pom.xml # 父 POM(BOM 导入)
├── host/ # MCP 主机应用程序
│ └── src/main/...
├── db-server/ # MCP 服务器:事务数据库
│ └── src/main/...
├── fs-server/ # MCP 服务器:沙箱文件系统
│ └── src/main/...
├── web-server/ # MCP 服务器:网络获取(允许列出)
│ └── src/main/...
└── scripts/
├── start-all.sh
└── stop-all.sh
```
## 先决条件
- Java 21
- Maven 3.9+
- Anthropic API 密钥(或交换 LLM - 参见下面的“切换 LLM 提供商”)
## 快速入门
```bash
# 1. 设置您的 API 密钥
export ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxx
# 2. 构建所有内容
mvn -DskipTests clean package
# 3. 启动所有四个服务
./scripts/start-all.sh
# 4. 提出需要数据库的问题
curl 'http://localhost:8080/chat?q=How+many+CHECKING+transactions+failed+enrichment%3F'
# 5. 提出需要文件系统的问题
curl 'http://localhost:8080/chat?q=What+does+the+vendor-notes.txt+file+say+about+performance+targets%3F'
# 6. 提出结合多个源的问题
curl 'http://localhost:8080/chat?q=Compare+the+actual+vendor+primacy+rate+for+CHECKING+with+the+target+in+vendor-notes.txt'
# 7. 停止所有内容
./scripts/stop-all.sh
```
## 接线工作原理(大多数教程省略的部分)
查看 `host/src/main/resources/application.yml`:
```yaml
spring:
ai:
mcp:
client:
streamable-http:
connections:
transaction-server: { url: http://localhost:8090 }
filesystem-server: { url: http://localhost:8091 }
web-server: { url: http://localhost:8092 }
toolcallback:
enabled: true
```
就是这样。`spring-ai-starter-mcp-client` 依赖项读取这三个连接,
为每个条目创建一个 MCP 客户端,在启动时调用每个服务器的 `tools/list` 端点,
并将所有发现的工具聚合到一个 `ToolCallbackProvider` Bean 中。主机的 `ChatClient` 将它们全部附加,
因此 LLM 看到一个统一的工具调色板。
当您询问“有多少 CHECKING 交易失败了增强?”时,Claude:
1. 查看所有可用的工具及其描述
2. 从交易服务器中选择 `getFailedEnrichmentCounts`
3. Spring AI 的 MCP 客户端运行时通过 HTTP 调用它
4. 结果流回 LLM,LLM 编写一个自然语言答案
## 尝试(以及每个尝试的重要性)
| 问题 | 教什么 |
|----------|----------------|
| “最近 7 天内我们有多少 CHECKING 交易?” | 通过描述匹配选择工具 |
| “最近 30 天内所有账户类型的总交易量是多少?” | LLM 多次调用同一个工具,参数不同 |
| “读取 vendor-notes.txt 文件并总结延迟目标” | 跨服务器:文件系统工具独立使用 |
| “比较我们的实际 Spade 成功率与 vendor-notes.txt 中的目标” | 跨服务器推理:DB 工具 + FS 工具组合 |
| “获取 https://httpbin.org/json 并告诉我有什么” | 带有允许列表的 Web 工具 |
| “获取 https://evil.com/x” | 允许列表拒绝 - 看到防护栏在行动 |
## 切换 LLM 提供商
MCP 架构是 LLM 无关的。要将 Anthropic 替换为 OpenAI:
```xml
<!-- 在 host/pom.xml 中,将 anthropic 依赖替换为: -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
```
```yaml
# 在 host/application.yml 中,将 anthropic 配置替换为:
spring.ai.openai.api-key: ${OPENAI_API_KEY}
spring.ai.openai.chat.options.model: gpt-4o
```
或使用 Ollama 进行完全本地推理 - 相同的模式。**您更改一个依赖项
和几行配置。MCP 服务器不会更改。** 这就是 MCP 的全部内容。
## 生产强化检查清单
这是一个学习项目。在任何类似生产环境之前:
1. **每个服务器都进行身份验证。** 在每个 MCP 服务器前放置 OAuth2 / mTLS / API 密钥。Spring AI 1.1+ 内置了 MCP 安全支持。
2. **工具输入验证。** LLM 控制工具参数。像用户输入一样在服务器端验证它们 - 因为它们实际上是。
3. **审计日志记录。** 记录每个工具调用的调用者身份、参数和结果大小。在受监管的环境中,这是不容商量的。
4. **每个工具的速率限制。** 一个混乱的 LLM 可以在循环中调用一个工具。限制它。
5. **工具输出的 PII 屏蔽。** 重用现有的 `@MaskPii` AOP - 将其应用于 `TransactionTools` 方法。
6. **在没有明确的用户确认流程的情况下,不要公开写入工具。** `writeFile` 工具应该需要一个单独的批准步骤在生产环境中。
7. **网络出口控制。** 网络服务器的允许列表是一个起点,
不是真正的控制。强制通过银行的出口代理进行。
## 这与您的 DSM 2.0 工作如何映射
`db-server` 故意按照 DSM 2.0 建模:
- 模式镜像您的丰富输出(account_type、vendor、status)
- 工具镜像您已经在 Datadog 仪表板上运行的查询(vendor primacy 分布、失败的丰富计数)
- vendor-notes 文件镜像了当前存储在 Confluence 中的操作上下文
自然的下一步是将 `db-server` 指向用于丰富路由规则的实际 Postgres 模式。
MCP 服务器模式意味着一个由 LLM 驱动的 Slack 机器人可以回答类似“今天我们的 Spade 成功率按账户类型划分是多少?”的工程问题,而无需任何人编写 SQL。