@liangshanli/mcp-server-project-standards 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 +588 -0
- package/README.zh-CN.md +607 -0
- package/bin/cli.js +196 -0
- package/package.json +38 -0
- package/src/server-final.js +874 -0
- package/src/utils/api_debug.js +514 -0
- package/src/utils/create_custom_tool.js +54 -0
- package/src/utils/database_standards.js +147 -0
- package/src/utils/execute_custom_tool.js +51 -0
- package/src/utils/get_api_standards.js +203 -0
- package/src/utils/get_development_standards.js +139 -0
- package/src/utils/get_project_info.js +87 -0
- package/src/utils/get_project_structure.js +139 -0
- package/src/utils/list_custom_tools.js +15 -0
- package/src/utils/update_config.js +36 -0
- package/start-server.js +108 -0
|
@@ -0,0 +1,874 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// Import tool modules
|
|
5
|
+
const project_info = require('./utils/get_project_info');
|
|
6
|
+
const project_structure = require('./utils/get_project_structure');
|
|
7
|
+
const api_standards = require('./utils/get_api_standards');
|
|
8
|
+
const development_standards = require('./utils/get_development_standards');
|
|
9
|
+
const database_standards = require('./utils/database_standards');
|
|
10
|
+
const api_debug = require('./utils/api_debug');
|
|
11
|
+
|
|
12
|
+
// Get configuration from file or environment
|
|
13
|
+
const getConfig = () => {
|
|
14
|
+
const configDir = process.env.CONFIG_DIR || './.setting';
|
|
15
|
+
const configPath = path.join(configDir, 'config.json');
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
if (fs.existsSync(configPath)) {
|
|
19
|
+
const configData = fs.readFileSync(configPath, 'utf8');
|
|
20
|
+
return JSON.parse(configData);
|
|
21
|
+
}
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error('Failed to read config file:', err.message);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Return null if no config file exists - this will trigger the notification
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Save configuration to file
|
|
31
|
+
const saveConfig = (config) => {
|
|
32
|
+
const configDir = process.env.CONFIG_DIR || './.setting';
|
|
33
|
+
const configPath = path.join(configDir, 'config.json');
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
if (!fs.existsSync(configDir)) {
|
|
37
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
40
|
+
return true;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.error('Failed to save config file:', err.message);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// 启动日志
|
|
48
|
+
console.error('=== MCP Project Standards Server Starting ===');
|
|
49
|
+
console.error(`Time: ${new Date().toISOString()}`);
|
|
50
|
+
console.error(`Config Dir: ${process.env.CONFIG_DIR || './.setting'}`);
|
|
51
|
+
console.error('==============================================');
|
|
52
|
+
|
|
53
|
+
// Final MCP Server
|
|
54
|
+
class ProjectStandardsMCPServer {
|
|
55
|
+
constructor() {
|
|
56
|
+
this.name = 'project-standards-mcp-server';
|
|
57
|
+
this.version = '1.0.0';
|
|
58
|
+
this.initialized = false;
|
|
59
|
+
this.config = getConfig();
|
|
60
|
+
this.needsProjectFolder = this.config === null;
|
|
61
|
+
|
|
62
|
+
// 如果配置文件不存在,创建默认配置
|
|
63
|
+
if (this.needsProjectFolder) {
|
|
64
|
+
this.createDefaultConfig();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 创建默认配置文件
|
|
69
|
+
createDefaultConfig() {
|
|
70
|
+
const configDir = process.env.CONFIG_DIR || './.setting';
|
|
71
|
+
const configPath = path.join(configDir, 'config.json');
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// 创建配置目录
|
|
75
|
+
if (!fs.existsSync(configDir)) {
|
|
76
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
77
|
+
console.error(`Created config directory: ${configDir}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 创建默认配置文件
|
|
81
|
+
const defaultConfig = {
|
|
82
|
+
project_info: {},
|
|
83
|
+
project_structure: [],
|
|
84
|
+
api_standards: {},
|
|
85
|
+
development_standards: [],
|
|
86
|
+
database_standards: []
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), 'utf8');
|
|
90
|
+
console.error(`Created default config file: ${configPath}`);
|
|
91
|
+
|
|
92
|
+
// 更新配置和状态
|
|
93
|
+
this.config = defaultConfig;
|
|
94
|
+
this.needsProjectFolder = false;
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error('Failed to create default config:', err.message);
|
|
97
|
+
// 保持 needsProjectFolder = true 状态
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
// Project information tool
|
|
103
|
+
async project_info(params) {
|
|
104
|
+
const result = await project_info(params, this.config, saveConfig);
|
|
105
|
+
// Update local config if action was 'set'
|
|
106
|
+
if (params?.action === 'set') {
|
|
107
|
+
this.config = getConfig();
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Project structure tool
|
|
113
|
+
async project_structure(params) {
|
|
114
|
+
const result = await project_structure(params, this.config, saveConfig);
|
|
115
|
+
// Update local config if action was 'set'
|
|
116
|
+
if (params?.action === 'set') {
|
|
117
|
+
this.config = getConfig();
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// API standards tool
|
|
123
|
+
async api_standards(params) {
|
|
124
|
+
const result = await api_standards(params, this.config, saveConfig);
|
|
125
|
+
// Update local config if action was 'set'
|
|
126
|
+
if (params?.action === 'set') {
|
|
127
|
+
this.config = getConfig();
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Development standards tool
|
|
133
|
+
async development_standards(params) {
|
|
134
|
+
const result = await development_standards(params, this.config, saveConfig);
|
|
135
|
+
// Update local config if action was 'set'
|
|
136
|
+
if (params?.action === 'set') {
|
|
137
|
+
this.config = getConfig();
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Database standards tool
|
|
143
|
+
async database_standards(params) {
|
|
144
|
+
const result = await database_standards(params, this.config, saveConfig);
|
|
145
|
+
// Update local config if action was 'set'
|
|
146
|
+
if (params?.action === 'set') {
|
|
147
|
+
this.config = getConfig();
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// API debug tool
|
|
153
|
+
async api_debug(params) {
|
|
154
|
+
const result = await api_debug(params, this.config, saveConfig);
|
|
155
|
+
// Update local config if action was 'set'
|
|
156
|
+
if (params?.action === 'set') {
|
|
157
|
+
this.config = getConfig();
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
// Handle JSON-RPC requests
|
|
166
|
+
async handleRequest(request) {
|
|
167
|
+
try {
|
|
168
|
+
const { jsonrpc, id, method, params } = request;
|
|
169
|
+
|
|
170
|
+
if (jsonrpc !== '2.0') {
|
|
171
|
+
throw new Error('Unsupported JSON-RPC version');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let result = null;
|
|
175
|
+
let error = null;
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
if (method === 'initialize') {
|
|
179
|
+
// If already initialized, return success but don't re-initialize
|
|
180
|
+
if (!this.initialized) {
|
|
181
|
+
this.initialized = true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Build server capabilities to match client capabilities
|
|
185
|
+
const serverCapabilities = {
|
|
186
|
+
tools: {
|
|
187
|
+
listChanged: false
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// If client supports prompts, we also support it
|
|
192
|
+
if (params?.capabilities?.prompts) {
|
|
193
|
+
serverCapabilities.prompts = {
|
|
194
|
+
listChanged: false
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// If client supports resources, we also support it
|
|
199
|
+
if (params?.capabilities?.resources) {
|
|
200
|
+
serverCapabilities.resources = {
|
|
201
|
+
listChanged: false
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// If client supports logging, we also support it
|
|
206
|
+
if (params?.capabilities?.logging) {
|
|
207
|
+
serverCapabilities.logging = {
|
|
208
|
+
listChanged: false
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// If client supports roots, we also support it
|
|
213
|
+
if (params?.capabilities?.roots) {
|
|
214
|
+
serverCapabilities.roots = {
|
|
215
|
+
listChanged: false
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
result = {
|
|
220
|
+
protocolVersion: params?.protocolVersion || '2025-06-18',
|
|
221
|
+
capabilities: serverCapabilities,
|
|
222
|
+
serverInfo: {
|
|
223
|
+
name: this.name,
|
|
224
|
+
version: this.version
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
} else if (method === 'tools/list') {
|
|
228
|
+
const tools = [];
|
|
229
|
+
|
|
230
|
+
// Add all tools since config is always available now
|
|
231
|
+
tools.push({
|
|
232
|
+
name: 'project_info',
|
|
233
|
+
description: 'Get or set project information in configuration file',
|
|
234
|
+
inputSchema: {
|
|
235
|
+
type: 'object',
|
|
236
|
+
properties: {
|
|
237
|
+
action: {
|
|
238
|
+
type: 'string',
|
|
239
|
+
enum: ['get', 'set'],
|
|
240
|
+
description: 'Action to perform: "get" to retrieve info, "set" to update info'
|
|
241
|
+
},
|
|
242
|
+
key: {
|
|
243
|
+
type: 'string',
|
|
244
|
+
enum: ['projectName', 'developmentLanguage', 'basicInfo'],
|
|
245
|
+
description: 'Key to update when action is "set" (projectName|developmentLanguage|basicInfo)'
|
|
246
|
+
},
|
|
247
|
+
value: {
|
|
248
|
+
description: 'Value to set when action is "set"'
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
required: ['action'],
|
|
252
|
+
anyOf: [
|
|
253
|
+
{
|
|
254
|
+
properties: {
|
|
255
|
+
action: { const: 'get' }
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
properties: {
|
|
260
|
+
action: { const: 'set' },
|
|
261
|
+
key: { type: 'string' },
|
|
262
|
+
value: {}
|
|
263
|
+
},
|
|
264
|
+
required: ['key', 'value']
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
tools.push( {
|
|
271
|
+
name: 'project_structure',
|
|
272
|
+
description: 'Get, set or delete project structure in configuration',
|
|
273
|
+
inputSchema: {
|
|
274
|
+
type: 'object',
|
|
275
|
+
properties: {
|
|
276
|
+
action: {
|
|
277
|
+
type: 'string',
|
|
278
|
+
enum: ['get', 'set', 'delete'],
|
|
279
|
+
description: 'Action to perform: "get" to retrieve structure, "set" to update structure, "delete" to delete structure item'
|
|
280
|
+
},
|
|
281
|
+
structure: {
|
|
282
|
+
type: 'array',
|
|
283
|
+
description: 'Array of structure items with path and description (required for "set" action)',
|
|
284
|
+
items: {
|
|
285
|
+
type: 'object',
|
|
286
|
+
properties: {
|
|
287
|
+
path: {
|
|
288
|
+
type: 'string',
|
|
289
|
+
description: 'Path of the structure item'
|
|
290
|
+
},
|
|
291
|
+
description: {
|
|
292
|
+
type: 'string',
|
|
293
|
+
description: 'Description of the structure item'
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
required: ['path', 'description']
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
path: {
|
|
300
|
+
type: 'string',
|
|
301
|
+
description: 'Path to delete when action is "delete"'
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
required: ['action'],
|
|
305
|
+
anyOf: [
|
|
306
|
+
{
|
|
307
|
+
properties: {
|
|
308
|
+
action: { const: 'get' }
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
properties: {
|
|
313
|
+
action: { const: 'set' },
|
|
314
|
+
structure: { type: 'array' }
|
|
315
|
+
},
|
|
316
|
+
required: ['structure']
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
properties: {
|
|
320
|
+
action: { const: 'delete' },
|
|
321
|
+
path: { type: 'string' }
|
|
322
|
+
},
|
|
323
|
+
required: ['path']
|
|
324
|
+
}
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
tools.push( {
|
|
330
|
+
name: 'api_standards',
|
|
331
|
+
description: 'Get, set or delete API interface standards and best practices',
|
|
332
|
+
inputSchema: {
|
|
333
|
+
type: 'object',
|
|
334
|
+
properties: {
|
|
335
|
+
action: {
|
|
336
|
+
type: 'string',
|
|
337
|
+
enum: ['get', 'set', 'delete'],
|
|
338
|
+
description: 'Action to perform: "get" to retrieve standards, "set" to update standards, "delete" to delete header'
|
|
339
|
+
},
|
|
340
|
+
key: {
|
|
341
|
+
type: 'string',
|
|
342
|
+
enum: ['interfaceType', 'successStructure', 'errorStructure', 'basicHeaders', 'requirements'],
|
|
343
|
+
description: 'Key to update when action is "set" (interfaceType|successStructure|errorStructure|basicHeaders|requirements)'
|
|
344
|
+
},
|
|
345
|
+
value: {
|
|
346
|
+
oneOf: [
|
|
347
|
+
{ type: 'string' },
|
|
348
|
+
{ type: 'array' }
|
|
349
|
+
],
|
|
350
|
+
description: 'Value to set when action is "set" (must be string or array)'
|
|
351
|
+
},
|
|
352
|
+
forceOverwrite: {
|
|
353
|
+
type: 'boolean',
|
|
354
|
+
description: 'Force overwrite array values when action is "set" and value is array (default: false)'
|
|
355
|
+
},
|
|
356
|
+
headerName: {
|
|
357
|
+
type: 'string',
|
|
358
|
+
description: 'Header name to delete when action is "delete"'
|
|
359
|
+
},
|
|
360
|
+
requirement: {
|
|
361
|
+
type: 'string',
|
|
362
|
+
description: 'Requirement content to delete when action is "delete"'
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
required: ['action'],
|
|
366
|
+
anyOf: [
|
|
367
|
+
{
|
|
368
|
+
properties: {
|
|
369
|
+
action: { const: 'get' }
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
properties: {
|
|
374
|
+
action: { const: 'set' },
|
|
375
|
+
key: { type: 'string' },
|
|
376
|
+
value: {}
|
|
377
|
+
},
|
|
378
|
+
required: ['key', 'value']
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
properties: {
|
|
382
|
+
action: { const: 'delete' },
|
|
383
|
+
headerName: { type: 'string' }
|
|
384
|
+
},
|
|
385
|
+
required: ['headerName']
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
properties: {
|
|
389
|
+
action: { const: 'delete' },
|
|
390
|
+
requirement: { type: 'string' }
|
|
391
|
+
},
|
|
392
|
+
required: ['requirement']
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
name: 'development_standards',
|
|
399
|
+
description: 'Get, set or delete development standards',
|
|
400
|
+
inputSchema: {
|
|
401
|
+
type: 'object',
|
|
402
|
+
properties: {
|
|
403
|
+
action: {
|
|
404
|
+
type: 'string',
|
|
405
|
+
enum: ['get', 'set', 'delete'],
|
|
406
|
+
description: 'Action to perform: "get" to retrieve standards, "set" to update standards, "delete" to delete standard'
|
|
407
|
+
},
|
|
408
|
+
standards: {
|
|
409
|
+
type: 'array',
|
|
410
|
+
description: 'Array of development standards (required for "set" action)',
|
|
411
|
+
items: {
|
|
412
|
+
type: 'string'
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
forceOverwrite: {
|
|
416
|
+
type: 'boolean',
|
|
417
|
+
description: 'Force overwrite array values when action is "set" and value is array (default: false)'
|
|
418
|
+
},
|
|
419
|
+
standard: {
|
|
420
|
+
type: 'string',
|
|
421
|
+
description: 'Standard content to delete when action is "delete"'
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
required: ['action'],
|
|
425
|
+
anyOf: [
|
|
426
|
+
{
|
|
427
|
+
properties: {
|
|
428
|
+
action: { const: 'get' }
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
properties: {
|
|
433
|
+
action: { const: 'set' },
|
|
434
|
+
standards: { type: 'array' }
|
|
435
|
+
},
|
|
436
|
+
required: ['standards']
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
properties: {
|
|
440
|
+
action: { const: 'delete' },
|
|
441
|
+
standard: { type: 'string' }
|
|
442
|
+
},
|
|
443
|
+
required: ['standard']
|
|
444
|
+
}
|
|
445
|
+
]
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
name: 'database_standards',
|
|
450
|
+
description: 'Get, set or delete database standards',
|
|
451
|
+
inputSchema: {
|
|
452
|
+
type: 'object',
|
|
453
|
+
properties: {
|
|
454
|
+
action: {
|
|
455
|
+
type: 'string',
|
|
456
|
+
enum: ['get', 'set', 'delete'],
|
|
457
|
+
description: 'Action to perform: "get" to retrieve standards, "set" to update standards, "delete" to delete standard'
|
|
458
|
+
},
|
|
459
|
+
standards: {
|
|
460
|
+
type: 'array',
|
|
461
|
+
description: 'Array of database standards (required for "set" action)',
|
|
462
|
+
items: {
|
|
463
|
+
type: 'string'
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
forceOverwrite: {
|
|
467
|
+
type: 'boolean',
|
|
468
|
+
description: 'Force overwrite array values when action is "set" and value is array (default: false)'
|
|
469
|
+
},
|
|
470
|
+
standard: {
|
|
471
|
+
type: 'string',
|
|
472
|
+
description: 'Standard content to delete when action is "delete"'
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
required: ['action'],
|
|
476
|
+
anyOf: [
|
|
477
|
+
{
|
|
478
|
+
properties: {
|
|
479
|
+
action: { const: 'get' }
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
properties: {
|
|
484
|
+
action: { const: 'set' },
|
|
485
|
+
standards: { type: 'array' }
|
|
486
|
+
},
|
|
487
|
+
required: ['standards']
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
properties: {
|
|
491
|
+
action: { const: 'delete' },
|
|
492
|
+
standard: { type: 'string' }
|
|
493
|
+
},
|
|
494
|
+
required: ['standard']
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
tools.push({
|
|
502
|
+
name: 'api_debug',
|
|
503
|
+
description: 'API debugging tool for testing and executing API requests',
|
|
504
|
+
inputSchema: {
|
|
505
|
+
type: 'object',
|
|
506
|
+
properties: {
|
|
507
|
+
action: {
|
|
508
|
+
type: 'string',
|
|
509
|
+
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'
|
|
511
|
+
},
|
|
512
|
+
config: {
|
|
513
|
+
type: 'object',
|
|
514
|
+
description: 'API debug configuration (required for "set" action)',
|
|
515
|
+
properties: {
|
|
516
|
+
baseUrl: {
|
|
517
|
+
type: 'string',
|
|
518
|
+
description: 'Base URL for API requests'
|
|
519
|
+
},
|
|
520
|
+
headers: {
|
|
521
|
+
type: 'object',
|
|
522
|
+
description: 'Common headers for all requests'
|
|
523
|
+
},
|
|
524
|
+
list: {
|
|
525
|
+
type: 'array',
|
|
526
|
+
description: 'List of API endpoints to test',
|
|
527
|
+
items: {
|
|
528
|
+
type: 'object',
|
|
529
|
+
properties: {
|
|
530
|
+
description: {
|
|
531
|
+
type: 'string',
|
|
532
|
+
description: 'API description'
|
|
533
|
+
},
|
|
534
|
+
url: {
|
|
535
|
+
type: 'string',
|
|
536
|
+
description: 'API endpoint URL'
|
|
537
|
+
},
|
|
538
|
+
method: {
|
|
539
|
+
type: 'string',
|
|
540
|
+
enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
|
541
|
+
description: 'HTTP method'
|
|
542
|
+
},
|
|
543
|
+
query: {
|
|
544
|
+
type: 'object',
|
|
545
|
+
description: 'Query parameters for GET requests'
|
|
546
|
+
},
|
|
547
|
+
body: {
|
|
548
|
+
description: 'Request body for POST/PUT requests'
|
|
549
|
+
},
|
|
550
|
+
contentType: {
|
|
551
|
+
type: 'string',
|
|
552
|
+
description: 'Content-Type for request body (optional, will auto-detect if not specified)'
|
|
553
|
+
},
|
|
554
|
+
header: {
|
|
555
|
+
type: 'object',
|
|
556
|
+
description: 'Additional headers for this specific request'
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
required: ['url', 'method']
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
index: {
|
|
565
|
+
type: 'number',
|
|
566
|
+
description: 'Index of API to delete or execute (required for "delete" and "execute" actions)'
|
|
567
|
+
},
|
|
568
|
+
baseUrl: {
|
|
569
|
+
type: 'string',
|
|
570
|
+
description: 'New base URL (required for "updateBaseUrl" action)'
|
|
571
|
+
},
|
|
572
|
+
headers: {
|
|
573
|
+
type: 'object',
|
|
574
|
+
description: 'New headers to add or update (required for "updateHeaders" action)'
|
|
575
|
+
},
|
|
576
|
+
headerName: {
|
|
577
|
+
type: 'string',
|
|
578
|
+
description: 'Name of header to delete (required for "deleteHeader" action)'
|
|
579
|
+
},
|
|
580
|
+
keyword: {
|
|
581
|
+
type: 'string',
|
|
582
|
+
description: 'Search keyword to match against URL or description (required for "search" action)'
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
required: ['action'],
|
|
586
|
+
anyOf: [
|
|
587
|
+
{
|
|
588
|
+
properties: {
|
|
589
|
+
action: { const: 'get' }
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
properties: {
|
|
594
|
+
action: { const: 'set' },
|
|
595
|
+
config: { type: 'object' }
|
|
596
|
+
},
|
|
597
|
+
required: ['config']
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
properties: {
|
|
601
|
+
action: { const: 'delete' },
|
|
602
|
+
index: { type: 'number' }
|
|
603
|
+
},
|
|
604
|
+
required: ['index']
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
properties: {
|
|
608
|
+
action: { const: 'execute' },
|
|
609
|
+
index: { type: 'number' }
|
|
610
|
+
},
|
|
611
|
+
required: ['index']
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
properties: {
|
|
615
|
+
action: { const: 'updateBaseUrl' },
|
|
616
|
+
baseUrl: { type: 'string' }
|
|
617
|
+
},
|
|
618
|
+
required: ['baseUrl']
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
properties: {
|
|
622
|
+
action: { const: 'updateHeaders' },
|
|
623
|
+
headers: { type: 'object' }
|
|
624
|
+
},
|
|
625
|
+
required: ['headers']
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
properties: {
|
|
629
|
+
action: { const: 'deleteHeader' },
|
|
630
|
+
headerName: { type: 'string' }
|
|
631
|
+
},
|
|
632
|
+
required: ['headerName']
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
properties: {
|
|
636
|
+
action: { const: 'search' },
|
|
637
|
+
keyword: { type: 'string' }
|
|
638
|
+
},
|
|
639
|
+
required: ['keyword']
|
|
640
|
+
}
|
|
641
|
+
]
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
result = {
|
|
646
|
+
tools: tools,
|
|
647
|
+
environment: {
|
|
648
|
+
CONFIG_DIR: process.env.CONFIG_DIR || './.setting',
|
|
649
|
+
serverInfo: {
|
|
650
|
+
name: this.name,
|
|
651
|
+
version: this.version
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
} else if (method === 'prompts/list') {
|
|
656
|
+
result = {
|
|
657
|
+
prompts: []
|
|
658
|
+
};
|
|
659
|
+
} else if (method === 'prompts/call') {
|
|
660
|
+
result = {
|
|
661
|
+
messages: [
|
|
662
|
+
{
|
|
663
|
+
role: 'assistant',
|
|
664
|
+
content: [
|
|
665
|
+
{
|
|
666
|
+
type: 'text',
|
|
667
|
+
text: 'Unsupported prompts call'
|
|
668
|
+
}
|
|
669
|
+
]
|
|
670
|
+
}
|
|
671
|
+
]
|
|
672
|
+
};
|
|
673
|
+
} else if (method === 'resources/list') {
|
|
674
|
+
result = {
|
|
675
|
+
resources: []
|
|
676
|
+
};
|
|
677
|
+
} else if (method === 'resources/read') {
|
|
678
|
+
result = {
|
|
679
|
+
contents: [
|
|
680
|
+
{
|
|
681
|
+
uri: 'error://unsupported',
|
|
682
|
+
text: 'Unsupported resources read'
|
|
683
|
+
}
|
|
684
|
+
]
|
|
685
|
+
};
|
|
686
|
+
} else if (method === 'logging/list') {
|
|
687
|
+
result = {
|
|
688
|
+
logs: []
|
|
689
|
+
};
|
|
690
|
+
} else if (method === 'logging/read') {
|
|
691
|
+
result = {
|
|
692
|
+
contents: [
|
|
693
|
+
{
|
|
694
|
+
uri: 'error://unsupported',
|
|
695
|
+
text: 'Unsupported logging read'
|
|
696
|
+
}
|
|
697
|
+
]
|
|
698
|
+
};
|
|
699
|
+
} else if (method === 'roots/list') {
|
|
700
|
+
result = {
|
|
701
|
+
roots: []
|
|
702
|
+
};
|
|
703
|
+
} else if (method === 'roots/read') {
|
|
704
|
+
result = {
|
|
705
|
+
contents: [
|
|
706
|
+
{
|
|
707
|
+
uri: 'error://unsupported',
|
|
708
|
+
text: 'Unsupported roots read'
|
|
709
|
+
}
|
|
710
|
+
]
|
|
711
|
+
};
|
|
712
|
+
} else if (method === 'tools/call') {
|
|
713
|
+
const { name, arguments: args } = params || {};
|
|
714
|
+
|
|
715
|
+
if (!name) {
|
|
716
|
+
throw new Error('Missing tool name');
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Check if method exists
|
|
720
|
+
if (!this[name]) {
|
|
721
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
result = await this[name](args || {});
|
|
725
|
+
|
|
726
|
+
// Tool call results need to be wrapped in content
|
|
727
|
+
result = {
|
|
728
|
+
content: [
|
|
729
|
+
{
|
|
730
|
+
type: 'text',
|
|
731
|
+
text: JSON.stringify(result, null, 2)
|
|
732
|
+
}
|
|
733
|
+
]
|
|
734
|
+
};
|
|
735
|
+
} else if (method === 'ping') {
|
|
736
|
+
result = { pong: true };
|
|
737
|
+
} else if (method === 'shutdown') {
|
|
738
|
+
result = null;
|
|
739
|
+
setTimeout(() => {
|
|
740
|
+
process.exit(0);
|
|
741
|
+
}, 100);
|
|
742
|
+
} else if (method === 'notifications/initialized') {
|
|
743
|
+
// Load configuration on initialization
|
|
744
|
+
this.config = getConfig();
|
|
745
|
+
console.error('Project Standards MCP server initialized');
|
|
746
|
+
} else if (method === 'notifications/exit') {
|
|
747
|
+
result = null;
|
|
748
|
+
process.exit(0);
|
|
749
|
+
} else {
|
|
750
|
+
throw new Error(`Unknown method: ${method}`);
|
|
751
|
+
}
|
|
752
|
+
} catch (err) {
|
|
753
|
+
error = err.message;
|
|
754
|
+
throw err;
|
|
755
|
+
} finally {
|
|
756
|
+
// No logging
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// For notification methods, no response is needed
|
|
760
|
+
if (method === 'notifications/initialized' || method === 'notifications/exit') {
|
|
761
|
+
return null;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// shutdown method needs to return response
|
|
765
|
+
if (method === 'shutdown') {
|
|
766
|
+
return {
|
|
767
|
+
jsonrpc: '2.0',
|
|
768
|
+
id,
|
|
769
|
+
result: null
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
return {
|
|
774
|
+
jsonrpc: '2.0',
|
|
775
|
+
id,
|
|
776
|
+
result
|
|
777
|
+
};
|
|
778
|
+
} catch (error) {
|
|
779
|
+
// Use standard MCP error codes
|
|
780
|
+
let errorCode = -32603; // Internal error
|
|
781
|
+
let errorMessage = error.message;
|
|
782
|
+
|
|
783
|
+
if (error.message.includes('Server not initialized')) {
|
|
784
|
+
errorCode = -32002; // Server not initialized
|
|
785
|
+
} else if (error.message.includes('Unknown method')) {
|
|
786
|
+
errorCode = -32601; // Method not found
|
|
787
|
+
} else if (error.message.includes('Unsupported JSON-RPC version')) {
|
|
788
|
+
errorCode = -32600; // Invalid Request
|
|
789
|
+
}
|
|
790
|
+
return {
|
|
791
|
+
jsonrpc: '2.0',
|
|
792
|
+
id: request.id,
|
|
793
|
+
error: {
|
|
794
|
+
code: errorCode,
|
|
795
|
+
message: errorMessage
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Start server
|
|
802
|
+
async start() {
|
|
803
|
+
console.error('MCP Project Standards server started');
|
|
804
|
+
|
|
805
|
+
// Listen to stdin
|
|
806
|
+
process.stdin.setEncoding('utf8');
|
|
807
|
+
|
|
808
|
+
process.stdin.on('data', async (data) => {
|
|
809
|
+
try {
|
|
810
|
+
const lines = data.toString().trim().split('\n');
|
|
811
|
+
|
|
812
|
+
for (const line of lines) {
|
|
813
|
+
if (line.trim()) {
|
|
814
|
+
try {
|
|
815
|
+
const request = JSON.parse(line);
|
|
816
|
+
const response = await this.handleRequest(request);
|
|
817
|
+
if (response) {
|
|
818
|
+
console.log(JSON.stringify(response));
|
|
819
|
+
}
|
|
820
|
+
} catch (requestError) {
|
|
821
|
+
console.error('Error processing individual request:', requestError.message);
|
|
822
|
+
const errorResponse = {
|
|
823
|
+
jsonrpc: '2.0',
|
|
824
|
+
id: null,
|
|
825
|
+
error: {
|
|
826
|
+
code: -32603,
|
|
827
|
+
message: `Internal error: ${requestError.message}`
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
console.log(JSON.stringify(errorResponse));
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
} catch (error) {
|
|
835
|
+
console.error('Error processing data:', error.message);
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
// Handle process signals
|
|
840
|
+
process.on('SIGTERM', async () => {
|
|
841
|
+
console.error('Received SIGTERM signal, shutting down server...');
|
|
842
|
+
process.exit(0);
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
process.on('SIGINT', async () => {
|
|
846
|
+
console.error('Received SIGINT signal, shutting down server...');
|
|
847
|
+
process.exit(0);
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
// Handle uncaught exceptions
|
|
851
|
+
process.on('uncaughtException', (error) => {
|
|
852
|
+
console.error('Uncaught exception:', error);
|
|
853
|
+
process.exit(1);
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
857
|
+
console.error('Unhandled Promise rejection:', reason);
|
|
858
|
+
process.exit(1);
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// Start server
|
|
864
|
+
async function main() {
|
|
865
|
+
console.error('Starting MCP Project Standards server...');
|
|
866
|
+
const server = new ProjectStandardsMCPServer();
|
|
867
|
+
await server.start();
|
|
868
|
+
console.error('MCP Project Standards server started successfully');
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
main().catch(error => {
|
|
872
|
+
console.error(error);
|
|
873
|
+
process.exit(1);
|
|
874
|
+
});
|