localsbnb-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -0
- package/dist/auth/apiKeyManager.d.ts +61 -0
- package/dist/auth/apiKeyManager.d.ts.map +1 -0
- package/dist/auth/apiKeyManager.js +121 -0
- package/dist/auth/apiKeyManager.js.map +1 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/permissionChecker.d.ts +10 -0
- package/dist/auth/permissionChecker.d.ts.map +1 -0
- package/dist/auth/permissionChecker.js +45 -0
- package/dist/auth/permissionChecker.js.map +1 -0
- package/dist/client/cacheManager.d.ts +24 -0
- package/dist/client/cacheManager.d.ts.map +1 -0
- package/dist/client/cacheManager.js +64 -0
- package/dist/client/cacheManager.js.map +1 -0
- package/dist/client/httpClient.d.ts +12 -0
- package/dist/client/httpClient.d.ts.map +1 -0
- package/dist/client/httpClient.js +121 -0
- package/dist/client/httpClient.js.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/retryHandler.d.ts +18 -0
- package/dist/client/retryHandler.d.ts.map +1 -0
- package/dist/client/retryHandler.js +68 -0
- package/dist/client/retryHandler.js.map +1 -0
- package/dist/config/index.d.ts +24 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +39 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/tools.d.ts +7 -0
- package/dist/config/tools.d.ts.map +1 -0
- package/dist/config/tools.js +159 -0
- package/dist/config/tools.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/logs/combined.log +30 -0
- package/dist/logs/error.log +0 -0
- package/dist/package.json +64 -0
- package/dist/run.cjs +19 -0
- package/dist/run.sh +3 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +129 -0
- package/dist/server.js.map +1 -0
- package/dist/start.mjs +34 -0
- package/dist/tools/channels/getChannelDetails.d.ts +3 -0
- package/dist/tools/channels/getChannelDetails.d.ts.map +1 -0
- package/dist/tools/channels/getChannelDetails.js +30 -0
- package/dist/tools/channels/getChannelDetails.js.map +1 -0
- package/dist/tools/channels/index.d.ts +1 -0
- package/dist/tools/channels/index.d.ts.map +1 -0
- package/dist/tools/channels/index.js +6 -0
- package/dist/tools/channels/index.js.map +1 -0
- package/dist/tools/channels/listChannels.d.ts +3 -0
- package/dist/tools/channels/listChannels.d.ts.map +1 -0
- package/dist/tools/channels/listChannels.js +29 -0
- package/dist/tools/channels/listChannels.js.map +1 -0
- package/dist/tools/finance/analyzeRevenue.d.ts +3 -0
- package/dist/tools/finance/analyzeRevenue.d.ts.map +1 -0
- package/dist/tools/finance/analyzeRevenue.js +30 -0
- package/dist/tools/finance/analyzeRevenue.js.map +1 -0
- package/dist/tools/finance/index.d.ts +2 -0
- package/dist/tools/finance/index.d.ts.map +1 -0
- package/dist/tools/finance/index.js +8 -0
- package/dist/tools/finance/index.js.map +1 -0
- package/dist/tools/finance/queryFinancialData.d.ts +3 -0
- package/dist/tools/finance/queryFinancialData.d.ts.map +1 -0
- package/dist/tools/finance/queryFinancialData.js +30 -0
- package/dist/tools/finance/queryFinancialData.js.map +1 -0
- package/dist/tools/finance/queryOperationalData.d.ts +3 -0
- package/dist/tools/finance/queryOperationalData.d.ts.map +1 -0
- package/dist/tools/finance/queryOperationalData.js +30 -0
- package/dist/tools/finance/queryOperationalData.js.map +1 -0
- package/dist/tools/finance/queryOperationalDataV2.d.ts +3 -0
- package/dist/tools/finance/queryOperationalDataV2.d.ts.map +1 -0
- package/dist/tools/finance/queryOperationalDataV2.js +125 -0
- package/dist/tools/finance/queryOperationalDataV2.js.map +1 -0
- package/dist/tools/orders/cancelOrder.d.ts +3 -0
- package/dist/tools/orders/cancelOrder.d.ts.map +1 -0
- package/dist/tools/orders/cancelOrder.js +27 -0
- package/dist/tools/orders/cancelOrder.js.map +1 -0
- package/dist/tools/orders/getOrderDetails.d.ts +3 -0
- package/dist/tools/orders/getOrderDetails.d.ts.map +1 -0
- package/dist/tools/orders/getOrderDetails.js +23 -0
- package/dist/tools/orders/getOrderDetails.js.map +1 -0
- package/dist/tools/orders/getOrderDetailsV2.d.ts +3 -0
- package/dist/tools/orders/getOrderDetailsV2.d.ts.map +1 -0
- package/dist/tools/orders/getOrderDetailsV2.js +48 -0
- package/dist/tools/orders/getOrderDetailsV2.js.map +1 -0
- package/dist/tools/orders/index.d.ts +3 -0
- package/dist/tools/orders/index.d.ts.map +1 -0
- package/dist/tools/orders/index.js +12 -0
- package/dist/tools/orders/index.js.map +1 -0
- package/dist/tools/orders/queryOrders.d.ts +3 -0
- package/dist/tools/orders/queryOrders.d.ts.map +1 -0
- package/dist/tools/orders/queryOrders.js +37 -0
- package/dist/tools/orders/queryOrders.js.map +1 -0
- package/dist/tools/orders/queryTodayOrders.d.ts +3 -0
- package/dist/tools/orders/queryTodayOrders.d.ts.map +1 -0
- package/dist/tools/orders/queryTodayOrders.js +159 -0
- package/dist/tools/orders/queryTodayOrders.js.map +1 -0
- package/dist/tools/rooms/batchUpdatePrices.d.ts +3 -0
- package/dist/tools/rooms/batchUpdatePrices.d.ts.map +1 -0
- package/dist/tools/rooms/batchUpdatePrices.js +40 -0
- package/dist/tools/rooms/batchUpdatePrices.js.map +1 -0
- package/dist/tools/rooms/index.d.ts +6 -0
- package/dist/tools/rooms/index.d.ts.map +1 -0
- package/dist/tools/rooms/index.js +7 -0
- package/dist/tools/rooms/index.js.map +1 -0
- package/dist/tools/rooms/queryRoomPrices.d.ts +3 -0
- package/dist/tools/rooms/queryRoomPrices.d.ts.map +1 -0
- package/dist/tools/rooms/queryRoomPrices.js +66 -0
- package/dist/tools/rooms/queryRoomPrices.js.map +1 -0
- package/dist/tools/rooms/queryRoomStatusNew.d.ts +28 -0
- package/dist/tools/rooms/queryRoomStatusNew.d.ts.map +1 -0
- package/dist/tools/rooms/queryRoomStatusNew.js +66 -0
- package/dist/tools/rooms/queryRoomStatusNew.js.map +1 -0
- package/dist/tools/rooms/queryTodayRoomStatus.d.ts +3 -0
- package/dist/tools/rooms/queryTodayRoomStatus.d.ts.map +1 -0
- package/dist/tools/rooms/queryTodayRoomStatus.js +72 -0
- package/dist/tools/rooms/queryTodayRoomStatus.js.map +1 -0
- package/dist/tools/rooms/updateRoomPrice.d.ts +3 -0
- package/dist/tools/rooms/updateRoomPrice.d.ts.map +1 -0
- package/dist/tools/rooms/updateRoomPrice.js +39 -0
- package/dist/tools/rooms/updateRoomPrice.js.map +1 -0
- package/dist/types/api.d.ts +122 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +3 -0
- package/dist/types/api.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mcp.d.ts +41 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +2 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/types/tools.d.ts +93 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +2 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/utils/desensitize.d.ts +32 -0
- package/dist/utils/desensitize.d.ts.map +1 -0
- package/dist/utils/desensitize.js +100 -0
- package/dist/utils/desensitize.js.map +1 -0
- package/dist/utils/errorHandler.d.ts +21 -0
- package/dist/utils/errorHandler.d.ts.map +1 -0
- package/dist/utils/errorHandler.js +137 -0
- package/dist/utils/errorHandler.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +37 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validator.d.ts +273 -0
- package/dist/utils/validator.d.ts.map +1 -0
- package/dist/utils/validator.js +153 -0
- package/dist/utils/validator.js.map +1 -0
- package/mcp.sample.json +12 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# 路客云 AI 助手
|
|
2
|
+
|
|
3
|
+
## 这是什么?
|
|
4
|
+
|
|
5
|
+
路客云 AI 助手让您可以在 **Cursor**、**Claude Desktop**、**ChatGPT** 等 AI 工具中,直接用自然语言操作路客云 SPMS(酒店物业管理系统)。
|
|
6
|
+
|
|
7
|
+
例如,您可以说:
|
|
8
|
+
|
|
9
|
+
- 「查询今天的房态」
|
|
10
|
+
- 「今天有哪些订单?」
|
|
11
|
+
- 「帮我查一下本周的入住率」
|
|
12
|
+
|
|
13
|
+
AI 会帮您调用路客云,并返回结果。
|
|
14
|
+
|
|
15
|
+
## 能做什么?
|
|
16
|
+
|
|
17
|
+
### 订单管理
|
|
18
|
+
- 查询订单列表
|
|
19
|
+
- 查看订单详情
|
|
20
|
+
- 创建订单
|
|
21
|
+
- 办理入住 / 退房
|
|
22
|
+
- 取消订单
|
|
23
|
+
|
|
24
|
+
### 房态管理
|
|
25
|
+
- 查询房态
|
|
26
|
+
- 查询和更新房价
|
|
27
|
+
- 批量更新价格
|
|
28
|
+
|
|
29
|
+
### 数据分析
|
|
30
|
+
- 查询经营数据
|
|
31
|
+
- 查询财务数据
|
|
32
|
+
- 收益分析
|
|
33
|
+
- 入住率相关数据
|
|
34
|
+
|
|
35
|
+
### 渠道管理
|
|
36
|
+
- 查看渠道列表
|
|
37
|
+
- 查看渠道详情
|
|
38
|
+
- 关联或解绑渠道
|
|
39
|
+
|
|
40
|
+
## 如何开始使用?
|
|
41
|
+
|
|
42
|
+
### 第一步:获取配置信息
|
|
43
|
+
|
|
44
|
+
在路客云 SPMS 中获取:
|
|
45
|
+
- **访问令牌**(Access Token)
|
|
46
|
+
- **营地 ID**(Camp ID)
|
|
47
|
+
|
|
48
|
+
### 第二步:配置 AI 工具
|
|
49
|
+
|
|
50
|
+
根据您使用的 AI 工具(Cursor、Claude Desktop、ChatGPT 等),在对应应用中完成 MCP 或 Skill 的配置,填入访问令牌和营地 ID。
|
|
51
|
+
|
|
52
|
+
### 第三步:开始使用
|
|
53
|
+
|
|
54
|
+
在 Cursor 中,可以这样使用:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
@lukeyun-pms 查询今天的房态信息
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
或直接描述您的需求,例如:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
帮我查一下今天有哪些订单需要办理入住
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 使用场景示例
|
|
67
|
+
|
|
68
|
+
| 您可以说 | AI 会帮您 |
|
|
69
|
+
|---------|----------|
|
|
70
|
+
| 今天有几间房是空房? | 查询并展示今日房态 |
|
|
71
|
+
| 本周入住率怎么样? | 统计并展示入住率数据 |
|
|
72
|
+
| 帮我查一下订单号为 XXX 的详情 | 返回该订单的完整信息 |
|
|
73
|
+
| 明天 101 房的价格是多少? | 查询并展示该房型价格 |
|
|
74
|
+
|
|
75
|
+
## 部署方式
|
|
76
|
+
|
|
77
|
+
- **云端使用**:由路客云托管,您只需完成配置即可使用
|
|
78
|
+
- **本地部署**:如需在企业内网使用,可联系技术支持获取本地部署方案
|
|
79
|
+
|
|
80
|
+
## 安全说明
|
|
81
|
+
|
|
82
|
+
- 使用 HTTPS 加密传输
|
|
83
|
+
- 密钥加密存储
|
|
84
|
+
- 支持按接口进行权限控制
|
|
85
|
+
|
|
86
|
+
## 需要帮助?
|
|
87
|
+
|
|
88
|
+
- **技术支持**:support@lukeyun.com
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
**文档版本**:v1.0
|
|
93
|
+
**最后更新**:2024年
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export declare class APIKeyManager {
|
|
2
|
+
private apiKey;
|
|
3
|
+
private scopes;
|
|
4
|
+
private hudsonAccessToken;
|
|
5
|
+
private campId;
|
|
6
|
+
/**
|
|
7
|
+
* 从环境变量加载API密钥
|
|
8
|
+
*/
|
|
9
|
+
loadFromEnv(): void;
|
|
10
|
+
/**
|
|
11
|
+
* 从配置文件加载API密钥
|
|
12
|
+
*/
|
|
13
|
+
loadFromConfig(config: {
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
scopes?: string[];
|
|
16
|
+
hudsonAccessToken?: string;
|
|
17
|
+
campId?: string;
|
|
18
|
+
}): void;
|
|
19
|
+
/**
|
|
20
|
+
* 设置API密钥
|
|
21
|
+
*/
|
|
22
|
+
setAPIKey(apiKey: string, scopes?: string[]): void;
|
|
23
|
+
/**
|
|
24
|
+
* 设置Hudson认证信息
|
|
25
|
+
*/
|
|
26
|
+
setHudsonCredentials(accessToken: string, campId: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* 获取API密钥
|
|
29
|
+
* 如果未配置,返回空字符串(用于仅使用Hudson认证的场景)
|
|
30
|
+
*/
|
|
31
|
+
getAPIKey(): string;
|
|
32
|
+
/**
|
|
33
|
+
* 检查是否配置了API密钥
|
|
34
|
+
*/
|
|
35
|
+
hasAPIKey(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* 检查是否有指定权限
|
|
38
|
+
*/
|
|
39
|
+
hasScope(scope: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* 获取所有权限范围
|
|
42
|
+
*/
|
|
43
|
+
getScopes(): string[];
|
|
44
|
+
/**
|
|
45
|
+
* 检查是否已配置
|
|
46
|
+
*/
|
|
47
|
+
isConfigured(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* 检查Hudson认证是否已配置
|
|
50
|
+
*/
|
|
51
|
+
isHudsonConfigured(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* 获取Hudson访问令牌
|
|
54
|
+
*/
|
|
55
|
+
getHudsonAccessToken(): string;
|
|
56
|
+
/**
|
|
57
|
+
* 获取Camp ID
|
|
58
|
+
*/
|
|
59
|
+
getCampId(): string;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=apiKeyManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiKeyManager.d.ts","sourceRoot":"","sources":["../../src/auth/apiKeyManager.ts"],"names":[],"mappings":"AAEA,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,MAAM,CAAuB;IAErC;;OAEG;IACH,WAAW,IAAI,IAAI;IAsBnB;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI;IAeR;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAMlD;;OAEG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAM/D;;;OAGG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAQhC;;OAEG;IACH,SAAS,IAAI,MAAM,EAAE;IAIrB;;OAEG;IACH,YAAY,IAAI,OAAO;IAIvB;;OAEG;IACH,kBAAkB,IAAI,OAAO;IAI7B;;OAEG;IACH,oBAAoB,IAAI,MAAM;IAO9B;;OAEG;IACH,SAAS,IAAI,MAAM;CAMpB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { logger } from '../utils/logger.js';
|
|
2
|
+
export class APIKeyManager {
|
|
3
|
+
apiKey = null;
|
|
4
|
+
scopes = [];
|
|
5
|
+
hudsonAccessToken = null;
|
|
6
|
+
campId = null;
|
|
7
|
+
/**
|
|
8
|
+
* 从环境变量加载API密钥
|
|
9
|
+
*/
|
|
10
|
+
loadFromEnv() {
|
|
11
|
+
this.apiKey = process.env.LUKEYUN_API_KEY || null;
|
|
12
|
+
const scopesStr = process.env.LUKEYUN_API_SCOPES;
|
|
13
|
+
this.scopes = scopesStr ? scopesStr.split(',').map((s) => s.trim()) : [];
|
|
14
|
+
// 加载应用鉴权信息(APP_SECRET / APP_ID)
|
|
15
|
+
this.hudsonAccessToken = process.env.APP_SECRET || null;
|
|
16
|
+
this.campId = process.env.APP_ID || null;
|
|
17
|
+
if (!this.apiKey) {
|
|
18
|
+
logger.warn('API key not found in environment variables');
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
logger.info('API key loaded from environment', { hasScopes: this.scopes.length > 0 });
|
|
22
|
+
}
|
|
23
|
+
if (!this.hudsonAccessToken || !this.campId) {
|
|
24
|
+
logger.warn('APP_SECRET or APP_ID not found in environment variables');
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
logger.info('Hudson credentials loaded from environment');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 从配置文件加载API密钥
|
|
32
|
+
*/
|
|
33
|
+
loadFromConfig(config) {
|
|
34
|
+
this.apiKey = config.apiKey || null;
|
|
35
|
+
this.scopes = config.scopes || [];
|
|
36
|
+
this.hudsonAccessToken = config.hudsonAccessToken || null;
|
|
37
|
+
this.campId = config.campId || null;
|
|
38
|
+
if (this.apiKey) {
|
|
39
|
+
logger.info('API key loaded from config', { hasScopes: this.scopes.length > 0 });
|
|
40
|
+
}
|
|
41
|
+
if (this.hudsonAccessToken && this.campId) {
|
|
42
|
+
logger.info('Hudson credentials loaded from config');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 设置API密钥
|
|
47
|
+
*/
|
|
48
|
+
setAPIKey(apiKey, scopes) {
|
|
49
|
+
this.apiKey = apiKey;
|
|
50
|
+
this.scopes = scopes || [];
|
|
51
|
+
logger.info('API key set', { hasScopes: this.scopes.length > 0 });
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 设置Hudson认证信息
|
|
55
|
+
*/
|
|
56
|
+
setHudsonCredentials(accessToken, campId) {
|
|
57
|
+
this.hudsonAccessToken = accessToken;
|
|
58
|
+
this.campId = campId;
|
|
59
|
+
logger.info('Hudson credentials set');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 获取API密钥
|
|
63
|
+
* 如果未配置,返回空字符串(用于仅使用Hudson认证的场景)
|
|
64
|
+
*/
|
|
65
|
+
getAPIKey() {
|
|
66
|
+
return this.apiKey || '';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 检查是否配置了API密钥
|
|
70
|
+
*/
|
|
71
|
+
hasAPIKey() {
|
|
72
|
+
return this.apiKey !== null && this.apiKey !== '';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 检查是否有指定权限
|
|
76
|
+
*/
|
|
77
|
+
hasScope(scope) {
|
|
78
|
+
// 如果有 * 权限,则拥有所有权限
|
|
79
|
+
if (this.scopes.includes('*')) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return this.scopes.includes(scope);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 获取所有权限范围
|
|
86
|
+
*/
|
|
87
|
+
getScopes() {
|
|
88
|
+
return [...this.scopes];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 检查是否已配置
|
|
92
|
+
*/
|
|
93
|
+
isConfigured() {
|
|
94
|
+
return this.apiKey !== null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 检查Hudson认证是否已配置
|
|
98
|
+
*/
|
|
99
|
+
isHudsonConfigured() {
|
|
100
|
+
return this.hudsonAccessToken !== null && this.campId !== null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 获取Hudson访问令牌
|
|
104
|
+
*/
|
|
105
|
+
getHudsonAccessToken() {
|
|
106
|
+
if (!this.hudsonAccessToken) {
|
|
107
|
+
throw new Error('APP_SECRET not configured. Please set APP_SECRET environment variable.');
|
|
108
|
+
}
|
|
109
|
+
return this.hudsonAccessToken;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 获取Camp ID
|
|
113
|
+
*/
|
|
114
|
+
getCampId() {
|
|
115
|
+
if (!this.campId) {
|
|
116
|
+
throw new Error('APP_ID not configured. Please set APP_ID environment variable.');
|
|
117
|
+
}
|
|
118
|
+
return this.campId;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=apiKeyManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiKeyManager.js","sourceRoot":"","sources":["../../src/auth/apiKeyManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { APIKeyManager } from './apiKeyManager.js';
|
|
2
|
+
export declare class PermissionChecker {
|
|
3
|
+
private keyManager;
|
|
4
|
+
constructor(keyManager: APIKeyManager);
|
|
5
|
+
/**
|
|
6
|
+
* 检查工具调用权限
|
|
7
|
+
*/
|
|
8
|
+
checkPermission(toolName: string, requiredScopes: string[]): void;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=permissionChecker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionChecker.d.ts","sourceRoot":"","sources":["../../src/auth/permissionChecker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAInD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,UAAU;gBAAV,UAAU,EAAE,aAAa;IAE7C;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,IAAI;CA0ClE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MCPError, ErrorCode } from '../utils/errorHandler.js';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
export class PermissionChecker {
|
|
4
|
+
keyManager;
|
|
5
|
+
constructor(keyManager) {
|
|
6
|
+
this.keyManager = keyManager;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 检查工具调用权限
|
|
10
|
+
*/
|
|
11
|
+
checkPermission(toolName, requiredScopes) {
|
|
12
|
+
if (requiredScopes.length === 0) {
|
|
13
|
+
// 如果没有权限要求,则允许
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// 如果只有Hudson认证(没有API key和权限范围),则允许所有操作
|
|
17
|
+
// 因为Hudson认证本身就包含了权限验证
|
|
18
|
+
if (!this.keyManager.hasAPIKey() && this.keyManager.isHudsonConfigured()) {
|
|
19
|
+
logger.debug('Permission check passed (Hudson auth only)', {
|
|
20
|
+
tool: toolName,
|
|
21
|
+
requiredScopes,
|
|
22
|
+
});
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const hasPermission = requiredScopes.some((scope) => this.keyManager.hasScope(scope));
|
|
26
|
+
if (!hasPermission) {
|
|
27
|
+
const scopes = this.keyManager.getScopes();
|
|
28
|
+
logger.warn('Permission denied', {
|
|
29
|
+
tool: toolName,
|
|
30
|
+
required: requiredScopes,
|
|
31
|
+
current: scopes,
|
|
32
|
+
});
|
|
33
|
+
throw new MCPError(ErrorCode.PERMISSION_DENIED, `权限不足:工具 ${toolName} 需要以下权限之一:${requiredScopes.join(', ')}。当前权限:${scopes.join(', ') || '无'}`, {
|
|
34
|
+
tool: toolName,
|
|
35
|
+
requiredScopes,
|
|
36
|
+
currentScopes: scopes,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
logger.debug('Permission check passed', {
|
|
40
|
+
tool: toolName,
|
|
41
|
+
scopes: requiredScopes,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=permissionChecker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionChecker.js","sourceRoot":"","sources":["../../src/auth/permissionChecker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,OAAO,iBAAiB;IACR;IAApB,YAAoB,UAAyB;QAAzB,eAAU,GAAV,UAAU,CAAe;IAAG,CAAC;IAEjD;;OAEG;IACH,eAAe,CAAC,QAAgB,EAAE,cAAwB;QACxD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,eAAe;YACf,OAAO;QACT,CAAC;QAED,uCAAuC;QACvC,uBAAuB;QACvB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,EAAE,CAAC;YACzE,MAAM,CAAC,KAAK,CAAC,4CAA4C,EAAE;gBACzD,IAAI,EAAE,QAAQ;gBACd,cAAc;aACf,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAEtF,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE;gBAC/B,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,cAAc;gBACxB,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YAEH,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,iBAAiB,EAC3B,WAAW,QAAQ,aAAa,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,EAC5F;gBACE,IAAI,EAAE,QAAQ;gBACd,cAAc;gBACd,aAAa,EAAE,MAAM;aACtB,CACF,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;YACtC,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,cAAc;SACvB,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare class CacheManager {
|
|
2
|
+
private cache;
|
|
3
|
+
/**
|
|
4
|
+
* 获取缓存数据
|
|
5
|
+
*/
|
|
6
|
+
get<T>(key: string): T | null;
|
|
7
|
+
/**
|
|
8
|
+
* 设置缓存数据
|
|
9
|
+
*/
|
|
10
|
+
set<T>(key: string, data: T, ttl?: number): void;
|
|
11
|
+
/**
|
|
12
|
+
* 删除缓存
|
|
13
|
+
*/
|
|
14
|
+
delete(key: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* 清空所有缓存
|
|
17
|
+
*/
|
|
18
|
+
clear(): void;
|
|
19
|
+
/**
|
|
20
|
+
* 生成缓存键
|
|
21
|
+
*/
|
|
22
|
+
static generateKey(prefix: string, params: Record<string, unknown>): string;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=cacheManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cacheManager.d.ts","sourceRoot":"","sources":["../../src/client/cacheManager.ts"],"names":[],"mappings":"AAQA,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAA+C;IAE5D;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAqB7B;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAchD;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;CAO5E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { config } from '../config/index.js';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
export class CacheManager {
|
|
4
|
+
cache = new Map();
|
|
5
|
+
/**
|
|
6
|
+
* 获取缓存数据
|
|
7
|
+
*/
|
|
8
|
+
get(key) {
|
|
9
|
+
if (!config.cache.enabled) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const entry = this.cache.get(key);
|
|
13
|
+
if (!entry) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
// 检查是否过期
|
|
17
|
+
if (Date.now() > entry.expiresAt) {
|
|
18
|
+
this.cache.delete(key);
|
|
19
|
+
logger.debug('Cache expired', { key });
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
logger.debug('Cache hit', { key });
|
|
23
|
+
return entry.data;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 设置缓存数据
|
|
27
|
+
*/
|
|
28
|
+
set(key, data, ttl) {
|
|
29
|
+
if (!config.cache.enabled) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const ttlMs = ttl || config.cache.ttl;
|
|
33
|
+
this.cache.set(key, {
|
|
34
|
+
data,
|
|
35
|
+
expiresAt: Date.now() + ttlMs,
|
|
36
|
+
});
|
|
37
|
+
logger.debug('Cache set', { key, ttl: ttlMs });
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 删除缓存
|
|
41
|
+
*/
|
|
42
|
+
delete(key) {
|
|
43
|
+
this.cache.delete(key);
|
|
44
|
+
logger.debug('Cache deleted', { key });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 清空所有缓存
|
|
48
|
+
*/
|
|
49
|
+
clear() {
|
|
50
|
+
this.cache.clear();
|
|
51
|
+
logger.debug('Cache cleared');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 生成缓存键
|
|
55
|
+
*/
|
|
56
|
+
static generateKey(prefix, params) {
|
|
57
|
+
const sortedParams = Object.keys(params)
|
|
58
|
+
.sort()
|
|
59
|
+
.map((key) => `${key}=${JSON.stringify(params[key])}`)
|
|
60
|
+
.join('&');
|
|
61
|
+
return `${prefix}:${sortedParams}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=cacheManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cacheManager.js","sourceRoot":"","sources":["../../src/client/cacheManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAO5C,MAAM,OAAO,YAAY;IACf,KAAK,GAAqC,IAAI,GAAG,EAAE,CAAC;IAE5D;;OAEG;IACH,GAAG,CAAI,GAAW;QAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,SAAS;QACT,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,IAAS,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,GAAW,EAAE,IAAO,EAAE,GAAY;QACvC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC9B,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,MAAc,EAAE,MAA+B;QAChE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;aACrC,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;aACrD,IAAI,CAAC,GAAG,CAAC,CAAC;QACb,OAAO,GAAG,MAAM,IAAI,YAAY,EAAE,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIClient, RequestConfig } from '../types/mcp.js';
|
|
2
|
+
export declare class HTTPClient implements APIClient {
|
|
3
|
+
private client;
|
|
4
|
+
private apiKey;
|
|
5
|
+
private hudsonAccessToken?;
|
|
6
|
+
private retryHandler;
|
|
7
|
+
constructor(apiKey: string, hudsonAccessToken?: string);
|
|
8
|
+
private setupInterceptors;
|
|
9
|
+
private handleError;
|
|
10
|
+
request<T>(requestConfig: RequestConfig): Promise<T>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=httpClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpClient.d.ts","sourceRoot":"","sources":["../../src/client/httpClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMhE,qBAAa,UAAW,YAAW,SAAS;IAC1C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,YAAY,CAAe;gBAEvB,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM;IAkBtD,OAAO,CAAC,iBAAiB;YAwCX,WAAW;IAoDnB,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC;CAiB3D"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { config } from '../config/index.js';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
import { MCPError, ErrorCode } from '../utils/errorHandler.js';
|
|
5
|
+
import { RetryHandler } from './retryHandler.js';
|
|
6
|
+
export class HTTPClient {
|
|
7
|
+
client;
|
|
8
|
+
apiKey;
|
|
9
|
+
hudsonAccessToken;
|
|
10
|
+
retryHandler;
|
|
11
|
+
constructor(apiKey, hudsonAccessToken) {
|
|
12
|
+
this.apiKey = apiKey;
|
|
13
|
+
this.hudsonAccessToken = hudsonAccessToken;
|
|
14
|
+
this.retryHandler = new RetryHandler(config.retry.maxRetries, config.retry.delay);
|
|
15
|
+
this.client = axios.create({
|
|
16
|
+
baseURL: config.api.baseURL,
|
|
17
|
+
timeout: config.api.timeout,
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
'X-Client-Type': 'mcp',
|
|
21
|
+
'X-Client-Version': process.env.npm_package_version || '1.0.0',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
this.setupInterceptors();
|
|
25
|
+
}
|
|
26
|
+
setupInterceptors() {
|
|
27
|
+
// 请求拦截器:自动注入API密钥和Hudson token
|
|
28
|
+
this.client.interceptors.request.use((config) => {
|
|
29
|
+
// 只有在提供了API key时才添加Authorization header
|
|
30
|
+
if (this.apiKey) {
|
|
31
|
+
config.headers.Authorization = `Bearer ${this.apiKey}`;
|
|
32
|
+
}
|
|
33
|
+
// 如果提供了Hudson token,添加到header
|
|
34
|
+
if (this.hudsonAccessToken) {
|
|
35
|
+
config.headers['hudson-access-token'] = this.hudsonAccessToken;
|
|
36
|
+
}
|
|
37
|
+
logger.debug('API request', {
|
|
38
|
+
method: config.method,
|
|
39
|
+
url: config.url,
|
|
40
|
+
params: config.params,
|
|
41
|
+
});
|
|
42
|
+
return config;
|
|
43
|
+
}, (error) => {
|
|
44
|
+
logger.error('Request interceptor error', error);
|
|
45
|
+
return Promise.reject(error);
|
|
46
|
+
});
|
|
47
|
+
// 响应拦截器:错误处理
|
|
48
|
+
this.client.interceptors.response.use((response) => {
|
|
49
|
+
logger.debug('API response', {
|
|
50
|
+
status: response.status,
|
|
51
|
+
url: response.config.url,
|
|
52
|
+
});
|
|
53
|
+
return response;
|
|
54
|
+
}, async (error) => {
|
|
55
|
+
return this.handleError(error);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async handleError(error) {
|
|
59
|
+
if (error.response) {
|
|
60
|
+
// API返回了错误响应
|
|
61
|
+
const status = error.response.status;
|
|
62
|
+
const data = error.response.data;
|
|
63
|
+
logger.error('API error response', {
|
|
64
|
+
status,
|
|
65
|
+
url: error.config?.url,
|
|
66
|
+
message: data.message,
|
|
67
|
+
});
|
|
68
|
+
switch (status) {
|
|
69
|
+
case 401:
|
|
70
|
+
throw new MCPError(ErrorCode.AUTH_INVALID, 'API密钥无效或已过期', data);
|
|
71
|
+
case 403:
|
|
72
|
+
throw new MCPError(ErrorCode.PERMISSION_DENIED, '权限不足', data);
|
|
73
|
+
case 404:
|
|
74
|
+
throw new MCPError(ErrorCode.API_NOT_FOUND, '资源不存在', data);
|
|
75
|
+
case 429:
|
|
76
|
+
throw new MCPError(ErrorCode.API_RATE_LIMIT, '请求频率过高,请稍后重试', data);
|
|
77
|
+
case 500:
|
|
78
|
+
case 502:
|
|
79
|
+
case 503:
|
|
80
|
+
case 504:
|
|
81
|
+
throw new MCPError(ErrorCode.API_ERROR, '服务器错误,请稍后重试', data);
|
|
82
|
+
default:
|
|
83
|
+
throw new MCPError(ErrorCode.API_ERROR, data.message || `API错误:${status}`, data);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (error.request) {
|
|
87
|
+
// 请求已发出但没有收到响应
|
|
88
|
+
logger.error('API request timeout', {
|
|
89
|
+
url: error.config?.url,
|
|
90
|
+
timeout: config.api.timeout,
|
|
91
|
+
});
|
|
92
|
+
if (error.code === 'ECONNABORTED') {
|
|
93
|
+
throw new MCPError(ErrorCode.API_TIMEOUT, '请求超时,请稍后重试');
|
|
94
|
+
}
|
|
95
|
+
throw new MCPError(ErrorCode.API_ERROR, '网络错误,请检查网络连接');
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// 请求配置错误
|
|
99
|
+
logger.error('Request configuration error', error);
|
|
100
|
+
throw new MCPError(ErrorCode.INTERNAL_ERROR, '请求配置错误');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async request(requestConfig) {
|
|
104
|
+
const axiosConfig = {
|
|
105
|
+
method: requestConfig.method,
|
|
106
|
+
url: requestConfig.url,
|
|
107
|
+
params: requestConfig.params,
|
|
108
|
+
data: requestConfig.data,
|
|
109
|
+
headers: requestConfig.headers,
|
|
110
|
+
};
|
|
111
|
+
try {
|
|
112
|
+
const response = await this.retryHandler.execute(() => this.client.request(axiosConfig));
|
|
113
|
+
return response.data;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
// 错误已在拦截器中处理,直接抛出
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=httpClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpClient.js","sourceRoot":"","sources":["../../src/client/httpClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class RetryHandler {
|
|
2
|
+
private maxRetries;
|
|
3
|
+
private baseDelay;
|
|
4
|
+
constructor(maxRetries?: number, baseDelay?: number);
|
|
5
|
+
/**
|
|
6
|
+
* 执行带重试的请求
|
|
7
|
+
*/
|
|
8
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
9
|
+
/**
|
|
10
|
+
* 判断错误是否可重试
|
|
11
|
+
*/
|
|
12
|
+
private isRetryableError;
|
|
13
|
+
/**
|
|
14
|
+
* 延迟函数
|
|
15
|
+
*/
|
|
16
|
+
private sleep;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=retryHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retryHandler.d.ts","sourceRoot":"","sources":["../../src/client/retryHandler.ts"],"names":[],"mappings":"AAGA,qBAAa,YAAY;IAErB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,SAAS;gBADT,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAa;IAGlC;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAkClD;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd"}
|