优化了组件属性的设置的接口,使AI调用起来更简单,更准确。每次更新场景信息、组件信息或者节点信息,端口将会返回最新的信息供AI进行追踪和比对。

This commit is contained in:
root
2025-07-23 18:19:12 +08:00
parent d7ab237707
commit ae604480ab
14 changed files with 2978 additions and 178 deletions

View File

@@ -15,6 +15,7 @@ import { SceneAdvancedTools } from './tools/scene-advanced-tools';
import { SceneViewTools } from './tools/scene-view-tools';
import { ReferenceImageTools } from './tools/reference-image-tools';
import { AssetAdvancedTools } from './tools/asset-advanced-tools';
import { ValidationTools } from './tools/validation-tools';
export class MCPServer {
private settings: MCPServerSettings;
@@ -44,6 +45,7 @@ export class MCPServer {
this.tools.sceneView = new SceneViewTools();
this.tools.referenceImage = new ReferenceImageTools();
this.tools.assetAdvanced = new AssetAdvancedTools();
this.tools.validation = new ValidationTools();
console.log('[MCPServer] Tools initialized successfully');
} catch (error) {
console.error('[MCPServer] Error initializing tools:', error);
@@ -146,6 +148,11 @@ export class MCPServer {
} else if (pathname === '/health' && req.method === 'GET') {
res.writeHead(200);
res.end(JSON.stringify({ status: 'ok', tools: this.toolsList.length }));
} else if (pathname?.startsWith('/api/') && req.method === 'POST') {
await this.handleSimpleAPIRequest(req, res, pathname);
} else if (pathname === '/api/tools' && req.method === 'GET') {
res.writeHead(200);
res.end(JSON.stringify({ tools: this.getSimplifiedToolsList() }));
} else {
res.writeHead(404);
res.end(JSON.stringify({ error: 'Not found' }));
@@ -166,11 +173,25 @@ export class MCPServer {
req.on('end', async () => {
try {
const message = JSON.parse(body);
// Enhanced JSON parsing with better error handling
let message;
try {
message = JSON.parse(body);
} catch (parseError: any) {
// Try to fix common JSON issues
const fixedBody = this.fixCommonJsonIssues(body);
try {
message = JSON.parse(fixedBody);
console.log('[MCPServer] Fixed JSON parsing issue');
} catch (secondError) {
throw new Error(`JSON parsing failed: ${parseError.message}. Original body: ${body.substring(0, 500)}...`);
}
}
const response = await this.handleMessage(message);
res.writeHead(200);
res.end(JSON.stringify(response));
} catch (error) {
} catch (error: any) {
console.error('Error handling MCP request:', error);
res.writeHead(400);
res.end(JSON.stringify({
@@ -178,7 +199,7 @@ export class MCPServer {
id: null,
error: {
code: -32700,
message: 'Parse error'
message: `Parse error: ${error.message}`
}
}));
}
@@ -234,6 +255,27 @@ export class MCPServer {
}
}
private fixCommonJsonIssues(jsonStr: string): string {
let fixed = jsonStr;
// Fix common escape character issues
fixed = fixed
// Fix unescaped quotes in strings
.replace(/([^\\])"([^"]*[^\\])"([^,}\]:])/g, '$1\\"$2\\"$3')
// Fix unescaped backslashes
.replace(/([^\\])\\([^"\\\/bfnrt])/g, '$1\\\\$2')
// Fix trailing commas
.replace(/,(\s*[}\]])/g, '$1')
// Fix single quotes (should be double quotes)
.replace(/'/g, '"')
// Fix common control characters
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t');
return fixed;
}
public stop(): void {
if (this.httpServer) {
this.httpServer.close();
@@ -252,6 +294,123 @@ export class MCPServer {
};
}
private async handleSimpleAPIRequest(req: http.IncomingMessage, res: http.ServerResponse, pathname: string): Promise<void> {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', async () => {
try {
// Extract tool name from path like /api/node/set_position
const pathParts = pathname.split('/').filter(p => p);
if (pathParts.length < 3) {
res.writeHead(400);
res.end(JSON.stringify({ error: 'Invalid API path. Use /api/{category}/{tool_name}' }));
return;
}
const category = pathParts[1];
const toolName = pathParts[2];
const fullToolName = `${category}_${toolName}`;
// Parse parameters with enhanced error handling
let params;
try {
params = body ? JSON.parse(body) : {};
} catch (parseError: any) {
// Try to fix JSON issues
const fixedBody = this.fixCommonJsonIssues(body);
try {
params = JSON.parse(fixedBody);
console.log('[MCPServer] Fixed API JSON parsing issue');
} catch (secondError: any) {
res.writeHead(400);
res.end(JSON.stringify({
error: 'Invalid JSON in request body',
details: parseError.message,
receivedBody: body.substring(0, 200)
}));
return;
}
}
// Execute tool
const result = await this.executeToolCall(fullToolName, params);
res.writeHead(200);
res.end(JSON.stringify({
success: true,
tool: fullToolName,
result: result
}));
} catch (error: any) {
console.error('Simple API error:', error);
res.writeHead(500);
res.end(JSON.stringify({
success: false,
error: error.message,
tool: pathname
}));
}
});
}
private getSimplifiedToolsList(): any[] {
return this.toolsList.map(tool => {
const parts = tool.name.split('_');
const category = parts[0];
const toolName = parts.slice(1).join('_');
return {
name: tool.name,
category: category,
toolName: toolName,
description: tool.description,
apiPath: `/api/${category}/${toolName}`,
curlExample: this.generateCurlExample(category, toolName, tool.inputSchema)
};
});
}
private generateCurlExample(category: string, toolName: string, schema: any): string {
// Generate sample parameters based on schema
const sampleParams = this.generateSampleParams(schema);
const jsonString = JSON.stringify(sampleParams, null, 2);
return `curl -X POST http://127.0.0.1:8585/api/${category}/${toolName} \\
-H "Content-Type: application/json" \\
-d '${jsonString}'`;
}
private generateSampleParams(schema: any): any {
if (!schema || !schema.properties) return {};
const sample: any = {};
for (const [key, prop] of Object.entries(schema.properties as any)) {
const propSchema = prop as any;
switch (propSchema.type) {
case 'string':
sample[key] = propSchema.default || 'example_string';
break;
case 'number':
sample[key] = propSchema.default || 42;
break;
case 'boolean':
sample[key] = propSchema.default || true;
break;
case 'object':
sample[key] = propSchema.default || { x: 0, y: 0, z: 0 };
break;
default:
sample[key] = 'example_value';
}
}
return sample;
}
public updateSettings(settings: MCPServerSettings) {
this.settings = settings;
if (this.httpServer) {