Skip to content

Commit 22a4a30

Browse files
committed
更新README
1 parent 99517c4 commit 22a4a30

File tree

2 files changed

+81
-131
lines changed

2 files changed

+81
-131
lines changed

framework/fel/java/plugins/tool-mcp-server/README.md

Lines changed: 75 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,38 @@
4242

4343
### 主要方法
4444

45-
| 方法名 | 来源 | 说明 |
46-
|-------------------------------|------------|-------------------------|
47-
| `protocolVersions()` | SDK 原始 | 返回支持的 MCP 协议版本 |
48-
| `setSessionFactory()` | SDK 原始 | 设置会话工厂 |
49-
| `notifyClients()` | SDK 原始 | 广播通知到所有客户端 |
50-
| `closeGracefully()` | SDK 原始 | 优雅关闭传输层 |
51-
| `handleGet()` | **FIT 改造** | 处理 GET 请求(SSE 连接) |
52-
| `handlePost()` | **FIT 改造** | 处理 POST 请求(JSON-RPC 消息) |
53-
| `handleDelete()` | **FIT 改造** | 处理 DELETE 请求(会话删除) |
54-
| `deserializeJsonRpcMessage()` | **FIT 创建** | 反序列化 JSON-RPC 消息 |
45+
| 方法名 | 来源 | 说明 |
46+
| --------------------- | ------------ | ------------------------------- |
47+
| `protocolVersions()` | SDK 原始 | 返回支持的 MCP 协议版本 |
48+
| `setSessionFactory()` | SDK 原始 | 设置会话工厂 |
49+
| `notifyClients()` | SDK 原始 | 广播通知到所有客户端 |
50+
| `closeGracefully()` | SDK 原始 | 优雅关闭传输层 |
51+
| `handleGet()` | **FIT 改造** | 处理 GET 请求(SSE 连接) |
52+
| `handlePost()` | **FIT 改造** | 处理 POST 请求(JSON-RPC 消息) |
53+
| `handleDelete()` | **FIT 改造** | 处理 DELETE 请求(会话删除) |
54+
55+
### 重构后的辅助方法
56+
57+
为提高代码可读性和可维护性,从原本的 `handleGet()``handlePost()``handleDelete()` 方法中抽取了以下辅助方法:
58+
59+
#### 验证请求合法性的方法
60+
61+
| 方法名 | 说明 |
62+
|-------------------------------|----------------------------------------------------------|
63+
| `validateGetAcceptHeaders()` | 验证 GET 请求的 Accept 头,确保包含 `text/event-stream` |
64+
| `validatePostAcceptHeaders()` | 验证 POST 请求的 Accept 头,确保包含 `text/event-stream``application/json` |
65+
| `validateRequestSessionId()` | 验证请求的 `mcp-session-id` 头是否存在,以及对应的会话是否存在 |
66+
67+
#### 根据请求类型调用处理逻辑的方法
68+
69+
| 方法名 | 处理的请求类型 | 说明 |
70+
|--------------------------------|---------|--------------------------------------|
71+
| `handleReplaySseRequest()` | GET | 处理 SSE 消息重放请求,用于断线重连后恢复错过的消息 |
72+
| `handleEstablishSseRequest()` | GET | 处理 SSE 连接建立请求,创建新的持久化 SSE 监听流 |
73+
| `handleInitializeRequest()` | POST | 处理客户端初始化连接请求,创建新的 MCP 会话 |
74+
| `handleJsonRpcResponse()` | POST | 处理 JSON-RPC 响应消息(如 Elicitation 中的客户端响应) |
75+
| `handleJsonRpcNotification()` | POST | 处理 JSON-RPC 通知消息(客户端单向通知) |
76+
| `handleJsonRpcRequest()` | POST | 处理 JSON-RPC 请求消息,返回 SSE 流式响应 |
5577

5678
### 内部类
5779

@@ -97,31 +119,7 @@ public Mono<Void> notifyClients(String method, Object params) {
97119
- 使用 `parallelStream()` 提高效率
98120
- 单个会话失败不影响其他会话
99121

100-
### 4. HTTP 端点处理核心流程
101-
102-
#### a. GET 请求处理流程(原始逻辑)
103-
104-
1. 检查 Accept 头是否包含 `text/event-stream`
105-
2. 验证 `mcp-session-id` 头是否存在
106-
3. 查找对应的会话
107-
4. 检查是否是重放请求(`Last-Event-ID` 头)
108-
5. 建立 SSE 连接或重放消息
109-
110-
#### b. POST 请求处理流程(原始逻辑)
111-
112-
1. 检查 Accept 头
113-
2. 反序列化 JSON-RPC 消息
114-
3. 特殊处理 `initialize` 请求(创建新会话)
115-
4. 处理其他请求(需要已存在的会话)
116-
5. 根据消息类型(Response/Notification/Request)分别处理
117-
118-
#### c. DELETE 请求处理流程(原始逻辑)
119-
120-
1. 检查是否禁用 DELETE
121-
2. 验证 `mcp-session-id`
122-
3. 查找并删除会话
123-
124-
### 5. 关闭逻辑
122+
### 4. 关闭逻辑
125123

126124
```java
127125
public Mono<Void> closeGracefully() {
@@ -135,63 +133,52 @@ public Mono<Void> closeGracefully() {
135133
- 关闭所有活跃会话
136134
- 清理资源
137135

138-
### 6. Keep-Alive 机制
139-
140-
```java
141-
if(keepAliveInterval != null){
142-
this.keepAliveScheduler =KeepAliveScheduler.builder(...)
143-
.initialDelay(keepAliveInterval)
144-
.interval(keepAliveInterval)
145-
.build();
146-
this.keepAliveScheduler.start();
147-
}
148-
```
149-
150-
- 支持可选的 Keep-Alive 调度
151-
152-
## FIT 框架新增/改造逻辑
136+
## FIT 框架改造核心逻辑
153137

154138
以下是为适配 FIT 框架而新增或改造的部分:
155139

156-
### 1. HTTP 类替换(重要改造
140+
### 1. HTTP 端点处理核心流程(核心改造
157141

158-
**原始 SDK(Spring MVC)**:
159-
160-
```java
161-
162-
@GetMapping("/mcp/streamable")
163-
public ResponseEntity<SseEmitter> handleGet(HttpServletRequest request, HttpServletResponse response)
164-
165-
@PostMapping("/mcp/streamable")
166-
public ResponseEntity<?> handlePost(HttpServletRequest request, @RequestBody Map<String, Object> body)
167-
168-
@DeleteMapping("/mcp/streamable")
169-
public ResponseEntity<Void> handleDelete(HttpServletRequest request)
170-
```
171-
172-
**FIT 框架改造后**:
173-
174-
```java
175-
176-
@GetMapping(path = MESSAGE_ENDPOINT)
177-
public Object handleGet(HttpClassicServerRequest request, HttpClassicServerResponse response)
178-
179-
@PostMapping(path = MESSAGE_ENDPOINT)
180-
public Object handlePost(HttpClassicServerRequest request, HttpClassicServerResponse response,
181-
@RequestBody Map<String, Object> requestBody)
182-
183-
@DeleteMapping(path = MESSAGE_ENDPOINT)
184-
public Object handleDelete(HttpClassicServerRequest request, HttpClassicServerResponse response)
185-
```
186-
187-
**关键变化**:
188-
189-
- 使用 FIT 的注解:`@GetMapping`, `@PostMapping`, `@DeleteMapping`
190142
- 请求/响应对象类型变更:
191143
- `HttpServletRequest``HttpClassicServerRequest`
192144
- `HttpServletResponse``HttpClassicServerResponse`
193145
- 返回类型改为通用的 `Object`,支持多种返回形式
194146

147+
#### a. GET 请求处理流程
148+
149+
1. 检查服务器是否正在关闭
150+
2. **调用 `validateGetAcceptHeaders()`** - 验证 Accept 头是否包含 `text/event-stream`
151+
3. **调用 `validateRequestSessionId()`** - 验证 `mcp-session-id` 头是否存在及对应会话是否存在
152+
4. 提取 `transportContext` 上下文
153+
5. 获取会话 ID 和会话对象
154+
6. 检查是否是重放请求(`Last-Event-ID` 头):
155+
- 如果是,**调用 `handleReplaySseRequest()`** - 重放错过的消息
156+
- 如果否,**调用 `handleEstablishSseRequest()`** - 建立新的 SSE 监听流
157+
158+
#### b. POST 请求处理流程
159+
160+
1. 检查服务器是否正在关闭
161+
2. **调用 `validatePostAcceptHeaders()`** - 验证 Accept 头包含 `text/event-stream``application/json`
162+
3. 提取 `transportContext` 上下文
163+
4. 反序列化 JSON-RPC 消息
164+
5. 判断是否为初始化请求(`initialize` 方法):
165+
- 如果是,**调用 `handleInitializeRequest()`** - 创建新会话并返回初始化结果
166+
6. **调用 `validateRequestSessionId()`** - 验证会话(仅非初始化请求)
167+
7. 获取会话 ID 和会话对象
168+
8. 根据消息类型分发处理:
169+
- `JSONRPCResponse`**调用 `handleJsonRpcResponse()`**
170+
- `JSONRPCNotification`**调用 `handleJsonRpcNotification()`**
171+
- `JSONRPCRequest`**调用 `handleJsonRpcRequest()`**
172+
173+
#### c. DELETE 请求处理流程
174+
175+
1. 检查服务器是否正在关闭
176+
2. 检查是否禁用 DELETE 操作
177+
3. **调用 `validateRequestSessionId()`** - 验证 `mcp-session-id` 头及会话存在性
178+
4. 提取 `transportContext` 上下文
179+
5. 获取会话 ID 和会话对象
180+
6. 删除会话并从会话映射表中移除
181+
195182
### 2. SSE 实现改造(核心改造)
196183

197184
**原始 SDK (Spring MVC)**:
@@ -320,55 +307,16 @@ if(!this.response.isActive()){
320307
}
321308
```
322309

323-
### 6. JSON-RPC 消息反序列化
324-
325-
```java
326-
public McpSchema.JSONRPCMessage deserializeJsonRpcMessage(Map<String, Object> map) {
327-
// 根据字段判断消息类型
328-
if (map.containsKey("method") && map.containsKey("id")) {
329-
return jsonMapper.convertValue(map, McpSchema.JSONRPCRequest.class);
330-
} else if (map.containsKey("method") && !map.containsKey("id")) {
331-
return jsonMapper.convertValue(map, McpSchema.JSONRPCNotification.class);
332-
} else if (map.containsKey("result") || map.containsKey("error")) {
333-
return jsonMapper.convertValue(map, McpSchema.JSONRPCResponse.class);
334-
}
335-
throw new IllegalArgumentException(...);
336-
}
337-
```
338-
339-
- 智能识别 JSON-RPC 消息类型
340-
341-
## 代码结构对照表
342-
343-
| 功能模块 | 改造程度 | SDK 原始实现 | FIT 框架实现 |
344-
|------------|----------|----------------------------------------|--------------------------------|
345-
| SSE 实现 | **重大改造** | `SseEmitter` | `Choir<TextEvent>` + `Emitter` |
346-
| HTTP 请求对象 | **重大改造** | `HttpServletRequest` | `HttpClassicServerRequest` |
347-
| HTTP 响应对象 | **重大改造** | `HttpServletResponse` | `HttpClassicServerResponse` |
348-
| HTTP返回类型 | **重大改造** | `ResponseEntity<?>` | `Object` (`Entity`或者`Choir`) |
349-
| Get连接检测 | 新增 || `response.isActive()` |
350-
| 验证工具 | 新增 | 无或其他 | FIT Validation |
351-
| 日志系统 | 轻微改造 | SLF4J | FIT Logger |
352-
| Builder 模式 | 轻微改造 | 原始逻辑 | 类型参数调整 |
353-
| HTTP 注解 | 无变化 | `@GetMapping` (Spring) | `@GetMapping` (FIT) |
354-
| 接口实现 | 无变化 | `McpStreamableServerTransportProvider` | 相同 |
355-
| 会话管理 | 无变化 | 原始逻辑 | 相同 |
356-
| 消息序列化 | 无变化 | 原始逻辑 | 相同 |
357-
| Keep-Alive | 无变化 | 原始逻辑 | 相同 |
358-
359310
## 参考资源
360311

361312
### MCP 协议文档
362313

363314
- MCP 协议规范:[https://spec.modelcontextprotocol.io/](https://spec.modelcontextprotocol.io/)
364315
- MCP SDK GitHub: [https://github.com/modelcontextprotocol/](https://github.com/modelcontextprotocol/)
365316

366-
### FIT 框架文档
367-
368-
- FIT HTTP 模块文档:`docs/framework/fit/java/user-guide-book/04. Web MVC 能力.md`
369-
- FIT 流式功能文档:`docs/framework/fit/java/user-guide-book/10. 流式功能.md`
370-
- FIT 日志文档:`docs/framework/fit/java/user-guide-book/08. 日志.md`
317+
### 更新记录
371318

372-
### 相关类文档
373-
- `Event` 枚举定义:`modelengine.fel.tool.mcp.entity.Event`
374-
- MCP Server 工具其他实现:`framework/fel/java/plugins/tool-mcp-server/`
319+
| 日期 | 更新内容 | 负责人 |
320+
|----------|---------------------------------|-----|
321+
| 2025-11-04 | 初始版本,从 SDK 改造为 FIT 框架实现 | 黄可欣 |
322+
| 2025-11-05 | 代码重构,提取9个辅助方法提高可读性和可维护性 | 黄可欣 |

framework/fel/java/plugins/tool-mcp-server/src/main/java/modelengine/fel/tool/mcp/server/transport/FitMcpStreamableServerTransportProvider.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ private Object validatePostAcceptHeaders(HttpClassicServerRequest request, HttpC
377377
* @param request The incoming {@link HttpClassicServerRequest} containing the session ID header
378378
* @param response The {@link HttpClassicServerResponse} to set status code if validation fails
379379
* @return An error {@link Entity} if validation fails (either missing session ID or session not found),
380-
* {@code null} if validation succeeds
380+
* {@code null} if validation succeeds
381381
*/
382382
private Object validateRequestSessionId(HttpClassicServerRequest request, HttpClassicServerResponse response) {
383383
if (!request.headers().contains(HttpHeaders.MCP_SESSION_ID)) {
@@ -484,9 +484,11 @@ public void onFailed(Exception cause) {
484484
*
485485
* @param request The incoming {@link HttpClassicServerRequest}
486486
* @param response The {@link HttpClassicServerResponse} to set session ID and initialization result
487-
* @param jsonrpcRequest The {@link McpSchema.JSONRPCRequest} containing {@link McpSchema.InitializeRequest} parameters
488-
* @return An {@link Entity} containing the {@link McpSchema.JSONRPCResponse} with {@link McpSchema.InitializeResult}
489-
* on success, or an error {@link Entity} with {@link McpError} on failure
487+
* @param jsonrpcRequest The {@link McpSchema.JSONRPCRequest} containing {@link McpSchema.InitializeRequest}
488+
* parameters
489+
* @return An {@link Entity} containing the {@link McpSchema.JSONRPCResponse} with
490+
* {@link McpSchema.InitializeResult}
491+
* on success, or an error {@link Entity} with {@link McpError} on failure
490492
*/
491493
private Object handleInitializeRequest(HttpClassicServerRequest request, HttpClassicServerResponse response,
492494
McpSchema.JSONRPCRequest jsonrpcRequest) {

0 commit comments

Comments
 (0)