@liangshanli/mcp-server-project-standards 1.0.0 → 1.2.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 +57 -5
- package/README.zh-CN.md +61 -5
- package/bin/cli.js +12 -1
- package/package.json +1 -1
- package/src/server-final.js +42 -10
- package/src/utils/api_debug.js +194 -73
package/README.md
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
A MCP (Model Context Protocol) server for project standards management, designed for AI-assisted development to help teams maintain unified development standards and specifications across multiple machines.
|
|
4
4
|
|
|
5
|
+
## 📋 Version Updates
|
|
6
|
+
|
|
7
|
+
### v1.1.0 (2024-12-19)
|
|
8
|
+
|
|
9
|
+
#### 🆕 New Features
|
|
10
|
+
- **API Debug Tool Environment Variable Support**:
|
|
11
|
+
- `API_DEBUG_ALLOWED_METHODS` - Control allowed request methods (default: GET)
|
|
12
|
+
- `API_DEBUG_LOGIN_URL` - Set login API URL (default: /api/login)
|
|
13
|
+
- `API_DEBUG_LOGIN_METHOD` - Set login request method (default: POST)
|
|
14
|
+
- `API_DEBUG_LOGIN_BODY` - Set login request body (default: {"username":"","password":""})
|
|
15
|
+
- `API_DEBUG_LOGIN_DESCRIPTION` - Set login API description (default: Save returned token to common headers in debug tool, field name Authorization, field value Bearer token)
|
|
16
|
+
|
|
17
|
+
#### 🔧 Feature Improvements
|
|
18
|
+
- **Smart Login API Recognition**:
|
|
19
|
+
- Support for full URL and relative path matching
|
|
20
|
+
- Automatic login API recognition using environment variable configuration
|
|
21
|
+
- Non-login APIs strictly follow allowed method restrictions
|
|
22
|
+
|
|
23
|
+
- **Error Handling Optimization**:
|
|
24
|
+
- Only request-related errors are saved to api.json
|
|
25
|
+
- Method validation errors don't pollute execution records
|
|
26
|
+
- More precise error classification and handling
|
|
27
|
+
|
|
28
|
+
- **Dynamic Tool Description**:
|
|
29
|
+
- Display login authentication information based on environment variable configuration
|
|
30
|
+
- Real-time display of allowed request methods and usage instructions
|
|
31
|
+
|
|
32
|
+
#### 🛡️ Security Enhancements
|
|
33
|
+
- **Request Method Restrictions**: Default only allows GET requests to prevent accidental operations
|
|
34
|
+
- **Login API Exception**: Login APIs can use methods configured in environment variables
|
|
35
|
+
- **Flexible Configuration**: Can open more request methods as needed
|
|
36
|
+
|
|
37
|
+
#### 📚 Documentation Updates
|
|
38
|
+
- Added environment variable configuration instructions
|
|
39
|
+
- Updated API debug tool usage guide
|
|
40
|
+
- Improved login authentication flow documentation
|
|
41
|
+
|
|
5
42
|
## 🚀 Core Advantages
|
|
6
43
|
|
|
7
44
|
### 🎯 Solving Multi-Machine Development Chaos
|
|
@@ -73,9 +110,14 @@ The server uses the `./.setting/` directory to store configuration files by defa
|
|
|
73
110
|
|
|
74
111
|
### Environment Variables
|
|
75
112
|
|
|
76
|
-
| Variable | Default | Description |
|
|
77
|
-
|
|
78
|
-
| CONFIG_DIR | ./.setting | Configuration file directory (contains config.json and api.json) |
|
|
113
|
+
| Variable | Default | Description | Example |
|
|
114
|
+
|----------|---------|-------------|---------|
|
|
115
|
+
| CONFIG_DIR | ./.setting | Configuration file directory (contains config.json and api.json) | `export CONFIG_DIR="./config"` |
|
|
116
|
+
| API_DEBUG_ALLOWED_METHODS | GET | Control allowed request methods (supports: GET,POST,PUT,DELETE,PATCH, etc.) | `export API_DEBUG_ALLOWED_METHODS="GET,POST"` |
|
|
117
|
+
| API_DEBUG_LOGIN_URL | /api/login | Set login API URL | `export API_DEBUG_LOGIN_URL="/api/auth/login"` |
|
|
118
|
+
| API_DEBUG_LOGIN_METHOD | POST | Set login request method | `export API_DEBUG_LOGIN_METHOD="POST"` |
|
|
119
|
+
| API_DEBUG_LOGIN_BODY | {"username":"","password":""} | Set login request body | `export API_DEBUG_LOGIN_BODY='{"mobile":"","password":""}'` |
|
|
120
|
+
| API_DEBUG_LOGIN_DESCRIPTION | Save returned token to common headers in debug tool, field name Authorization, field value Bearer token | Set login API description | `export API_DEBUG_LOGIN_DESCRIPTION="User Login API"` |
|
|
79
121
|
|
|
80
122
|
### Configuration Files
|
|
81
123
|
|
|
@@ -166,7 +208,12 @@ npm run dev
|
|
|
166
208
|
"command": "npx",
|
|
167
209
|
"args": ["@liangshanli/mcp-server-project-standards"],
|
|
168
210
|
"env": {
|
|
169
|
-
"CONFIG_DIR": "./.setting"
|
|
211
|
+
"CONFIG_DIR": "./.setting",
|
|
212
|
+
"API_DEBUG_ALLOWED_METHODS": "GET,POST,PUT,DELETE",
|
|
213
|
+
"API_DEBUG_LOGIN_URL": "/api/login",
|
|
214
|
+
"API_DEBUG_LOGIN_METHOD": "POST",
|
|
215
|
+
"API_DEBUG_LOGIN_BODY": "{\"username\":\"\",\"password\":\"\"}",
|
|
216
|
+
"API_DEBUG_LOGIN_DESCRIPTION": "Save returned token to common headers in debug tool, field name Authorization, field value Bearer token"
|
|
170
217
|
}
|
|
171
218
|
}
|
|
172
219
|
}
|
|
@@ -185,7 +232,12 @@ npm run dev
|
|
|
185
232
|
"command": "npx",
|
|
186
233
|
"args": ["@liangshanli/mcp-server-project-standards"],
|
|
187
234
|
"env": {
|
|
188
|
-
"CONFIG_DIR": "./.setting"
|
|
235
|
+
"CONFIG_DIR": "./.setting",
|
|
236
|
+
"API_DEBUG_ALLOWED_METHODS": "GET,POST,PUT,DELETE",
|
|
237
|
+
"API_DEBUG_LOGIN_URL": "/api/login",
|
|
238
|
+
"API_DEBUG_LOGIN_METHOD": "POST",
|
|
239
|
+
"API_DEBUG_LOGIN_BODY": "{\"username\":\"\",\"password\":\"\"}",
|
|
240
|
+
"API_DEBUG_LOGIN_DESCRIPTION": "Save returned token to common headers in debug tool, field name Authorization, field value Bearer token"
|
|
189
241
|
}
|
|
190
242
|
}
|
|
191
243
|
}
|
package/README.zh-CN.md
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
一个基于 MCP(Model Context Protocol)协议的项目标准管理工具,专为 AI 辅助开发而设计,帮助团队在多台机器上保持统一的开发标准和规范。
|
|
4
4
|
|
|
5
|
+
## 📋 版本更新说明
|
|
6
|
+
|
|
7
|
+
### v1.1.0 (2024-12-19)
|
|
8
|
+
|
|
9
|
+
#### 🆕 新增功能
|
|
10
|
+
- **API 调试工具环境变量支持**:
|
|
11
|
+
- `API_DEBUG_ALLOWED_METHODS` - 控制允许的请求方法(默认:GET,支持:GET,POST,PUT,DELETE,PATCH等)
|
|
12
|
+
- `API_DEBUG_LOGIN_URL` - 设置登录接口 URL(默认:/api/login)
|
|
13
|
+
- `API_DEBUG_LOGIN_METHOD` - 设置登录请求方法(默认:POST)
|
|
14
|
+
- `API_DEBUG_LOGIN_BODY` - 设置登录请求体(默认:{"username":"","password":""})
|
|
15
|
+
- `API_DEBUG_LOGIN_DESCRIPTION` - 设置登录接口说明(默认:将返回的token保存到调试工具中的公共header,字段名Authorization,字段值是Bearer token)
|
|
16
|
+
|
|
17
|
+
#### 🔧 功能优化
|
|
18
|
+
- **登录接口智能识别**:
|
|
19
|
+
- 支持完整 URL 和相对路径匹配
|
|
20
|
+
- 自动识别登录接口并使用环境变量配置
|
|
21
|
+
- 非登录接口严格遵循允许的方法限制
|
|
22
|
+
|
|
23
|
+
- **错误处理优化**:
|
|
24
|
+
- 只有请求相关错误才保存到 api.json
|
|
25
|
+
- 方法验证错误不污染执行记录
|
|
26
|
+
- 更精确的错误分类和处理
|
|
27
|
+
|
|
28
|
+
- **工具描述动态显示**:
|
|
29
|
+
- 根据环境变量配置显示登录认证信息
|
|
30
|
+
- 实时显示允许的请求方法和使用说明
|
|
31
|
+
|
|
32
|
+
#### 🛡️ 安全增强
|
|
33
|
+
- **请求方法限制**:默认只允许 GET 请求,防止误操作
|
|
34
|
+
- **登录接口例外**:登录接口可使用环境变量中配置的方法
|
|
35
|
+
- **灵活配置**:可根据需要开放更多请求方法
|
|
36
|
+
|
|
37
|
+
#### 📚 文档更新
|
|
38
|
+
- 添加了环境变量配置说明
|
|
39
|
+
- 更新了 API 调试工具使用指南
|
|
40
|
+
- 完善了登录认证流程文档
|
|
41
|
+
|
|
5
42
|
## 🚀 核心优势
|
|
6
43
|
|
|
7
44
|
### 🎯 解决多机器开发混乱问题
|
|
@@ -73,9 +110,14 @@ npm install
|
|
|
73
110
|
|
|
74
111
|
### 环境变量
|
|
75
112
|
|
|
76
|
-
| 变量名 | 默认值 | 描述 |
|
|
77
|
-
|
|
78
|
-
| CONFIG_DIR | ./.setting | 配置文件目录(包含 config.json 和 api.json) |
|
|
113
|
+
| 变量名 | 默认值 | 描述 | 示例 |
|
|
114
|
+
|--------|--------|------|------|
|
|
115
|
+
| CONFIG_DIR | ./.setting | 配置文件目录(包含 config.json 和 api.json) | `export CONFIG_DIR="./config"` |
|
|
116
|
+
| API_DEBUG_ALLOWED_METHODS | GET | 控制允许的请求方法(支持:GET,POST,PUT,DELETE,PATCH等) | `export API_DEBUG_ALLOWED_METHODS="GET,POST"` |
|
|
117
|
+
| API_DEBUG_LOGIN_URL | /api/login | 设置登录接口 URL | `export API_DEBUG_LOGIN_URL="/api/auth/login"` |
|
|
118
|
+
| API_DEBUG_LOGIN_METHOD | POST | 设置登录请求方法 | `export API_DEBUG_LOGIN_METHOD="POST"` |
|
|
119
|
+
| API_DEBUG_LOGIN_BODY | {"username":"","password":""} | 设置登录请求体 | `export API_DEBUG_LOGIN_BODY='{"mobile":"","password":""}'` |
|
|
120
|
+
| API_DEBUG_LOGIN_DESCRIPTION | 将返回的token保存到调试工具中的公共header,字段名Authorization,字段值是Bearer token | 设置登录接口说明 | `export API_DEBUG_LOGIN_DESCRIPTION="用户登录接口"` |
|
|
79
121
|
|
|
80
122
|
### 配置文件
|
|
81
123
|
|
|
@@ -166,7 +208,12 @@ npm run dev
|
|
|
166
208
|
"command": "npx",
|
|
167
209
|
"args": ["@liangshanli/mcp-server-project-standards"],
|
|
168
210
|
"env": {
|
|
169
|
-
"CONFIG_DIR": "./.setting"
|
|
211
|
+
"CONFIG_DIR": "./.setting",
|
|
212
|
+
"API_DEBUG_ALLOWED_METHODS": "GET,POST,PUT,DELETE",
|
|
213
|
+
"API_DEBUG_LOGIN_URL": "/api/login",
|
|
214
|
+
"API_DEBUG_LOGIN_METHOD": "POST",
|
|
215
|
+
"API_DEBUG_LOGIN_BODY": "{\"username\":\"\",\"password\":\"\"}",
|
|
216
|
+
"API_DEBUG_LOGIN_DESCRIPTION": "将返回的token保存到调试工具中的公共header,字段名Authorization,字段值是Bearer token"
|
|
170
217
|
}
|
|
171
218
|
}
|
|
172
219
|
}
|
|
@@ -185,7 +232,12 @@ npm run dev
|
|
|
185
232
|
"command": "npx",
|
|
186
233
|
"args": ["@liangshanli/mcp-server-project-standards"],
|
|
187
234
|
"env": {
|
|
188
|
-
"CONFIG_DIR": "./.setting"
|
|
235
|
+
"CONFIG_DIR": "./.setting",
|
|
236
|
+
"API_DEBUG_ALLOWED_METHODS": "GET,POST,PUT,DELETE",
|
|
237
|
+
"API_DEBUG_LOGIN_URL": "/api/login",
|
|
238
|
+
"API_DEBUG_LOGIN_METHOD": "POST",
|
|
239
|
+
"API_DEBUG_LOGIN_BODY": "{\"username\":\"\",\"password\":\"\"}",
|
|
240
|
+
"API_DEBUG_LOGIN_DESCRIPTION": "将返回的token保存到调试工具中的公共header,字段名Authorization,字段值是Bearer token"
|
|
189
241
|
}
|
|
190
242
|
}
|
|
191
243
|
}
|
|
@@ -348,6 +400,10 @@ npm run dev
|
|
|
348
400
|
- **执行记录**:无论成功失败都记录执行历史
|
|
349
401
|
- **搜索功能**:支持按 URL 或描述搜索 API
|
|
350
402
|
- **参数管理**:支持查询参数、请求体、自定义请求头等
|
|
403
|
+
- **环境变量控制**:通过环境变量控制允许的请求方法和登录接口配置
|
|
404
|
+
- **请求方法限制**:默认只允许 GET 请求,防止误操作
|
|
405
|
+
- **登录接口智能识别**:自动识别登录接口并使用环境变量配置
|
|
406
|
+
- **动态工具描述**:根据环境变量配置实时显示工具说明
|
|
351
407
|
|
|
352
408
|
**🔐 特别说明 - 登录认证流程:**
|
|
353
409
|
|
package/bin/cli.js
CHANGED
|
@@ -28,9 +28,20 @@ function startServer() {
|
|
|
28
28
|
const env = {
|
|
29
29
|
...process.env,
|
|
30
30
|
// Set CONFIG_DIR if specified, otherwise use default
|
|
31
|
-
CONFIG_DIR: process.env.CONFIG_DIR || './.setting'
|
|
31
|
+
CONFIG_DIR: process.env.CONFIG_DIR || './.setting',
|
|
32
|
+
// API Debug environment variables
|
|
33
|
+
API_DEBUG_ALLOWED_METHODS: process.env.API_DEBUG_ALLOWED_METHODS || 'GET',
|
|
34
|
+
API_DEBUG_LOGIN_URL: process.env.API_DEBUG_LOGIN_URL || '/api/login',
|
|
35
|
+
API_DEBUG_LOGIN_METHOD: process.env.API_DEBUG_LOGIN_METHOD || 'POST',
|
|
36
|
+
API_DEBUG_LOGIN_BODY: process.env.API_DEBUG_LOGIN_BODY || '{"username":"","password":""}',
|
|
37
|
+
API_DEBUG_LOGIN_DESCRIPTION: process.env.API_DEBUG_LOGIN_DESCRIPTION || 'Save returned token to common headers in debug tool, field name Authorization, field value Bearer token'
|
|
32
38
|
};
|
|
33
39
|
|
|
40
|
+
// Convert allowed methods to uppercase if specified
|
|
41
|
+
if (env.API_DEBUG_ALLOWED_METHODS) {
|
|
42
|
+
env.API_DEBUG_ALLOWED_METHODS = env.API_DEBUG_ALLOWED_METHODS.toUpperCase();
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
writeLog('INFO', 'Starting MCP Project Standards server');
|
|
35
46
|
|
|
36
47
|
server = spawn('node', [serverPath], {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liangshanli/mcp-server-project-standards",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MCP Project Standards server with project info, structure, API standards, development standards and custom tools",
|
|
5
5
|
"main": "bin/cli.js",
|
|
6
6
|
"bin": {
|
package/src/server-final.js
CHANGED
|
@@ -54,7 +54,7 @@ console.error('==============================================');
|
|
|
54
54
|
class ProjectStandardsMCPServer {
|
|
55
55
|
constructor() {
|
|
56
56
|
this.name = 'project-standards-mcp-server';
|
|
57
|
-
this.version = '1.
|
|
57
|
+
this.version = '1.2.0';
|
|
58
58
|
this.initialized = false;
|
|
59
59
|
this.config = getConfig();
|
|
60
60
|
this.needsProjectFolder = this.config === null;
|
|
@@ -498,16 +498,48 @@ class ProjectStandardsMCPServer {
|
|
|
498
498
|
}
|
|
499
499
|
);
|
|
500
500
|
|
|
501
|
+
// 构建 API 调试工具描述
|
|
502
|
+
let apiDebugDescription = 'API debugging tool for testing and executing API requests. Use URL to identify APIs instead of index numbers.';
|
|
503
|
+
|
|
504
|
+
// 检查是否设置了登录接口环境变量
|
|
505
|
+
const loginUrl = process.env.API_DEBUG_LOGIN_URL;
|
|
506
|
+
const loginMethod = process.env.API_DEBUG_LOGIN_METHOD;
|
|
507
|
+
const loginDescription = process.env.API_DEBUG_LOGIN_DESCRIPTION;
|
|
508
|
+
const allowedMethods = process.env.API_DEBUG_ALLOWED_METHODS;
|
|
509
|
+
|
|
510
|
+
if (loginUrl || loginMethod || allowedMethods) {
|
|
511
|
+
apiDebugDescription += '\n\n🔐 Login Authentication Configuration:';
|
|
512
|
+
|
|
513
|
+
if (loginUrl) {
|
|
514
|
+
apiDebugDescription += `\n- Login URL: ${loginUrl}`;
|
|
515
|
+
}
|
|
516
|
+
if (loginMethod) {
|
|
517
|
+
apiDebugDescription += `\n- Login Method: ${loginMethod}`;
|
|
518
|
+
}
|
|
519
|
+
if (loginDescription) {
|
|
520
|
+
apiDebugDescription += `\n- Login Description: ${loginDescription}`;
|
|
521
|
+
}
|
|
522
|
+
if (allowedMethods) {
|
|
523
|
+
apiDebugDescription += `\n- Allowed Methods: ${allowedMethods}`;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
apiDebugDescription += '\n\n💡 Usage Instructions:';
|
|
527
|
+
apiDebugDescription += '\n- Use URL to identify APIs for execute and delete operations (not index numbers)';
|
|
528
|
+
apiDebugDescription += '\n- Login API automatically uses environment variable configuration';
|
|
529
|
+
apiDebugDescription += '\n- Non-login APIs must use allowed methods only';
|
|
530
|
+
apiDebugDescription += '\n- Common request headers are automatically updated after successful login';
|
|
531
|
+
}
|
|
532
|
+
|
|
501
533
|
tools.push({
|
|
502
534
|
name: 'api_debug',
|
|
503
|
-
description:
|
|
535
|
+
description: apiDebugDescription,
|
|
504
536
|
inputSchema: {
|
|
505
537
|
type: 'object',
|
|
506
538
|
properties: {
|
|
507
539
|
action: {
|
|
508
540
|
type: 'string',
|
|
509
541
|
enum: ['get', 'set', 'delete', 'execute', 'updateBaseUrl', 'updateHeaders', 'deleteHeader', 'search'],
|
|
510
|
-
description: 'Action to perform: "get" to retrieve config, "set" to update config, "delete" to delete API, "execute" to execute API, "updateBaseUrl" to update base URL, "updateHeaders" to update headers, "deleteHeader" to delete specific header, "search" to search APIs by URL or description'
|
|
542
|
+
description: 'Action to perform: "get" to retrieve config, "set" to update config, "delete" to delete API by URL, "execute" to execute API by URL, "updateBaseUrl" to update base URL, "updateHeaders" to update headers, "deleteHeader" to delete specific header, "search" to search APIs by URL or description'
|
|
511
543
|
},
|
|
512
544
|
config: {
|
|
513
545
|
type: 'object',
|
|
@@ -561,9 +593,9 @@ class ProjectStandardsMCPServer {
|
|
|
561
593
|
}
|
|
562
594
|
}
|
|
563
595
|
},
|
|
564
|
-
|
|
565
|
-
type: '
|
|
566
|
-
description: '
|
|
596
|
+
url: {
|
|
597
|
+
type: 'string',
|
|
598
|
+
description: 'URL of API to delete or execute (required for "delete" and "execute" actions)'
|
|
567
599
|
},
|
|
568
600
|
baseUrl: {
|
|
569
601
|
type: 'string',
|
|
@@ -599,16 +631,16 @@ class ProjectStandardsMCPServer {
|
|
|
599
631
|
{
|
|
600
632
|
properties: {
|
|
601
633
|
action: { const: 'delete' },
|
|
602
|
-
|
|
634
|
+
url: { type: 'string' }
|
|
603
635
|
},
|
|
604
|
-
required: ['
|
|
636
|
+
required: ['url']
|
|
605
637
|
},
|
|
606
638
|
{
|
|
607
639
|
properties: {
|
|
608
640
|
action: { const: 'execute' },
|
|
609
|
-
|
|
641
|
+
url: { type: 'string' }
|
|
610
642
|
},
|
|
611
|
-
required: ['
|
|
643
|
+
required: ['url']
|
|
612
644
|
},
|
|
613
645
|
{
|
|
614
646
|
properties: {
|
package/src/utils/api_debug.js
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
|
+
// Get allowed methods from environment variable
|
|
5
|
+
const getAllowedMethods = () => {
|
|
6
|
+
const allowedMethods = process.env.API_DEBUG_ALLOWED_METHODS || 'GET';
|
|
7
|
+
return allowedMethods.split(',').map(method => method.trim().toUpperCase());
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// Get login URL from environment variable
|
|
11
|
+
const getLoginUrl = () => {
|
|
12
|
+
return process.env.API_DEBUG_LOGIN_URL || '/api/login';
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Get login method from environment variable
|
|
16
|
+
const getLoginMethod = () => {
|
|
17
|
+
return (process.env.API_DEBUG_LOGIN_METHOD || 'POST').toUpperCase();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Get login body from environment variable
|
|
21
|
+
const getLoginBody = () => {
|
|
22
|
+
return process.env.API_DEBUG_LOGIN_BODY || '{"username":"","password":""}';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Get login description from environment variable
|
|
26
|
+
const getLoginDescription = () => {
|
|
27
|
+
return process.env.API_DEBUG_LOGIN_DESCRIPTION || 'Save returned token to common headers in debug tool, field name Authorization, field value Bearer token';
|
|
28
|
+
};
|
|
29
|
+
|
|
4
30
|
// Get API debug config file path
|
|
5
31
|
const getApiConfigPath = () => {
|
|
6
32
|
const configDir = process.env.CONFIG_DIR || './.setting';
|
|
@@ -93,7 +119,7 @@ const detectContentType = (body) => {
|
|
|
93
119
|
* @param {string} params.config.baseUrl - API 基础 URL
|
|
94
120
|
* @param {Object} params.config.headers - 公共请求头
|
|
95
121
|
* @param {Array} params.config.list - API 接口列表
|
|
96
|
-
* @param {string} params.
|
|
122
|
+
* @param {string} params.url - 要执行的接口URL(执行时必需)
|
|
97
123
|
* @param {string} params.baseUrl - 新的基础 URL(updateBaseUrl 时必需)
|
|
98
124
|
* @param {Object} params.headers - 新的公共请求头(updateHeaders 时必需)
|
|
99
125
|
* @param {string} params.headerName - 要删除的请求头名称(deleteHeader 时必需)
|
|
@@ -103,7 +129,7 @@ const detectContentType = (body) => {
|
|
|
103
129
|
* @returns {Object} API 调试结果
|
|
104
130
|
*/
|
|
105
131
|
async function api_debug(params, config, saveConfig) {
|
|
106
|
-
const { action, config: apiConfig,
|
|
132
|
+
const { action, config: apiConfig, url } = params || {};
|
|
107
133
|
|
|
108
134
|
if (!action) {
|
|
109
135
|
throw new Error('Missing action parameter. Must be "get", "set", "delete", "execute", "updateBaseUrl", "updateHeaders", "deleteHeader", or "search"');
|
|
@@ -173,8 +199,8 @@ async function api_debug(params, config, saveConfig) {
|
|
|
173
199
|
throw new Error(`Failed to update API debug config: ${err.message}`);
|
|
174
200
|
}
|
|
175
201
|
} else if (action === 'delete') {
|
|
176
|
-
if (!
|
|
177
|
-
throw new Error('Missing
|
|
202
|
+
if (!url) {
|
|
203
|
+
throw new Error('Missing url parameter for delete action');
|
|
178
204
|
}
|
|
179
205
|
|
|
180
206
|
try {
|
|
@@ -185,31 +211,36 @@ async function api_debug(params, config, saveConfig) {
|
|
|
185
211
|
apiDebugConfig.list = [];
|
|
186
212
|
}
|
|
187
213
|
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const saved = saveApiConfig(apiDebugConfig);
|
|
194
|
-
if (!saved) {
|
|
195
|
-
throw new Error('Failed to save API configuration');
|
|
196
|
-
}
|
|
197
|
-
|
|
214
|
+
// 查找并删除指定URL的接口
|
|
215
|
+
const originalLength = apiDebugConfig.list.length;
|
|
216
|
+
apiDebugConfig.list = apiDebugConfig.list.filter(item => item.url !== url);
|
|
217
|
+
|
|
218
|
+
if (apiDebugConfig.list.length === originalLength) {
|
|
198
219
|
return {
|
|
199
|
-
success:
|
|
200
|
-
message: `
|
|
201
|
-
deletedItem: deletedItem,
|
|
220
|
+
success: false,
|
|
221
|
+
message: `API with URL "${url}" not found`,
|
|
202
222
|
timestamp: new Date().toISOString()
|
|
203
223
|
};
|
|
204
|
-
} else {
|
|
205
|
-
throw new Error(`Invalid index: ${index}. Must be between 0 and ${apiDebugConfig.list.length - 1}`);
|
|
206
224
|
}
|
|
225
|
+
|
|
226
|
+
// 保存配置
|
|
227
|
+
const saved = saveApiConfig(apiDebugConfig);
|
|
228
|
+
if (!saved) {
|
|
229
|
+
throw new Error('Failed to save API configuration');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
success: true,
|
|
234
|
+
message: `Successfully deleted API with URL: ${url}`,
|
|
235
|
+
deletedUrl: url,
|
|
236
|
+
timestamp: new Date().toISOString()
|
|
237
|
+
};
|
|
207
238
|
} catch (err) {
|
|
208
239
|
throw new Error(`Failed to delete API: ${err.message}`);
|
|
209
240
|
}
|
|
210
241
|
} else if (action === 'execute') {
|
|
211
|
-
if (!
|
|
212
|
-
throw new Error('Missing
|
|
242
|
+
if (!url) {
|
|
243
|
+
throw new Error('Missing url parameter for execute action');
|
|
213
244
|
}
|
|
214
245
|
|
|
215
246
|
try {
|
|
@@ -220,14 +251,54 @@ async function api_debug(params, config, saveConfig) {
|
|
|
220
251
|
throw new Error('API list not found or invalid');
|
|
221
252
|
}
|
|
222
253
|
|
|
223
|
-
|
|
224
|
-
|
|
254
|
+
// 查找指定URL的接口
|
|
255
|
+
const apiItem = apiDebugConfig.list.find(item => item.url === url);
|
|
256
|
+
if (!apiItem) {
|
|
257
|
+
throw new Error(`API with URL "${url}" not found`);
|
|
225
258
|
}
|
|
226
259
|
|
|
227
|
-
|
|
260
|
+
// 获取接口在列表中的索引(用于更新数据)
|
|
261
|
+
const itemIndex = apiDebugConfig.list.findIndex(item => item.url === url);
|
|
228
262
|
const baseUrl = apiDebugConfig.baseUrl || '';
|
|
229
263
|
const commonHeaders = apiDebugConfig.headers || {};
|
|
230
264
|
|
|
265
|
+
// 验证请求方法是否被允许
|
|
266
|
+
const allowedMethods = getAllowedMethods();
|
|
267
|
+
const requestMethod = (apiItem.method || 'GET').toUpperCase();
|
|
268
|
+
const loginUrl = getLoginUrl();
|
|
269
|
+
|
|
270
|
+
// 判断是否为登录接口 - 支持完整 URL 和相对路径匹配
|
|
271
|
+
const isLoginRequest = (() => {
|
|
272
|
+
const apiUrl = apiItem.url;
|
|
273
|
+
const loginUrlPattern = loginUrl;
|
|
274
|
+
|
|
275
|
+
// 如果登录 URL 是完整 URL,提取路径部分进行匹配
|
|
276
|
+
if (loginUrlPattern.startsWith('http://') || loginUrlPattern.startsWith('https://')) {
|
|
277
|
+
try {
|
|
278
|
+
const url = new URL(loginUrlPattern);
|
|
279
|
+
const loginPath = url.pathname;
|
|
280
|
+
// 匹配完整路径或去掉前导斜杠的路径
|
|
281
|
+
return apiUrl === loginPath || apiUrl === loginPath.replace(/^\//, '') || apiUrl === loginUrlPattern;
|
|
282
|
+
} catch (e) {
|
|
283
|
+
// 如果 URL 解析失败,回退到字符串匹配
|
|
284
|
+
return apiUrl === loginUrlPattern;
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
// 相对路径匹配
|
|
288
|
+
return apiUrl === loginUrlPattern ||
|
|
289
|
+
apiUrl === loginUrlPattern.replace(/^\//, '') ||
|
|
290
|
+
apiUrl.endsWith(loginUrlPattern) ||
|
|
291
|
+
apiUrl.endsWith(loginUrlPattern.replace(/^\//, ''));
|
|
292
|
+
}
|
|
293
|
+
})();
|
|
294
|
+
|
|
295
|
+
if (!allowedMethods.includes(requestMethod)) {
|
|
296
|
+
// 如果是登录接口,继续执行;否则返回错误
|
|
297
|
+
if (!isLoginRequest) {
|
|
298
|
+
throw new Error(`Method ${requestMethod} is not allowed. Allowed methods: ${allowedMethods.join(', ')}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
231
302
|
// 构建完整 URL
|
|
232
303
|
const fullUrl = baseUrl + apiItem.url;
|
|
233
304
|
|
|
@@ -291,64 +362,113 @@ async function api_debug(params, config, saveConfig) {
|
|
|
291
362
|
|
|
292
363
|
const finalUrl = queryString ? `${fullUrl}?${queryString}` : fullUrl;
|
|
293
364
|
|
|
365
|
+
let success = true;
|
|
294
366
|
let response;
|
|
295
367
|
let responseData;
|
|
296
368
|
let error = null;
|
|
297
|
-
let success = true;
|
|
298
369
|
|
|
370
|
+
// 请求处理部分 - 只有这部分出错才会保存到 api.json
|
|
299
371
|
try {
|
|
300
|
-
// 执行请求
|
|
301
|
-
response = await fetch(finalUrl, {
|
|
302
|
-
method: apiItem.method || 'GET',
|
|
303
|
-
headers: headers,
|
|
304
|
-
body: body
|
|
305
|
-
});
|
|
306
372
|
|
|
307
|
-
//
|
|
308
|
-
|
|
373
|
+
// 如果是登录接口且方法不被允许,使用环境变量中的登录配置
|
|
374
|
+
if (isLoginRequest && !allowedMethods.includes(requestMethod)) {
|
|
375
|
+
const loginMethod = getLoginMethod();
|
|
376
|
+
const loginBody = getLoginBody();
|
|
377
|
+
|
|
378
|
+
// 更新请求方法和请求体
|
|
379
|
+
apiItem.method = loginMethod;
|
|
380
|
+
if (loginBody) {
|
|
381
|
+
apiItem.body = loginBody;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 更新最终 URL 和方法
|
|
385
|
+
const updatedFinalUrl = queryString ? `${fullUrl}?${queryString}` : fullUrl;
|
|
386
|
+
|
|
387
|
+
try {
|
|
388
|
+
response = await fetch(updatedFinalUrl, {
|
|
389
|
+
method: loginMethod,
|
|
390
|
+
headers: headers,
|
|
391
|
+
body: loginBody
|
|
392
|
+
});
|
|
393
|
+
} catch (fetchError) {
|
|
394
|
+
error = fetchError.message;
|
|
395
|
+
success = false;
|
|
396
|
+
response = null;
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
try {
|
|
400
|
+
// 执行请求
|
|
401
|
+
response = await fetch(finalUrl, {
|
|
402
|
+
method: apiItem.method || 'GET',
|
|
403
|
+
headers: headers,
|
|
404
|
+
body: body
|
|
405
|
+
});
|
|
406
|
+
} catch (fetchError) {
|
|
407
|
+
error = fetchError.message;
|
|
408
|
+
success = false;
|
|
409
|
+
response = null;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
309
412
|
|
|
310
|
-
if (
|
|
311
|
-
|
|
413
|
+
if (response) {
|
|
414
|
+
// 获取响应数据
|
|
415
|
+
const contentType = response.headers.get('content-type');
|
|
416
|
+
|
|
417
|
+
if (contentType && contentType.includes('application/json')) {
|
|
418
|
+
responseData = await response.json();
|
|
419
|
+
} else {
|
|
420
|
+
responseData = await response.text();
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// 判断请求是否成功(HTTP 状态码 200-299 为成功)
|
|
424
|
+
const isHttpSuccess = response.status >= 200 && response.status < 300;
|
|
425
|
+
success = isHttpSuccess;
|
|
426
|
+
|
|
427
|
+
// 记录响应信息
|
|
428
|
+
apiDebugConfig.list[itemIndex].data = responseData;
|
|
429
|
+
apiDebugConfig.list[itemIndex].status = response.status;
|
|
430
|
+
apiDebugConfig.list[itemIndex].statusText = response.statusText;
|
|
431
|
+
apiDebugConfig.list[itemIndex].responseHeaders = Object.fromEntries(response.headers.entries());
|
|
432
|
+
apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
|
|
433
|
+
apiDebugConfig.list[itemIndex].success = isHttpSuccess;
|
|
434
|
+
apiDebugConfig.list[itemIndex].error = isHttpSuccess ? null : `HTTP ${response.status}: ${response.statusText}`;
|
|
312
435
|
} else {
|
|
313
|
-
|
|
436
|
+
// 记录失败信息
|
|
437
|
+
success = false;
|
|
438
|
+
apiDebugConfig.list[itemIndex].data = null;
|
|
439
|
+
apiDebugConfig.list[itemIndex].status = null;
|
|
440
|
+
apiDebugConfig.list[itemIndex].statusText = null;
|
|
441
|
+
apiDebugConfig.list[itemIndex].responseHeaders = null;
|
|
442
|
+
apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
|
|
443
|
+
apiDebugConfig.list[itemIndex].success = false;
|
|
444
|
+
apiDebugConfig.list[itemIndex].error = error;
|
|
314
445
|
}
|
|
315
446
|
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
apiDebugConfig.list
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
apiDebugConfig.list
|
|
447
|
+
// 去重处理:相同的 URL 只保留一份(保留最新的执行结果)
|
|
448
|
+
const urlMap = new Map();
|
|
449
|
+
apiDebugConfig.list.forEach(item => {
|
|
450
|
+
if (item.url) {
|
|
451
|
+
urlMap.set(item.url, item);
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
apiDebugConfig.list = Array.from(urlMap.values());
|
|
324
455
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
error = fetchError.message;
|
|
328
|
-
success = false;
|
|
456
|
+
// 无论成功还是失败,都保存配置
|
|
457
|
+
saveApiConfig(apiDebugConfig);
|
|
329
458
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// 去重处理:相同的 URL 只保留一份(保留最新的执行结果)
|
|
340
|
-
const urlMap = new Map();
|
|
341
|
-
apiDebugConfig.list.forEach(item => {
|
|
342
|
-
if (item.url) {
|
|
343
|
-
urlMap.set(item.url, item);
|
|
459
|
+
} catch (requestError) {
|
|
460
|
+
// 只有请求相关的错误才保存到 api.json
|
|
461
|
+
try {
|
|
462
|
+
apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
|
|
463
|
+
apiDebugConfig.list[itemIndex].success = false;
|
|
464
|
+
apiDebugConfig.list[itemIndex].error = requestError.message;
|
|
465
|
+
saveApiConfig(apiDebugConfig);
|
|
466
|
+
} catch (saveErr) {
|
|
467
|
+
console.error('Failed to save request error information:', saveErr.message);
|
|
344
468
|
}
|
|
345
|
-
}
|
|
346
|
-
apiDebugConfig.list = Array.from(urlMap.values());
|
|
347
|
-
|
|
348
|
-
// 无论成功还是失败,都保存配置
|
|
349
|
-
saveApiConfig(apiDebugConfig);
|
|
469
|
+
}
|
|
350
470
|
|
|
351
|
-
if (success) {
|
|
471
|
+
if (success && response) {
|
|
352
472
|
return {
|
|
353
473
|
success: true,
|
|
354
474
|
message: `Successfully executed API: ${apiItem.description || apiItem.url}`,
|
|
@@ -376,7 +496,7 @@ async function api_debug(params, config, saveConfig) {
|
|
|
376
496
|
headers: headers,
|
|
377
497
|
body: body
|
|
378
498
|
},
|
|
379
|
-
error: error,
|
|
499
|
+
error: error || (response ? `HTTP ${response.status}: ${response.statusText}` : 'Request failed'),
|
|
380
500
|
timestamp: new Date().toISOString()
|
|
381
501
|
};
|
|
382
502
|
}
|
|
@@ -384,10 +504,11 @@ async function api_debug(params, config, saveConfig) {
|
|
|
384
504
|
// 如果是在保存配置时出错,也要尝试记录错误信息
|
|
385
505
|
try {
|
|
386
506
|
const apiDebugConfig = loadApiConfig();
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
apiDebugConfig.list[
|
|
390
|
-
apiDebugConfig.list[
|
|
507
|
+
const itemIndex = apiDebugConfig.list.findIndex(item => item.url === url);
|
|
508
|
+
if (apiDebugConfig.list && itemIndex >= 0) {
|
|
509
|
+
apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
|
|
510
|
+
apiDebugConfig.list[itemIndex].success = false;
|
|
511
|
+
apiDebugConfig.list[itemIndex].error = err.message;
|
|
391
512
|
saveApiConfig(apiDebugConfig);
|
|
392
513
|
}
|
|
393
514
|
} catch (saveErr) {
|