@fastcoder/vision-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 +263 -0
- package/README.zh-CN.md +210 -0
- package/build/core/api-common.d.ts +89 -0
- package/build/core/api-common.d.ts.map +1 -0
- package/build/core/api-common.js +119 -0
- package/build/core/api-common.js.map +1 -0
- package/build/core/base-image-service.d.ts +38 -0
- package/build/core/base-image-service.d.ts.map +1 -0
- package/build/core/base-image-service.js +92 -0
- package/build/core/base-image-service.js.map +1 -0
- package/build/core/chat-service.d.ts +42 -0
- package/build/core/chat-service.d.ts.map +1 -0
- package/build/core/chat-service.js +97 -0
- package/build/core/chat-service.js.map +1 -0
- package/build/core/environment.d.ts +76 -0
- package/build/core/environment.d.ts.map +1 -0
- package/build/core/environment.js +132 -0
- package/build/core/environment.js.map +1 -0
- package/build/core/error-handler.d.ts +124 -0
- package/build/core/error-handler.d.ts.map +1 -0
- package/build/core/error-handler.js +248 -0
- package/build/core/error-handler.js.map +1 -0
- package/build/core/file-service.d.ts +36 -0
- package/build/core/file-service.d.ts.map +1 -0
- package/build/core/file-service.js +141 -0
- package/build/core/file-service.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +119 -0
- package/build/index.js.map +1 -0
- package/build/prompts/data-viz.d.ts +5 -0
- package/build/prompts/data-viz.d.ts.map +1 -0
- package/build/prompts/data-viz.js +98 -0
- package/build/prompts/data-viz.js.map +1 -0
- package/build/prompts/diagram-analysis.d.ts +5 -0
- package/build/prompts/diagram-analysis.d.ts.map +1 -0
- package/build/prompts/diagram-analysis.js +102 -0
- package/build/prompts/diagram-analysis.js.map +1 -0
- package/build/prompts/error-diagnosis.d.ts +5 -0
- package/build/prompts/error-diagnosis.d.ts.map +1 -0
- package/build/prompts/error-diagnosis.js +69 -0
- package/build/prompts/error-diagnosis.js.map +1 -0
- package/build/prompts/general-image.d.ts +5 -0
- package/build/prompts/general-image.d.ts.map +1 -0
- package/build/prompts/general-image.js +45 -0
- package/build/prompts/general-image.js.map +1 -0
- package/build/prompts/index.d.ts +8 -0
- package/build/prompts/index.d.ts.map +1 -0
- package/build/prompts/index.js +8 -0
- package/build/prompts/index.js.map +1 -0
- package/build/prompts/text-extraction.d.ts +5 -0
- package/build/prompts/text-extraction.d.ts.map +1 -0
- package/build/prompts/text-extraction.js +45 -0
- package/build/prompts/text-extraction.js.map +1 -0
- package/build/prompts/ui-diff.d.ts +5 -0
- package/build/prompts/ui-diff.d.ts.map +1 -0
- package/build/prompts/ui-diff.js +190 -0
- package/build/prompts/ui-diff.js.map +1 -0
- package/build/prompts/ui-to-artifact.d.ts +10 -0
- package/build/prompts/ui-to-artifact.d.ts.map +1 -0
- package/build/prompts/ui-to-artifact.js +89 -0
- package/build/prompts/ui-to-artifact.js.map +1 -0
- package/build/tools/data-viz.d.ts +5 -0
- package/build/tools/data-viz.d.ts.map +1 -0
- package/build/tools/data-viz.js +93 -0
- package/build/tools/data-viz.js.map +1 -0
- package/build/tools/diagram-analysis.d.ts +5 -0
- package/build/tools/diagram-analysis.d.ts.map +1 -0
- package/build/tools/diagram-analysis.js +93 -0
- package/build/tools/diagram-analysis.js.map +1 -0
- package/build/tools/error-diagnosis.d.ts +5 -0
- package/build/tools/error-diagnosis.d.ts.map +1 -0
- package/build/tools/error-diagnosis.js +93 -0
- package/build/tools/error-diagnosis.js.map +1 -0
- package/build/tools/general-image.d.ts +5 -0
- package/build/tools/general-image.d.ts.map +1 -0
- package/build/tools/general-image.js +81 -0
- package/build/tools/general-image.js.map +1 -0
- package/build/tools/index.d.ts +8 -0
- package/build/tools/index.d.ts.map +1 -0
- package/build/tools/index.js +9 -0
- package/build/tools/index.js.map +1 -0
- package/build/tools/text-extraction.d.ts +5 -0
- package/build/tools/text-extraction.d.ts.map +1 -0
- package/build/tools/text-extraction.js +93 -0
- package/build/tools/text-extraction.js.map +1 -0
- package/build/tools/ui-diff.d.ts +5 -0
- package/build/tools/ui-diff.d.ts.map +1 -0
- package/build/tools/ui-diff.js +98 -0
- package/build/tools/ui-diff.js.map +1 -0
- package/build/tools/ui-to-artifact.d.ts +5 -0
- package/build/tools/ui-to-artifact.d.ts.map +1 -0
- package/build/tools/ui-to-artifact.js +117 -0
- package/build/tools/ui-to-artifact.js.map +1 -0
- package/build/types/index.d.ts +26 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +43 -0
- package/build/types/index.js.map +1 -0
- package/build/utils/logger.d.ts +24 -0
- package/build/utils/logger.d.ts.map +1 -0
- package/build/utils/logger.js +119 -0
- package/build/utils/logger.js.map +1 -0
- package/build/utils/validation.d.ts +87 -0
- package/build/utils/validation.d.ts.map +1 -0
- package/build/utils/validation.js +155 -0
- package/build/utils/validation.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"general-image.d.ts","sourceRoot":"","sources":["../../src/tools/general-image.ts"],"names":[],"mappings":"AA4CA;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAgElE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { FileNotFoundError, ApiError, ValidationError } from '../types/index.js';
|
|
3
|
+
import { CommonSchemas } from '../utils/validation.js';
|
|
4
|
+
import { formatMcpResponse, createSuccessResponse, createErrorResponse, withRetry } from '../core/api-common.js';
|
|
5
|
+
import { BaseImageAnalysisService } from '../core/base-image-service.js';
|
|
6
|
+
import { GENERAL_IMAGE_ANALYSIS_PROMPT } from '../prompts/general-image.js';
|
|
7
|
+
/**
|
|
8
|
+
* General Image Analysis service - General-purpose image analysis
|
|
9
|
+
*/
|
|
10
|
+
class GeneralImageAnalysisService extends BaseImageAnalysisService {
|
|
11
|
+
/**
|
|
12
|
+
* Analyze general image
|
|
13
|
+
*/
|
|
14
|
+
async analyzeImage(imageSource, userPrompt) {
|
|
15
|
+
console.info('Starting general image analysis', {
|
|
16
|
+
imageSource,
|
|
17
|
+
prompt: userPrompt
|
|
18
|
+
});
|
|
19
|
+
// Validate prompt
|
|
20
|
+
this.validatePrompt(userPrompt, 'general-image-analysis');
|
|
21
|
+
// Process image
|
|
22
|
+
const imageContent = await this.processImageSource(imageSource);
|
|
23
|
+
// Execute analysis
|
|
24
|
+
return await this.executeVisionAnalysis(GENERAL_IMAGE_ANALYSIS_PROMPT, userPrompt, [imageContent], 'general-image-analysis');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Register General Image Analysis tool with MCP server
|
|
29
|
+
*/
|
|
30
|
+
export function registerGeneralImageAnalysisTool(server) {
|
|
31
|
+
const service = new GeneralImageAnalysisService();
|
|
32
|
+
const retryableAnalyze = withRetry(service.analyzeImage.bind(service), 2, 1000);
|
|
33
|
+
server.tool('analyze_image', `General-purpose image analysis for scenarios not covered by specialized tools.`, {
|
|
34
|
+
image_source: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1, 'Image source cannot be empty')
|
|
37
|
+
.describe('Local file path or remote URL to the image'),
|
|
38
|
+
prompt: z
|
|
39
|
+
.string()
|
|
40
|
+
.min(1, 'Prompt cannot be empty')
|
|
41
|
+
.describe('Detailed description of what you want to analyze')
|
|
42
|
+
}, async (params) => {
|
|
43
|
+
try {
|
|
44
|
+
// Validate parameters
|
|
45
|
+
const validationSchema = CommonSchemas.filePath
|
|
46
|
+
? z.object({
|
|
47
|
+
image_source: CommonSchemas.filePath,
|
|
48
|
+
prompt: CommonSchemas.nonEmptyString
|
|
49
|
+
})
|
|
50
|
+
: z.object({
|
|
51
|
+
image_source: CommonSchemas.nonEmptyString,
|
|
52
|
+
prompt: CommonSchemas.nonEmptyString
|
|
53
|
+
});
|
|
54
|
+
const validated = validationSchema.safeParse(params);
|
|
55
|
+
if (!validated.success) {
|
|
56
|
+
const errorResponse = createErrorResponse(`Validation failed: ${validated.error.errors?.map(e => e.message).join(', ')}`);
|
|
57
|
+
return formatMcpResponse(errorResponse);
|
|
58
|
+
}
|
|
59
|
+
// Execute analysis
|
|
60
|
+
const result = await retryableAnalyze(validated.data.image_source, validated.data.prompt);
|
|
61
|
+
return formatMcpResponse(createSuccessResponse(result));
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
let errorResponse;
|
|
65
|
+
if (error instanceof FileNotFoundError) {
|
|
66
|
+
errorResponse = createErrorResponse(`Image file not found: ${error.message}`);
|
|
67
|
+
}
|
|
68
|
+
else if (error instanceof ValidationError) {
|
|
69
|
+
errorResponse = createErrorResponse(`Validation error: ${error.message}`);
|
|
70
|
+
}
|
|
71
|
+
else if (error instanceof ApiError) {
|
|
72
|
+
errorResponse = createErrorResponse(`API error: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
errorResponse = createErrorResponse(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
76
|
+
}
|
|
77
|
+
return formatMcpResponse(errorResponse);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=general-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"general-image.js","sourceRoot":"","sources":["../../src/tools/general-image.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { registerUiToArtifactTool } from './ui-to-artifact.js';
|
|
2
|
+
export { registerTextExtractionTool } from './text-extraction.js';
|
|
3
|
+
export { registerErrorDiagnosisTool } from './error-diagnosis.js';
|
|
4
|
+
export { registerDiagramAnalysisTool } from './diagram-analysis.js';
|
|
5
|
+
export { registerDataVizAnalysisTool } from './data-viz.js';
|
|
6
|
+
export { registerUiDiffCheckTool } from './ui-diff.js';
|
|
7
|
+
export { registerGeneralImageAnalysisTool } from './general-image.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Re-export all tools for easier imports
|
|
2
|
+
export { registerUiToArtifactTool } from './ui-to-artifact.js';
|
|
3
|
+
export { registerTextExtractionTool } from './text-extraction.js';
|
|
4
|
+
export { registerErrorDiagnosisTool } from './error-diagnosis.js';
|
|
5
|
+
export { registerDiagramAnalysisTool } from './diagram-analysis.js';
|
|
6
|
+
export { registerDataVizAnalysisTool } from './data-viz.js';
|
|
7
|
+
export { registerUiDiffCheckTool } from './ui-diff.js';
|
|
8
|
+
export { registerGeneralImageAnalysisTool } from './general-image.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-extraction.d.ts","sourceRoot":"","sources":["../../src/tools/text-extraction.ts"],"names":[],"mappings":"AAoDA;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAuE5D"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { FileNotFoundError, ApiError, ValidationError } from '../types/index.js';
|
|
3
|
+
import { CommonSchemas } from '../utils/validation.js';
|
|
4
|
+
import { formatMcpResponse, createSuccessResponse, createErrorResponse, withRetry } from '../core/api-common.js';
|
|
5
|
+
import { BaseImageAnalysisService } from '../core/base-image-service.js';
|
|
6
|
+
import { TEXT_EXTRACTION_PROMPT } from '../prompts/text-extraction.js';
|
|
7
|
+
/**
|
|
8
|
+
* Text Extraction service - OCR text extraction from screenshots
|
|
9
|
+
*/
|
|
10
|
+
class TextExtractionService extends BaseImageAnalysisService {
|
|
11
|
+
/**
|
|
12
|
+
* Extract text from screenshot
|
|
13
|
+
*/
|
|
14
|
+
async extractText(imageSource, userPrompt, programmingLanguage) {
|
|
15
|
+
console.info('Starting text extraction', {
|
|
16
|
+
imageSource,
|
|
17
|
+
prompt: userPrompt,
|
|
18
|
+
programmingLanguage
|
|
19
|
+
});
|
|
20
|
+
// Validate prompt
|
|
21
|
+
this.validatePrompt(userPrompt, 'text-extraction');
|
|
22
|
+
// If programming language is provided, enhance the prompt
|
|
23
|
+
let enhancedPrompt = userPrompt;
|
|
24
|
+
if (programmingLanguage && programmingLanguage.trim()) {
|
|
25
|
+
enhancedPrompt = `${userPrompt}\n\n<language_hint>The code is in ${programmingLanguage}.</language_hint>`;
|
|
26
|
+
}
|
|
27
|
+
// Process image
|
|
28
|
+
const imageContent = await this.processImageSource(imageSource);
|
|
29
|
+
// Execute analysis
|
|
30
|
+
return await this.executeVisionAnalysis(TEXT_EXTRACTION_PROMPT, enhancedPrompt, [imageContent], 'text-extraction');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Register Text Extraction tool with MCP server
|
|
35
|
+
*/
|
|
36
|
+
export function registerTextExtractionTool(server) {
|
|
37
|
+
const service = new TextExtractionService();
|
|
38
|
+
const retryableExtract = withRetry(service.extractText.bind(service), 2, 1000);
|
|
39
|
+
server.tool('extract_text_from_screenshot', `Extract and recognize text from screenshots using advanced OCR capabilities.`, {
|
|
40
|
+
image_source: z
|
|
41
|
+
.string()
|
|
42
|
+
.min(1, 'Image source cannot be empty')
|
|
43
|
+
.describe('Local file path or remote URL to the image containing text to extract'),
|
|
44
|
+
prompt: z
|
|
45
|
+
.string()
|
|
46
|
+
.min(1, 'Prompt cannot be empty')
|
|
47
|
+
.describe('Instructions for text extraction - describe what text to extract or any special requirements'),
|
|
48
|
+
programming_language: z
|
|
49
|
+
.string()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Optional hint about the programming language in the image (e.g., javascript, python, go)')
|
|
52
|
+
}, async (params) => {
|
|
53
|
+
try {
|
|
54
|
+
// Validate parameters
|
|
55
|
+
const validationSchema = CommonSchemas.filePath
|
|
56
|
+
? z.object({
|
|
57
|
+
image_source: CommonSchemas.filePath,
|
|
58
|
+
prompt: CommonSchemas.nonEmptyString,
|
|
59
|
+
programming_language: z.string().optional()
|
|
60
|
+
})
|
|
61
|
+
: z.object({
|
|
62
|
+
image_source: CommonSchemas.nonEmptyString,
|
|
63
|
+
prompt: CommonSchemas.nonEmptyString,
|
|
64
|
+
programming_language: z.string().optional()
|
|
65
|
+
});
|
|
66
|
+
const validated = validationSchema.safeParse(params);
|
|
67
|
+
if (!validated.success) {
|
|
68
|
+
const errorResponse = createErrorResponse(`Validation failed: ${validated.error.errors?.map(e => e.message).join(', ')}`);
|
|
69
|
+
return formatMcpResponse(errorResponse);
|
|
70
|
+
}
|
|
71
|
+
// Execute extraction
|
|
72
|
+
const result = await retryableExtract(validated.data.image_source, validated.data.prompt, validated.data.programming_language);
|
|
73
|
+
return formatMcpResponse(createSuccessResponse(result));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
let errorResponse;
|
|
77
|
+
if (error instanceof FileNotFoundError) {
|
|
78
|
+
errorResponse = createErrorResponse(`Image file not found: ${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
else if (error instanceof ValidationError) {
|
|
81
|
+
errorResponse = createErrorResponse(`Validation error: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
else if (error instanceof ApiError) {
|
|
84
|
+
errorResponse = createErrorResponse(`API error: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
errorResponse = createErrorResponse(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
88
|
+
}
|
|
89
|
+
return formatMcpResponse(errorResponse);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=text-extraction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-extraction.js","sourceRoot":"","sources":["../../src/tools/text-extraction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-diff.d.ts","sourceRoot":"","sources":["../../src/tools/ui-diff.ts"],"names":[],"mappings":"AAyDA;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAuEzD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { FileNotFoundError, ApiError, ValidationError } from '../types/index.js';
|
|
3
|
+
import { CommonSchemas } from '../utils/validation.js';
|
|
4
|
+
import { formatMcpResponse, createSuccessResponse, createErrorResponse, withRetry } from '../core/api-common.js';
|
|
5
|
+
import { BaseImageAnalysisService } from '../core/base-image-service.js';
|
|
6
|
+
import { UI_DIFF_CHECK_PROMPT } from '../prompts/ui-diff.js';
|
|
7
|
+
/**
|
|
8
|
+
* UI Diff Check service - Compare two UI screenshots
|
|
9
|
+
*/
|
|
10
|
+
class UiDiffCheckService extends BaseImageAnalysisService {
|
|
11
|
+
/**
|
|
12
|
+
* Compare two UI screenshots
|
|
13
|
+
*/
|
|
14
|
+
async compareUiScreenshots(expectedImageSource, actualImageSource, userPrompt) {
|
|
15
|
+
console.info('Starting UI diff check', {
|
|
16
|
+
expectedImageSource,
|
|
17
|
+
actualImageSource,
|
|
18
|
+
prompt: userPrompt
|
|
19
|
+
});
|
|
20
|
+
// Validate prompt
|
|
21
|
+
this.validatePrompt(userPrompt, 'ui-diff-check');
|
|
22
|
+
// Enhance the prompt to clarify which is expected vs actual
|
|
23
|
+
const enhancedPrompt = `<images>
|
|
24
|
+
The first image is EXPECTED/REFERENCE design (the target).
|
|
25
|
+
The second image is ACTUAL/CURRENT implementation (what needs to be checked).
|
|
26
|
+
</images>
|
|
27
|
+
|
|
28
|
+
${userPrompt}`;
|
|
29
|
+
// Process both images
|
|
30
|
+
const imageContents = await this.processMultipleImageSources([
|
|
31
|
+
expectedImageSource,
|
|
32
|
+
actualImageSource
|
|
33
|
+
]);
|
|
34
|
+
// Execute analysis
|
|
35
|
+
return await this.executeVisionAnalysis(UI_DIFF_CHECK_PROMPT, enhancedPrompt, imageContents, 'ui-diff-check');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Register UI Diff Check tool with MCP server
|
|
40
|
+
*/
|
|
41
|
+
export function registerUiDiffCheckTool(server) {
|
|
42
|
+
const service = new UiDiffCheckService();
|
|
43
|
+
const retryableCompare = withRetry(service.compareUiScreenshots.bind(service), 2, 1000);
|
|
44
|
+
server.tool('ui_diff_check', `Compare two UI screenshots to identify visual differences and implementation discrepancies.`, {
|
|
45
|
+
expected_image_source: z
|
|
46
|
+
.string()
|
|
47
|
+
.min(1, 'Expected image source cannot be empty')
|
|
48
|
+
.describe('Local file path or remote URL to the expected/reference image'),
|
|
49
|
+
actual_image_source: z
|
|
50
|
+
.string()
|
|
51
|
+
.min(1, 'Actual image source cannot be empty')
|
|
52
|
+
.describe('Local file path or remote URL to the actual implementation image'),
|
|
53
|
+
prompt: z
|
|
54
|
+
.string()
|
|
55
|
+
.min(1, 'Prompt cannot be empty')
|
|
56
|
+
.describe('Instructions for comparison')
|
|
57
|
+
}, async (params) => {
|
|
58
|
+
try {
|
|
59
|
+
// Validate parameters
|
|
60
|
+
const validationSchema = CommonSchemas.filePath
|
|
61
|
+
? z.object({
|
|
62
|
+
expected_image_source: CommonSchemas.filePath,
|
|
63
|
+
actual_image_source: CommonSchemas.filePath,
|
|
64
|
+
prompt: CommonSchemas.nonEmptyString
|
|
65
|
+
})
|
|
66
|
+
: z.object({
|
|
67
|
+
expected_image_source: CommonSchemas.nonEmptyString,
|
|
68
|
+
actual_image_source: CommonSchemas.nonEmptyString,
|
|
69
|
+
prompt: CommonSchemas.nonEmptyString
|
|
70
|
+
});
|
|
71
|
+
const validated = validationSchema.safeParse(params);
|
|
72
|
+
if (!validated.success) {
|
|
73
|
+
const errorResponse = createErrorResponse(`Validation failed: ${validated.error.errors?.map(e => e.message).join(', ')}`);
|
|
74
|
+
return formatMcpResponse(errorResponse);
|
|
75
|
+
}
|
|
76
|
+
// Execute comparison
|
|
77
|
+
const result = await retryableCompare(validated.data.expected_image_source, validated.data.actual_image_source, validated.data.prompt);
|
|
78
|
+
return formatMcpResponse(createSuccessResponse(result));
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
let errorResponse;
|
|
82
|
+
if (error instanceof FileNotFoundError) {
|
|
83
|
+
errorResponse = createErrorResponse(`Image file not found: ${error.message}`);
|
|
84
|
+
}
|
|
85
|
+
else if (error instanceof ValidationError) {
|
|
86
|
+
errorResponse = createErrorResponse(`Validation error: ${error.message}`);
|
|
87
|
+
}
|
|
88
|
+
else if (error instanceof ApiError) {
|
|
89
|
+
errorResponse = createErrorResponse(`API error: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
errorResponse = createErrorResponse(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
93
|
+
}
|
|
94
|
+
return formatMcpResponse(errorResponse);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=ui-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-diff.js","sourceRoot":"","sources":["../../src/tools/ui-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-to-artifact.d.ts","sourceRoot":"","sources":["../../src/tools/ui-to-artifact.ts"],"names":[],"mappings":"AAwDA;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAoG1D"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { FileNotFoundError, ApiError, ValidationError } from '../types/index.js';
|
|
3
|
+
import { CommonSchemas } from '../utils/validation.js';
|
|
4
|
+
import { formatMcpResponse, createSuccessResponse, createErrorResponse, withRetry } from '../core/api-common.js';
|
|
5
|
+
import { BaseImageAnalysisService } from '../core/base-image-service.js';
|
|
6
|
+
import { UI_TO_ARTIFACT_PROMPTS } from '../prompts/ui-to-artifact.js';
|
|
7
|
+
/**
|
|
8
|
+
* UI to Artifact service - Convert UI screenshots to various artifacts
|
|
9
|
+
*/
|
|
10
|
+
class UiToArtifactService extends BaseImageAnalysisService {
|
|
11
|
+
/**
|
|
12
|
+
* Convert UI screenshot to specified artifact type
|
|
13
|
+
*/
|
|
14
|
+
async convertUiToArtifact(imageSource, outputType, userPrompt) {
|
|
15
|
+
console.info('Starting UI to artifact conversion', {
|
|
16
|
+
imageSource,
|
|
17
|
+
outputType,
|
|
18
|
+
prompt: userPrompt
|
|
19
|
+
});
|
|
20
|
+
// Validate output type
|
|
21
|
+
const normalizedType = outputType.toLowerCase();
|
|
22
|
+
const systemPrompt = UI_TO_ARTIFACT_PROMPTS[normalizedType];
|
|
23
|
+
if (!systemPrompt) {
|
|
24
|
+
throw new ValidationError(`Invalid output_type '${outputType}'. Must be one of: code, prompt, spec, description`);
|
|
25
|
+
}
|
|
26
|
+
// Validate prompt
|
|
27
|
+
this.validatePrompt(userPrompt, 'ui-to-artifact');
|
|
28
|
+
// Process image
|
|
29
|
+
const imageContent = await this.processImageSource(imageSource);
|
|
30
|
+
// Execute analysis
|
|
31
|
+
return await this.executeVisionAnalysis(systemPrompt, userPrompt, [imageContent], 'ui-to-artifact');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Register UI to Artifact tool with MCP server
|
|
36
|
+
*/
|
|
37
|
+
export function registerUiToArtifactTool(server) {
|
|
38
|
+
const service = new UiToArtifactService();
|
|
39
|
+
const retryableConvert = withRetry(service.convertUiToArtifact.bind(service), 2, 1000);
|
|
40
|
+
server.tool('ui_to_artifact', `Convert UI screenshots into various artifacts: code, prompts, design specifications, or descriptions.
|
|
41
|
+
|
|
42
|
+
Use this tool ONLY when user wants to:
|
|
43
|
+
- Generate frontend code from UI design (output_type='code')
|
|
44
|
+
- Create AI prompts for UI generation (output_type='prompt')
|
|
45
|
+
- Extract design specifications (output_type='spec')
|
|
46
|
+
- Generate UI descriptions (output_type='description')
|
|
47
|
+
|
|
48
|
+
Supported output types:
|
|
49
|
+
- code: Production-ready HTML + CSS with semantic structure
|
|
50
|
+
- prompt: Detailed AI prompt for recreating the UI
|
|
51
|
+
- spec: Comprehensive design system documentation
|
|
52
|
+
- description: Natural language UI analysis`, {
|
|
53
|
+
image_source: z
|
|
54
|
+
.string()
|
|
55
|
+
.min(1, 'Image source cannot be empty')
|
|
56
|
+
.describe('Local file path or remote URL to the UI screenshot'),
|
|
57
|
+
output_type: z
|
|
58
|
+
.enum(['code', 'prompt', 'spec', 'description'], {
|
|
59
|
+
message: 'output_type must be one of: code, prompt, spec, description'
|
|
60
|
+
})
|
|
61
|
+
.describe('Type of artifact to generate from the UI'),
|
|
62
|
+
prompt: z
|
|
63
|
+
.string()
|
|
64
|
+
.min(1, 'Prompt cannot be empty')
|
|
65
|
+
.describe('Detailed instructions describing what to generate')
|
|
66
|
+
}, async (params) => {
|
|
67
|
+
try {
|
|
68
|
+
// Validate parameters
|
|
69
|
+
const validationSchema = CommonSchemas.filePath
|
|
70
|
+
? z.object({
|
|
71
|
+
image_source: CommonSchemas.filePath,
|
|
72
|
+
output_type: z.enum([
|
|
73
|
+
'code',
|
|
74
|
+
'prompt',
|
|
75
|
+
'spec',
|
|
76
|
+
'description'
|
|
77
|
+
]),
|
|
78
|
+
prompt: CommonSchemas.nonEmptyString
|
|
79
|
+
})
|
|
80
|
+
: z.object({
|
|
81
|
+
image_source: CommonSchemas.nonEmptyString,
|
|
82
|
+
output_type: z.enum([
|
|
83
|
+
'code',
|
|
84
|
+
'prompt',
|
|
85
|
+
'spec',
|
|
86
|
+
'description'
|
|
87
|
+
]),
|
|
88
|
+
prompt: CommonSchemas.nonEmptyString
|
|
89
|
+
});
|
|
90
|
+
const validated = validationSchema.safeParse(params);
|
|
91
|
+
if (!validated.success) {
|
|
92
|
+
const errorResponse = createErrorResponse(`Validation failed: ${validated.error.errors?.map(e => e.message).join(', ')}`);
|
|
93
|
+
return formatMcpResponse(errorResponse);
|
|
94
|
+
}
|
|
95
|
+
// Execute conversion
|
|
96
|
+
const result = await retryableConvert(validated.data.image_source, validated.data.output_type, validated.data.prompt);
|
|
97
|
+
return formatMcpResponse(createSuccessResponse(result));
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
let errorResponse;
|
|
101
|
+
if (error instanceof FileNotFoundError) {
|
|
102
|
+
errorResponse = createErrorResponse(`Image file not found: ${error.message}`);
|
|
103
|
+
}
|
|
104
|
+
else if (error instanceof ValidationError) {
|
|
105
|
+
errorResponse = createErrorResponse(`Validation error: ${error.message}`);
|
|
106
|
+
}
|
|
107
|
+
else if (error instanceof ApiError) {
|
|
108
|
+
errorResponse = createErrorResponse(`API error: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
errorResponse = createErrorResponse(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
112
|
+
}
|
|
113
|
+
return formatMcpResponse(errorResponse);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=ui-to-artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-to-artifact.js","sourceRoot":"","sources":["../../src/tools/ui-to-artifact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for API-related errors
|
|
3
|
+
*/
|
|
4
|
+
export declare class ApiError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Custom error class for file not found errors
|
|
9
|
+
*/
|
|
10
|
+
export declare class FileNotFoundError extends Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Custom error class for validation errors
|
|
15
|
+
*/
|
|
16
|
+
export declare class ValidationError extends Error {
|
|
17
|
+
details?: Record<string, unknown> | undefined;
|
|
18
|
+
constructor(message: string, details?: Record<string, unknown> | undefined);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Custom error class for tool execution errors
|
|
22
|
+
*/
|
|
23
|
+
export declare class ToolExecutionError extends Error {
|
|
24
|
+
constructor(message: string);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAAzD,OAAO,EAAE,MAAM,EAAS,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAKtE;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAK5B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for API-related errors
|
|
3
|
+
*/
|
|
4
|
+
export class ApiError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ApiError';
|
|
8
|
+
Object.setPrototypeOf(this, ApiError.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Custom error class for file not found errors
|
|
13
|
+
*/
|
|
14
|
+
export class FileNotFoundError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'FileNotFoundError';
|
|
18
|
+
Object.setPrototypeOf(this, FileNotFoundError.prototype);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Custom error class for validation errors
|
|
23
|
+
*/
|
|
24
|
+
export class ValidationError extends Error {
|
|
25
|
+
details;
|
|
26
|
+
constructor(message, details) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.details = details;
|
|
29
|
+
this.name = 'ValidationError';
|
|
30
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Custom error class for tool execution errors
|
|
35
|
+
*/
|
|
36
|
+
export class ToolExecutionError extends Error {
|
|
37
|
+
constructor(message) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = 'ToolExecutionError';
|
|
40
|
+
Object.setPrototypeOf(this, ToolExecutionError.prototype);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC3D,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACJ;IAApC,YAAY,OAAe,EAAS,OAAiC;QACnE,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,YAAO,GAAP,OAAO,CAA0B;QAEnE,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger utility that writes to stderr and a log file.
|
|
3
|
+
* Stderr keeps MCP JSON on stdout clean; file provides persistent logs.
|
|
4
|
+
*/
|
|
5
|
+
declare class Logger {
|
|
6
|
+
private logStream?;
|
|
7
|
+
constructor(logFilePath?: string);
|
|
8
|
+
setLogFile(logFilePath: string): void;
|
|
9
|
+
private safeStringify;
|
|
10
|
+
private write;
|
|
11
|
+
info(message: string, ...args: unknown[]): void;
|
|
12
|
+
error(message: string, ...args: unknown[]): void;
|
|
13
|
+
warn(message: string, ...args: unknown[]): void;
|
|
14
|
+
debug(message: string, ...args: unknown[]): void;
|
|
15
|
+
log(message: string, ...args: unknown[]): void;
|
|
16
|
+
}
|
|
17
|
+
export declare const logger: Logger;
|
|
18
|
+
/**
|
|
19
|
+
* Override global console to redirect to stderr
|
|
20
|
+
* This prevents console output from interfering with MCP JSON protocol
|
|
21
|
+
*/
|
|
22
|
+
export declare function setupConsoleRedirection(): typeof console;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,cAAM,MAAM;IACV,OAAO,CAAC,SAAS,CAAC,CAAiB;gBAEvB,WAAW,CAAC,EAAE,MAAM;IAMhC,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAerC,OAAO,CAAC,aAAa;IA+BrB,OAAO,CAAC,KAAK;IAeb,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAIhD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI/C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAIhD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;CAG/C;AAED,eAAO,MAAM,MAAM,QAAe,CAAC;AAEnC;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,OAAO,CA8BxD"}
|