@liangshanli/mcp-server-project-standards 1.2.2 → 2.0.1

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.
@@ -0,0 +1,137 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ // Get API debug config file path
5
+ const getApiConfigPath = () => {
6
+ const configDir = process.env.CONFIG_DIR || './.setting';
7
+ return path.join(configDir, 'api.json');
8
+ };
9
+
10
+ // Load API debug config
11
+ const loadApiConfig = () => {
12
+ const apiConfigPath = getApiConfigPath();
13
+ try {
14
+ if (fs.existsSync(apiConfigPath)) {
15
+ const configData = fs.readFileSync(apiConfigPath, 'utf8');
16
+ return JSON.parse(configData);
17
+ }
18
+ } catch (err) {
19
+ console.error('Failed to read API config file:', err.message);
20
+ }
21
+ return {
22
+ baseUrl: '',
23
+ headers: {
24
+ 'Content-Type': 'application/json',
25
+ 'Accept': 'application/json'
26
+ },
27
+ list: []
28
+ };
29
+ };
30
+
31
+ // Save API debug config
32
+ const saveApiConfig = (apiConfig) => {
33
+ const configDir = process.env.CONFIG_DIR || './.setting';
34
+ const apiConfigPath = path.join(configDir, 'api.json');
35
+
36
+ try {
37
+ if (!fs.existsSync(configDir)) {
38
+ fs.mkdirSync(configDir, { recursive: true });
39
+ }
40
+ fs.writeFileSync(apiConfigPath, JSON.stringify(apiConfig, null, 2), 'utf8');
41
+ return true;
42
+ } catch (err) {
43
+ console.error('Failed to save API config file:', err.message);
44
+ return false;
45
+ }
46
+ };
47
+
48
+ // Get allowed methods from environment variable
49
+ const getAllowedMethods = () => {
50
+ const allowedMethods = process.env.API_DEBUG_ALLOWED_METHODS || 'GET';
51
+ return allowedMethods.split(',').map(method => method.trim().toUpperCase());
52
+ };
53
+
54
+ // Get login URL from environment variable
55
+ const getLoginUrl = () => {
56
+ return process.env.API_DEBUG_LOGIN_URL || '/api/login';
57
+ };
58
+
59
+ // Get login method from environment variable
60
+ const getLoginMethod = () => {
61
+ return (process.env.API_DEBUG_LOGIN_METHOD || 'POST').toUpperCase();
62
+ };
63
+
64
+ // Get login body from environment variable
65
+ const getLoginBody = () => {
66
+ const envBody = process.env.API_DEBUG_LOGIN_BODY || '{"username":"","password":""}';
67
+
68
+ // 如果是字符串格式,直接返回
69
+ if (typeof envBody === 'string' && !envBody.startsWith('{')) {
70
+ return envBody;
71
+ }
72
+
73
+ // 如果是JSON格式,解析后返回
74
+ try {
75
+ return JSON.parse(envBody);
76
+ } catch {
77
+ // 如果解析失败,返回原始字符串
78
+ return envBody;
79
+ }
80
+ };
81
+
82
+ // Get login description from environment variable
83
+ const getLoginDescription = () => {
84
+ return process.env.API_DEBUG_LOGIN_DESCRIPTION || 'Save returned token to common headers in debug tool, field name Authorization, field value Bearer token';
85
+ };
86
+
87
+ // Detect content type based on body content
88
+ const detectContentType = (body) => {
89
+ if (typeof body !== 'string') {
90
+ return 'application/json';
91
+ }
92
+
93
+ const trimmedBody = body.trim();
94
+
95
+ // Check for XML
96
+ if (trimmedBody.startsWith('<') && trimmedBody.endsWith('>')) {
97
+ return 'application/xml';
98
+ }
99
+
100
+ // Check for HTML
101
+ if (trimmedBody.includes('<html') || trimmedBody.includes('<!DOCTYPE html')) {
102
+ return 'text/html';
103
+ }
104
+
105
+ // Check for JSON
106
+ try {
107
+ JSON.parse(trimmedBody);
108
+ return 'application/json';
109
+ } catch {
110
+ // Not JSON, continue checking
111
+ }
112
+
113
+ // Check for URL encoded format
114
+ if (trimmedBody.includes('=') && trimmedBody.includes('&')) {
115
+ return 'application/x-www-form-urlencoded';
116
+ }
117
+
118
+ // Check for plain text patterns
119
+ if (trimmedBody.includes('\n') || trimmedBody.includes('\r')) {
120
+ return 'text/plain';
121
+ }
122
+
123
+ // Default to text/plain
124
+ return 'text/plain';
125
+ };
126
+
127
+ module.exports = {
128
+ getApiConfigPath,
129
+ loadApiConfig,
130
+ saveApiConfig,
131
+ getAllowedMethods,
132
+ getLoginUrl,
133
+ getLoginMethod,
134
+ getLoginBody,
135
+ getLoginDescription,
136
+ detectContentType
137
+ };
@@ -0,0 +1,217 @@
1
+ const { loadApiConfig, saveApiConfig } = require('./api_common');
2
+
3
+ /**
4
+ * API 配置工具 - 专门处理API配置管理
5
+ * @param {Object} params - 参数
6
+ * @param {string} params.action - 操作类型 ('get', 'set', 'updateBaseUrl', 'updateHeaders', 'deleteHeader', 'search', 'list')
7
+ * @param {Object} params.config - API配置(set 时必需)
8
+ * @param {string} params.baseUrl - 基础URL(updateBaseUrl 时必需)
9
+ * @param {Object} params.headers - 请求头(updateHeaders 时必需)
10
+ * @param {string} params.headerName - 要删除的请求头名称(deleteHeader 时必需)
11
+ * @param {string} params.keyword - 搜索关键词(search 时必需)
12
+ * @param {Object} config - 服务器配置
13
+ * @param {Function} saveConfig - 保存配置函数
14
+ * @returns {Object} API配置结果
15
+ */
16
+ async function api_config(params, config, saveConfig) {
17
+ const { action, config: apiConfig, baseUrl, headers, headerName, keyword } = params || {};
18
+
19
+ if (!action) {
20
+ throw new Error('Missing action parameter. Must be "get", "set", "updateBaseUrl", "updateHeaders", "deleteHeader", "search", or "list"');
21
+ }
22
+
23
+ if (action === 'get') {
24
+ try {
25
+ const apiDebugConfig = loadApiConfig();
26
+ return {
27
+ success: true,
28
+ config: apiDebugConfig,
29
+ timestamp: new Date().toISOString()
30
+ };
31
+ } catch (err) {
32
+ throw new Error(`Failed to get API config: ${err.message}`);
33
+ }
34
+ } else if (action === 'set') {
35
+ if (!apiConfig || typeof apiConfig !== 'object') {
36
+ throw new Error('Missing or invalid config parameter for set action');
37
+ }
38
+
39
+ try {
40
+ // 加载现有配置
41
+ const existingConfig = loadApiConfig();
42
+
43
+ // 合并配置
44
+ const mergedConfig = {
45
+ baseUrl: apiConfig.baseUrl !== undefined ? apiConfig.baseUrl : existingConfig.baseUrl || '',
46
+ headers: { ...existingConfig.headers, ...apiConfig.headers },
47
+ list: []
48
+ };
49
+
50
+ // 去重处理:相同的 URL 只保留一份
51
+ const urlMap = new Map();
52
+
53
+ // 先添加现有列表中的项目
54
+ if (existingConfig.list && Array.isArray(existingConfig.list)) {
55
+ existingConfig.list.forEach(item => {
56
+ if (item.url) {
57
+ urlMap.set(item.url, item);
58
+ }
59
+ });
60
+ }
61
+
62
+ // 再添加新配置中的项目(会覆盖相同 URL 的项目)
63
+ if (apiConfig.list && Array.isArray(apiConfig.list)) {
64
+ apiConfig.list.forEach(item => {
65
+ if (item.url) {
66
+ urlMap.set(item.url, item);
67
+ }
68
+ });
69
+ }
70
+
71
+ // 转换为数组
72
+ mergedConfig.list = Array.from(urlMap.values());
73
+
74
+ // 保存配置
75
+ const saved = saveApiConfig(mergedConfig);
76
+ if (!saved) {
77
+ throw new Error('Failed to save API configuration');
78
+ }
79
+
80
+ return {
81
+ success: true,
82
+ message: `Successfully updated API config. Total APIs: ${mergedConfig.list.length}`,
83
+ config: mergedConfig,
84
+ totalApis: mergedConfig.list.length,
85
+ timestamp: new Date().toISOString()
86
+ };
87
+ } catch (err) {
88
+ throw new Error(`Failed to update API config: ${err.message}`);
89
+ }
90
+ } else if (action === 'updateBaseUrl') {
91
+ if (!baseUrl) {
92
+ throw new Error('Missing baseUrl parameter for updateBaseUrl action');
93
+ }
94
+
95
+ try {
96
+ const apiDebugConfig = loadApiConfig();
97
+ apiDebugConfig.baseUrl = baseUrl;
98
+ const saved = saveApiConfig(apiDebugConfig);
99
+ if (!saved) {
100
+ throw new Error('Failed to save API configuration');
101
+ }
102
+
103
+ return {
104
+ success: true,
105
+ message: `Successfully updated base URL to: ${baseUrl}`,
106
+ baseUrl: baseUrl,
107
+ timestamp: new Date().toISOString()
108
+ };
109
+ } catch (err) {
110
+ throw new Error(`Failed to update base URL: ${err.message}`);
111
+ }
112
+ } else if (action === 'updateHeaders') {
113
+ if (!headers || typeof headers !== 'object') {
114
+ throw new Error('Missing or invalid headers parameter for updateHeaders action');
115
+ }
116
+
117
+ try {
118
+ const apiDebugConfig = loadApiConfig();
119
+ apiDebugConfig.headers = { ...apiDebugConfig.headers, ...headers };
120
+ const saved = saveApiConfig(apiDebugConfig);
121
+ if (!saved) {
122
+ throw new Error('Failed to save API configuration');
123
+ }
124
+
125
+ return {
126
+ success: true,
127
+ message: 'Successfully updated headers',
128
+ headers: apiDebugConfig.headers,
129
+ timestamp: new Date().toISOString()
130
+ };
131
+ } catch (err) {
132
+ throw new Error(`Failed to update headers: ${err.message}`);
133
+ }
134
+ } else if (action === 'deleteHeader') {
135
+ if (!headerName) {
136
+ throw new Error('Missing headerName parameter for deleteHeader action');
137
+ }
138
+
139
+ try {
140
+ const apiDebugConfig = loadApiConfig();
141
+ if (apiDebugConfig.headers && apiDebugConfig.headers[headerName]) {
142
+ delete apiDebugConfig.headers[headerName];
143
+ const saved = saveApiConfig(apiDebugConfig);
144
+ if (!saved) {
145
+ throw new Error('Failed to save API configuration');
146
+ }
147
+
148
+ return {
149
+ success: true,
150
+ message: `Successfully deleted header: ${headerName}`,
151
+ headers: apiDebugConfig.headers,
152
+ timestamp: new Date().toISOString()
153
+ };
154
+ } else {
155
+ return {
156
+ success: false,
157
+ message: `Header '${headerName}' not found`,
158
+ headers: apiDebugConfig.headers,
159
+ timestamp: new Date().toISOString()
160
+ };
161
+ }
162
+ } catch (err) {
163
+ throw new Error(`Failed to delete header: ${err.message}`);
164
+ }
165
+ } else if (action === 'search') {
166
+ if (!keyword) {
167
+ throw new Error('Missing keyword parameter for search action');
168
+ }
169
+
170
+ try {
171
+ const apiDebugConfig = loadApiConfig();
172
+ let searchResults = [];
173
+
174
+ if (apiDebugConfig.list && Array.isArray(apiDebugConfig.list)) {
175
+ searchResults = apiDebugConfig.list.filter((item) => {
176
+ const urlMatch = item.url && item.url.toLowerCase().includes(keyword.toLowerCase());
177
+ const descMatch = item.description && item.description.toLowerCase().includes(keyword.toLowerCase());
178
+ return urlMatch || descMatch;
179
+ });
180
+ }
181
+
182
+ return {
183
+ success: true,
184
+ message: `Found ${searchResults.length} matching API(s) for keyword: "${keyword}"`,
185
+ keyword: keyword,
186
+ results: searchResults,
187
+ totalCount: searchResults.length,
188
+ timestamp: new Date().toISOString()
189
+ };
190
+ } catch (err) {
191
+ throw new Error(`Failed to search APIs: ${err.message}`);
192
+ }
193
+ } else if (action === 'list') {
194
+ try {
195
+ const apiDebugConfig = loadApiConfig();
196
+ const apiList = apiDebugConfig.list || [];
197
+
198
+ return {
199
+ success: true,
200
+ message: `Found ${apiList.length} configured API(s)`,
201
+ apis: apiList,
202
+ totalCount: apiList.length,
203
+ config: {
204
+ baseUrl: apiDebugConfig.baseUrl,
205
+ headers: apiDebugConfig.headers
206
+ },
207
+ timestamp: new Date().toISOString()
208
+ };
209
+ } catch (err) {
210
+ throw new Error(`Failed to list APIs: ${err.message}`);
211
+ }
212
+ } else {
213
+ throw new Error('Invalid action. Must be "get", "set", "updateBaseUrl", "updateHeaders", "deleteHeader", "addApi", "deleteApi", "search", or "list"');
214
+ }
215
+ }
216
+
217
+ module.exports = api_config;