mcp-image 0.1.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +163 -0
  3. package/dist/api/geminiClient.d.ts +55 -0
  4. package/dist/api/geminiClient.d.ts.map +1 -0
  5. package/dist/api/geminiClient.js +194 -0
  6. package/dist/api/geminiClient.js.map +1 -0
  7. package/dist/api/urlContextClient.d.ts +149 -0
  8. package/dist/api/urlContextClient.d.ts.map +1 -0
  9. package/dist/api/urlContextClient.js +320 -0
  10. package/dist/api/urlContextClient.js.map +1 -0
  11. package/dist/business/errorHandler.d.ts +97 -0
  12. package/dist/business/errorHandler.d.ts.map +1 -0
  13. package/dist/business/errorHandler.js +511 -0
  14. package/dist/business/errorHandler.js.map +1 -0
  15. package/dist/business/fileManager.d.ts +20 -0
  16. package/dist/business/fileManager.d.ts.map +1 -0
  17. package/dist/business/fileManager.js +112 -0
  18. package/dist/business/fileManager.js.map +1 -0
  19. package/dist/business/imageGenerator.d.ts +64 -0
  20. package/dist/business/imageGenerator.d.ts.map +1 -0
  21. package/dist/business/imageGenerator.js +147 -0
  22. package/dist/business/imageGenerator.js.map +1 -0
  23. package/dist/business/imageGeneratorRobust.d.ts +60 -0
  24. package/dist/business/imageGeneratorRobust.d.ts.map +1 -0
  25. package/dist/business/imageGeneratorRobust.js +242 -0
  26. package/dist/business/imageGeneratorRobust.js.map +1 -0
  27. package/dist/business/inputValidator.d.ts +29 -0
  28. package/dist/business/inputValidator.d.ts.map +1 -0
  29. package/dist/business/inputValidator.js +132 -0
  30. package/dist/business/inputValidator.js.map +1 -0
  31. package/dist/business/performanceManager.d.ts +88 -0
  32. package/dist/business/performanceManager.d.ts.map +1 -0
  33. package/dist/business/performanceManager.js +142 -0
  34. package/dist/business/performanceManager.js.map +1 -0
  35. package/dist/business/responseBuilder.d.ts +20 -0
  36. package/dist/business/responseBuilder.d.ts.map +1 -0
  37. package/dist/business/responseBuilder.js +162 -0
  38. package/dist/business/responseBuilder.js.map +1 -0
  39. package/dist/business/secureFileManager.d.ts +56 -0
  40. package/dist/business/secureFileManager.d.ts.map +1 -0
  41. package/dist/business/secureFileManager.js +185 -0
  42. package/dist/business/secureFileManager.js.map +1 -0
  43. package/dist/business/urlExtractor.d.ts +60 -0
  44. package/dist/business/urlExtractor.d.ts.map +1 -0
  45. package/dist/business/urlExtractor.js +144 -0
  46. package/dist/business/urlExtractor.js.map +1 -0
  47. package/dist/index.d.ts +5 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +45 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/server/concurrencyManager.d.ts +56 -0
  52. package/dist/server/concurrencyManager.d.ts.map +1 -0
  53. package/dist/server/concurrencyManager.js +133 -0
  54. package/dist/server/concurrencyManager.js.map +1 -0
  55. package/dist/server/errorHandler.d.ts +29 -0
  56. package/dist/server/errorHandler.d.ts.map +1 -0
  57. package/dist/server/errorHandler.js +93 -0
  58. package/dist/server/errorHandler.js.map +1 -0
  59. package/dist/server/mcpServer.d.ts +111 -0
  60. package/dist/server/mcpServer.d.ts.map +1 -0
  61. package/dist/server/mcpServer.js +353 -0
  62. package/dist/server/mcpServer.js.map +1 -0
  63. package/dist/types/mcp.d.ts +72 -0
  64. package/dist/types/mcp.d.ts.map +1 -0
  65. package/dist/types/mcp.js +7 -0
  66. package/dist/types/mcp.js.map +1 -0
  67. package/dist/types/result.d.ts +27 -0
  68. package/dist/types/result.d.ts.map +1 -0
  69. package/dist/types/result.js +31 -0
  70. package/dist/types/result.js.map +1 -0
  71. package/dist/utils/config.d.ts +26 -0
  72. package/dist/utils/config.d.ts.map +1 -0
  73. package/dist/utils/config.js +53 -0
  74. package/dist/utils/config.js.map +1 -0
  75. package/dist/utils/errors.d.ts +84 -0
  76. package/dist/utils/errors.d.ts.map +1 -0
  77. package/dist/utils/errors.js +218 -0
  78. package/dist/utils/errors.js.map +1 -0
  79. package/dist/utils/logger.d.ts +80 -0
  80. package/dist/utils/logger.d.ts.map +1 -0
  81. package/dist/utils/logger.js +223 -0
  82. package/dist/utils/logger.js.map +1 -0
  83. package/dist/utils/security.d.ts +50 -0
  84. package/dist/utils/security.d.ts.map +1 -0
  85. package/dist/utils/security.js +153 -0
  86. package/dist/utils/security.js.map +1 -0
  87. package/package.json +73 -0
  88. package/vitest.config.mjs +47 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Secure File Manager for handling image file operations with enhanced security
3
+ * Extends FileManager with security features, temporary file management, and cleanup
4
+ */
5
+ import { promises as fs } from 'node:fs';
6
+ import * as path from 'node:path';
7
+ import { Err, Ok } from '../types/result';
8
+ import { FileOperationError } from '../utils/errors';
9
+ import { Logger } from '../utils/logger';
10
+ import { SecurityManager } from '../utils/security';
11
+ import { FileManager } from './fileManager';
12
+ /**
13
+ * Secure file manager with enhanced security features and temporary file management
14
+ */
15
+ export class SecureFileManager extends FileManager {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.tempFiles = new Set();
19
+ this.securityManager = new SecurityManager();
20
+ this.logger = new Logger();
21
+ }
22
+ /**
23
+ * Securely save image data with comprehensive security checks
24
+ * @param imageData Buffer containing the image data
25
+ * @param outputPath Path where the image should be saved
26
+ * @param format Image format for validation (optional)
27
+ * @returns Result containing the saved file path or an error
28
+ */
29
+ async saveImageSecure(imageData, outputPath, format) {
30
+ try {
31
+ // Security validation
32
+ const sanitizedPath = this.securityManager.sanitizeFilePath(outputPath);
33
+ if (!sanitizedPath.success) {
34
+ return sanitizedPath;
35
+ }
36
+ const validationResult = this.securityManager.validateImageFile(sanitizedPath.data);
37
+ if (!validationResult.success) {
38
+ return validationResult;
39
+ }
40
+ // Ensure secure directory creation
41
+ const dirPath = path.dirname(sanitizedPath.data);
42
+ const dirResult = await this.ensureSecureDirectory(dirPath);
43
+ if (!dirResult.success) {
44
+ return dirResult;
45
+ }
46
+ // Atomic file operation using temporary file
47
+ const tempPath = `${sanitizedPath.data}.tmp`;
48
+ this.tempFiles.add(tempPath);
49
+ this.logger.debug('secure-file-manager', 'Starting atomic file save', {
50
+ outputPath: sanitizedPath.data,
51
+ tempPath,
52
+ fileSize: imageData.length,
53
+ format,
54
+ });
55
+ // Write to temporary file first
56
+ await fs.writeFile(tempPath, imageData);
57
+ // Atomic move to final destination
58
+ await fs.rename(tempPath, sanitizedPath.data);
59
+ this.tempFiles.delete(tempPath);
60
+ this.logger.info('secure-file-manager', 'Image saved successfully', {
61
+ outputPath: sanitizedPath.data,
62
+ fileSize: imageData.length,
63
+ format,
64
+ securityChecks: 'passed',
65
+ });
66
+ return Ok(sanitizedPath.data);
67
+ }
68
+ catch (error) {
69
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
70
+ this.logger.error('secure-file-manager', 'Failed to save image securely', error, {
71
+ outputPath,
72
+ format,
73
+ errorType: 'file-operation',
74
+ });
75
+ return Err(new FileOperationError(`Failed to save image: ${errorMessage}`));
76
+ }
77
+ }
78
+ /**
79
+ * Ensure secure directory creation with security validation
80
+ * @param dirPath Directory path to create
81
+ * @returns Result indicating success or failure
82
+ */
83
+ async ensureSecureDirectory(dirPath) {
84
+ try {
85
+ // Validate directory path security
86
+ const validationResult = this.securityManager.validateDirectoryPath(dirPath);
87
+ if (!validationResult.success) {
88
+ return validationResult;
89
+ }
90
+ // Use parent class method for actual directory creation
91
+ const createResult = this.ensureDirectoryExists(dirPath);
92
+ if (!createResult.success) {
93
+ return createResult;
94
+ }
95
+ this.logger.debug('secure-file-manager', 'Secure directory created', {
96
+ directoryPath: dirPath,
97
+ });
98
+ return Ok(undefined);
99
+ }
100
+ catch (error) {
101
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
102
+ this.logger.error('secure-file-manager', 'Failed to create secure directory', error, {
103
+ directoryPath: dirPath,
104
+ });
105
+ return Err(new FileOperationError(`Failed to create secure directory: ${errorMessage}`));
106
+ }
107
+ }
108
+ /**
109
+ * Cleanup all tracked temporary files
110
+ */
111
+ async cleanup() {
112
+ const cleanupPromises = Array.from(this.tempFiles).map(async (tempFile) => {
113
+ try {
114
+ await fs.unlink(tempFile);
115
+ this.tempFiles.delete(tempFile);
116
+ this.logger.debug('secure-file-manager', 'Temporary file cleaned up', {
117
+ file: tempFile,
118
+ });
119
+ }
120
+ catch (error) {
121
+ this.logger.warn('secure-file-manager', 'Failed to cleanup temporary file', {
122
+ file: tempFile,
123
+ error: error instanceof Error ? error.message : 'Unknown error',
124
+ });
125
+ }
126
+ });
127
+ await Promise.all(cleanupPromises);
128
+ if (this.tempFiles.size > 0) {
129
+ this.logger.warn('secure-file-manager', 'Some temporary files could not be cleaned', {
130
+ remainingCount: this.tempFiles.size,
131
+ });
132
+ }
133
+ }
134
+ /**
135
+ * Setup process cleanup handlers for graceful shutdown
136
+ */
137
+ setupProcessCleanup() {
138
+ const cleanup = () => {
139
+ this.logger.info('secure-file-manager', 'Process cleanup initiated');
140
+ this.cleanup().catch((error) => {
141
+ console.error('Failed to cleanup temporary files:', error);
142
+ });
143
+ };
144
+ // Setup cleanup on various process exit scenarios
145
+ process.on('exit', cleanup);
146
+ process.on('SIGINT', cleanup);
147
+ process.on('SIGTERM', cleanup);
148
+ process.on('uncaughtException', (error) => {
149
+ this.logger.error('secure-file-manager', 'Uncaught exception during cleanup', error);
150
+ cleanup();
151
+ });
152
+ this.logger.info('secure-file-manager', 'Process cleanup handlers registered');
153
+ }
154
+ /**
155
+ * Generate secure filename with validation
156
+ * @param baseName Base name for the file
157
+ * @param extension File extension (with dot)
158
+ * @returns Secure filename
159
+ */
160
+ generateSecureFileName(baseName, extension) {
161
+ const sanitizedBase = baseName
162
+ ? this.securityManager.sanitizeFilename(baseName)
163
+ : 'gemini-image';
164
+ const safeExtension = extension || '.png';
165
+ const timestamp = Date.now();
166
+ const random = Math.floor(Math.random() * 1000);
167
+ return `${sanitizedBase}-${timestamp}-${random}${safeExtension}`;
168
+ }
169
+ /**
170
+ * Get count of tracked temporary files
171
+ * @returns Number of temporary files being tracked
172
+ */
173
+ getTempFileCount() {
174
+ return this.tempFiles.size;
175
+ }
176
+ /**
177
+ * Check if a specific temporary file is being tracked
178
+ * @param filePath Path to check
179
+ * @returns True if file is being tracked as temporary
180
+ */
181
+ isTempFileTracked(filePath) {
182
+ return this.tempFiles.has(filePath);
183
+ }
184
+ }
185
+ //# sourceMappingURL=secureFileManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secureFileManager.js","sourceRoot":"","sources":["../../src/business/secureFileManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * URL extraction logic for processing URLs in prompts
3
+ * Provides functionality to extract, validate, and manipulate URLs in text
4
+ */
5
+ import { type Result } from '../types/result';
6
+ import { InvalidUrlError } from '../utils/errors';
7
+ /**
8
+ * Extract URLs from a given prompt text
9
+ * @param prompt The text to extract URLs from
10
+ * @returns Array of unique URLs found in the prompt (max 10)
11
+ */
12
+ export declare function extractUrls(prompt: string): string[];
13
+ /**
14
+ * Check if the prompt contains any URLs
15
+ * @param prompt The text to check for URLs
16
+ * @returns True if URLs are found, false otherwise
17
+ */
18
+ export declare function hasUrls(prompt: string): boolean;
19
+ /**
20
+ * Remove all URLs from the prompt text
21
+ * @param prompt The text to remove URLs from
22
+ * @returns The prompt with URLs removed and extra spaces trimmed
23
+ */
24
+ export declare function removeUrls(prompt: string): string;
25
+ /**
26
+ * Validate a single URL using built-in URL constructor
27
+ * @param url The URL string to validate
28
+ * @returns Result containing validation success or error
29
+ */
30
+ export declare function validateUrl(url: string): Result<string, InvalidUrlError>;
31
+ /**
32
+ * Extract and validate URLs from prompt with detailed error reporting
33
+ * @param prompt The text to extract URLs from
34
+ * @returns Result containing valid URLs or validation error
35
+ */
36
+ export declare function extractValidUrls(prompt: string): Result<string[], InvalidUrlError>;
37
+ /**
38
+ * Get URL statistics for analysis
39
+ * @param prompt The text to analyze
40
+ * @returns Statistics about URLs in the prompt
41
+ */
42
+ export declare function getUrlStats(prompt: string): {
43
+ totalFound: number;
44
+ validUrls: number;
45
+ httpUrls: number;
46
+ httpsUrls: number;
47
+ uniqueDomains: string[];
48
+ };
49
+ /**
50
+ * URL extractor utilities - backward compatibility object
51
+ */
52
+ export declare const URLExtractor: {
53
+ extractUrls: typeof extractUrls;
54
+ hasUrls: typeof hasUrls;
55
+ removeUrls: typeof removeUrls;
56
+ validateUrl: typeof validateUrl;
57
+ extractValidUrls: typeof extractValidUrls;
58
+ getUrlStats: typeof getUrlStats;
59
+ };
60
+ //# sourceMappingURL=urlExtractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urlExtractor.d.ts","sourceRoot":"","sources":["../../src/business/urlExtractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAcjD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CASpD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CA4BxE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAuBlF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB,CAwBA;AAED;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;CAOxB,CAAA"}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ /**
3
+ * URL extraction logic for processing URLs in prompts
4
+ * Provides functionality to extract, validate, and manipulate URLs in text
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.URLExtractor = void 0;
8
+ exports.extractUrls = extractUrls;
9
+ exports.hasUrls = hasUrls;
10
+ exports.removeUrls = removeUrls;
11
+ exports.validateUrl = validateUrl;
12
+ exports.extractValidUrls = extractValidUrls;
13
+ exports.getUrlStats = getUrlStats;
14
+ const result_1 = require("../types/result");
15
+ const errors_1 = require("../utils/errors");
16
+ /**
17
+ * Enhanced regular expression pattern for matching HTTP and HTTPS URLs
18
+ * Supports complex URLs with query parameters, fragments, and various domains
19
+ * More precise pattern to avoid false positives
20
+ */
21
+ const URL_PATTERN = /https?:\/\/(?:[-\w.])+(?:\.[a-zA-Z]{2,})+(?:\/[-\w._~:/?#[\]@!$&'()*+,;=]*)?/g;
22
+ /**
23
+ * Maximum number of URLs to extract (performance consideration)
24
+ */
25
+ const MAX_URLS = 10;
26
+ /**
27
+ * Extract URLs from a given prompt text
28
+ * @param prompt The text to extract URLs from
29
+ * @returns Array of unique URLs found in the prompt (max 10)
30
+ */
31
+ function extractUrls(prompt) {
32
+ const matches = prompt.match(URL_PATTERN);
33
+ if (!matches) {
34
+ return [];
35
+ }
36
+ // Remove duplicates using Set and limit to MAX_URLS
37
+ const uniqueUrls = [...new Set(matches)];
38
+ return uniqueUrls.slice(0, MAX_URLS);
39
+ }
40
+ /**
41
+ * Check if the prompt contains any URLs
42
+ * @param prompt The text to check for URLs
43
+ * @returns True if URLs are found, false otherwise
44
+ */
45
+ function hasUrls(prompt) {
46
+ return extractUrls(prompt).length > 0;
47
+ }
48
+ /**
49
+ * Remove all URLs from the prompt text
50
+ * @param prompt The text to remove URLs from
51
+ * @returns The prompt with URLs removed and extra spaces trimmed
52
+ */
53
+ function removeUrls(prompt) {
54
+ return prompt.replace(URL_PATTERN, '').replace(/\s+/g, ' ').trim();
55
+ }
56
+ /**
57
+ * Validate a single URL using built-in URL constructor
58
+ * @param url The URL string to validate
59
+ * @returns Result containing validation success or error
60
+ */
61
+ function validateUrl(url) {
62
+ try {
63
+ const urlObj = new URL(url);
64
+ // Only allow HTTP and HTTPS protocols
65
+ if (!['http:', 'https:'].includes(urlObj.protocol)) {
66
+ return (0, result_1.Err)(new errors_1.InvalidUrlError(`Invalid protocol: ${urlObj.protocol}`, 'Only HTTP and HTTPS URLs are supported', url));
67
+ }
68
+ // Basic hostname validation
69
+ if (!urlObj.hostname || urlObj.hostname.length === 0) {
70
+ return (0, result_1.Err)(new errors_1.InvalidUrlError('Invalid hostname in URL', 'URL must have a valid hostname', url));
71
+ }
72
+ return (0, result_1.Ok)(url);
73
+ }
74
+ catch (error) {
75
+ return (0, result_1.Err)(new errors_1.InvalidUrlError(`Malformed URL: ${url}`, 'Please check the URL format and try again', url));
76
+ }
77
+ }
78
+ /**
79
+ * Extract and validate URLs from prompt with detailed error reporting
80
+ * @param prompt The text to extract URLs from
81
+ * @returns Result containing valid URLs or validation error
82
+ */
83
+ function extractValidUrls(prompt) {
84
+ const extractedUrls = extractUrls(prompt);
85
+ const validUrls = [];
86
+ const errors = [];
87
+ for (const url of extractedUrls) {
88
+ const validation = validateUrl(url);
89
+ if (validation.success) {
90
+ validUrls.push(validation.data);
91
+ }
92
+ else {
93
+ errors.push(validation.error);
94
+ }
95
+ }
96
+ // If there are validation errors and no valid URLs, return first error
97
+ if (errors.length > 0 && validUrls.length === 0) {
98
+ const firstError = errors[0];
99
+ if (firstError) {
100
+ return (0, result_1.Err)(firstError);
101
+ }
102
+ }
103
+ return (0, result_1.Ok)(validUrls);
104
+ }
105
+ /**
106
+ * Get URL statistics for analysis
107
+ * @param prompt The text to analyze
108
+ * @returns Statistics about URLs in the prompt
109
+ */
110
+ function getUrlStats(prompt) {
111
+ const urls = extractUrls(prompt);
112
+ const httpUrls = urls.filter((url) => url.startsWith('http:')).length;
113
+ const httpsUrls = urls.filter((url) => url.startsWith('https:')).length;
114
+ const domains = urls
115
+ .map((url) => {
116
+ try {
117
+ return new URL(url).hostname;
118
+ }
119
+ catch {
120
+ return null;
121
+ }
122
+ })
123
+ .filter((domain) => domain !== null);
124
+ const uniqueDomains = [...new Set(domains)];
125
+ return {
126
+ totalFound: urls.length,
127
+ validUrls: domains.length,
128
+ httpUrls,
129
+ httpsUrls,
130
+ uniqueDomains,
131
+ };
132
+ }
133
+ /**
134
+ * URL extractor utilities - backward compatibility object
135
+ */
136
+ exports.URLExtractor = {
137
+ extractUrls,
138
+ hasUrls,
139
+ removeUrls,
140
+ validateUrl,
141
+ extractValidUrls,
142
+ getUrlStats,
143
+ };
144
+ //# sourceMappingURL=urlExtractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urlExtractor.js","sourceRoot":"","sources":["../../src/business/urlExtractor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAsBH,kCASC;AAOD,0BAEC;AAOD,gCAEC;AAOD,kCA4BC;AAOD,4CAuBC;AAOD,kCA8BC;AArJD,4CAAsD;AACtD,4CAAiD;AAEjD;;;;GAIG;AACH,MAAM,WAAW,GAAG,+EAA+E,CAAA;AAEnG;;GAEG;AACH,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB;;;;GAIG;AACH,SAAgB,WAAW,CAAC,MAAc;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IACzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,CAAA;IACX,CAAC;IAED,oDAAoD;IACpD,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;IACxC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;AACtC,CAAC;AAED;;;;GAIG;AACH,SAAgB,OAAO,CAAC,MAAc;IACpC,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;AACvC,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU,CAAC,MAAc;IACvC,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;AACpE,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QAE3B,sCAAsC;QACtC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnD,OAAO,IAAA,YAAG,EACR,IAAI,wBAAe,CACjB,qBAAqB,MAAM,CAAC,QAAQ,EAAE,EACtC,wCAAwC,EACxC,GAAG,CACJ,CACF,CAAA;QACH,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrD,OAAO,IAAA,YAAG,EACR,IAAI,wBAAe,CAAC,yBAAyB,EAAE,gCAAgC,EAAE,GAAG,CAAC,CACtF,CAAA;QACH,CAAC;QAED,OAAO,IAAA,WAAE,EAAC,GAAG,CAAC,CAAA;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,IAAA,YAAG,EACR,IAAI,wBAAe,CAAC,kBAAkB,GAAG,EAAE,EAAE,2CAA2C,EAAE,GAAG,CAAC,CAC/F,CAAA;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,MAAc;IAC7C,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IACzC,MAAM,SAAS,GAAa,EAAE,CAAA;IAC9B,MAAM,MAAM,GAAsB,EAAE,CAAA;IAEpC,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YACvB,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;QAC5B,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,IAAA,YAAG,EAAC,UAAU,CAAC,CAAA;QACxB,CAAC;IACH,CAAC;IAED,OAAO,IAAA,WAAE,EAAC,SAAS,CAAC,CAAA;AACtB,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAC,MAAc;IAOxC,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAA;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAA;IAEvE,MAAM,OAAO,GAAG,IAAI;SACjB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,MAAM,EAAoB,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,CAAA;IAExD,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;IAE3C,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,MAAM;QACvB,SAAS,EAAE,OAAO,CAAC,MAAM;QACzB,QAAQ;QACR,SAAS;QACT,aAAa;KACd,CAAA;AACH,CAAC;AAED;;GAEG;AACU,QAAA,YAAY,GAAG;IAC1B,WAAW;IACX,OAAO;IACP,UAAU;IACV,WAAW;IACX,gBAAgB;IAChB,WAAW;CACZ,CAAA"}
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ export { createMCPServer, MCPServerImpl } from './server/mcpServer';
3
+ export type { GenerateImageParams, MCPServerConfig } from './types/mcp';
4
+ export type { GeneratedImageResult } from './api/geminiClient';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA+CA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACnE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AACvE,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.MCPServerImpl = exports.createMCPServer = void 0;
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ /**
7
+ * MCP Image Generator entry point
8
+ * MCP server startup process
9
+ */
10
+ const mcpServer_1 = require("./server/mcpServer");
11
+ const logger_1 = require("./utils/logger");
12
+ const logger = new logger_1.Logger();
13
+ /**
14
+ * Application startup
15
+ */
16
+ async function main() {
17
+ try {
18
+ logger.info('mcp-startup', 'Starting MCP Image Generator initialization', {
19
+ nodeVersion: process.version,
20
+ platform: process.platform,
21
+ env: process.env['NODE_ENV'] || 'development',
22
+ });
23
+ const mcpServerImpl = new mcpServer_1.MCPServerImpl();
24
+ const server = mcpServerImpl.initialize();
25
+ const transport = new stdio_js_1.StdioServerTransport();
26
+ await server.connect(transport);
27
+ logger.info('mcp-startup', 'Image Generator MCP Server started successfully');
28
+ }
29
+ catch (error) {
30
+ logger.error('mcp-startup', 'Failed to start MCP server', error, {
31
+ errorType: error?.constructor?.name,
32
+ stack: error?.stack,
33
+ });
34
+ process.exit(1);
35
+ }
36
+ }
37
+ // Run main function
38
+ main().catch((error) => {
39
+ logger.error('mcp-startup', 'Fatal error during startup', error);
40
+ process.exit(1);
41
+ });
42
+ var mcpServer_2 = require("./server/mcpServer");
43
+ Object.defineProperty(exports, "createMCPServer", { enumerable: true, get: function () { return mcpServer_2.createMCPServer; } });
44
+ Object.defineProperty(exports, "MCPServerImpl", { enumerable: true, get: function () { return mcpServer_2.MCPServerImpl; } });
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAEA,wEAAgF;AAChF;;;GAGG;AACH,kDAAkD;AAClD,2CAAuC;AAEvC,MAAM,MAAM,GAAG,IAAI,eAAM,EAAE,CAAA;AAE3B;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,6CAA6C,EAAE;YACxE,WAAW,EAAE,OAAO,CAAC,OAAO;YAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa;SAC9C,CAAC,CAAA;QAEF,MAAM,aAAa,GAAG,IAAI,yBAAa,EAAE,CAAA;QAEzC,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,EAAE,CAAA;QAEzC,MAAM,SAAS,GAAG,IAAI,+BAAoB,EAAE,CAAA;QAE5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAE/B,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,iDAAiD,CAAC,CAAA;IAC/E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,4BAA4B,EAAE,KAAc,EAAE;YACxE,SAAS,EAAG,KAAe,EAAE,WAAW,EAAE,IAAI;YAC9C,KAAK,EAAG,KAAe,EAAE,KAAK;SAC/B,CAAC,CAAA;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,oBAAoB;AACpB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,4BAA4B,EAAE,KAAc,CAAC,CAAA;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA;AAEF,gDAAmE;AAA1D,4GAAA,eAAe,OAAA;AAAE,0GAAA,aAAa,OAAA"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Concurrency Manager - Controls concurrent request execution
3
+ * Implements singleton pattern with queue management
4
+ */
5
+ /**
6
+ * Concurrency manager for limiting concurrent requests
7
+ */
8
+ export declare class ConcurrencyManager {
9
+ private static instance;
10
+ private activeRequests;
11
+ private readonly maxConcurrent;
12
+ private requestQueue;
13
+ private readonly queueTimeout;
14
+ /**
15
+ * Get singleton instance of ConcurrencyManager
16
+ * @returns ConcurrencyManager instance
17
+ */
18
+ static getInstance(): ConcurrencyManager;
19
+ /**
20
+ * Acquire a concurrency lock
21
+ * @returns Promise that resolves when lock is acquired
22
+ */
23
+ acquireLock(): Promise<void>;
24
+ /**
25
+ * Release a concurrency lock
26
+ */
27
+ releaseLock(): void;
28
+ /**
29
+ * Process the next request in the queue
30
+ */
31
+ private processNextRequest;
32
+ /**
33
+ * Clean up expired requests from the queue
34
+ */
35
+ private cleanupExpiredRequests;
36
+ /**
37
+ * Check if concurrency limit is reached
38
+ * @returns True if at limit
39
+ */
40
+ isAtLimit(): boolean;
41
+ /**
42
+ * Get current queue length
43
+ * @returns Number of queued requests
44
+ */
45
+ getQueueLength(): number;
46
+ /**
47
+ * Get current active request count
48
+ * @returns Number of active requests
49
+ */
50
+ getActiveRequestCount(): number;
51
+ /**
52
+ * Reset the concurrency manager (for testing purposes)
53
+ */
54
+ reset(): void;
55
+ }
56
+ //# sourceMappingURL=concurrencyManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrencyManager.d.ts","sourceRoot":"","sources":["../../src/server/concurrencyManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAoB;IAC3C,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAI;IAClC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IAErC;;;OAGG;IACH,MAAM,CAAC,WAAW,IAAI,kBAAkB;IAOxC;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAuClC;;OAEG;IACH,WAAW,IAAI,IAAI;IAOnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAoB9B;;;OAGG;IACH,SAAS,IAAI,OAAO;IAIpB;;;OAGG;IACH,cAAc,IAAI,MAAM;IAIxB;;;OAGG;IACH,qBAAqB,IAAI,MAAM;IAI/B;;OAEG;IACH,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Concurrency Manager - Controls concurrent request execution
3
+ * Implements singleton pattern with queue management
4
+ */
5
+ /**
6
+ * Concurrency manager for limiting concurrent requests
7
+ */
8
+ export class ConcurrencyManager {
9
+ constructor() {
10
+ this.activeRequests = 0;
11
+ this.maxConcurrent = 1;
12
+ this.requestQueue = [];
13
+ this.queueTimeout = 30000; // 30 seconds
14
+ }
15
+ /**
16
+ * Get singleton instance of ConcurrencyManager
17
+ * @returns ConcurrencyManager instance
18
+ */
19
+ static getInstance() {
20
+ if (!ConcurrencyManager.instance) {
21
+ ConcurrencyManager.instance = new ConcurrencyManager();
22
+ }
23
+ return ConcurrencyManager.instance;
24
+ }
25
+ /**
26
+ * Acquire a concurrency lock
27
+ * @returns Promise that resolves when lock is acquired
28
+ */
29
+ async acquireLock() {
30
+ if (this.activeRequests < this.maxConcurrent) {
31
+ this.activeRequests++;
32
+ return Promise.resolve();
33
+ }
34
+ return new Promise((resolve, reject) => {
35
+ const request = {
36
+ resolve,
37
+ reject,
38
+ timestamp: Date.now(),
39
+ };
40
+ this.requestQueue.push(request);
41
+ // Set timeout for this request
42
+ const timeoutId = setTimeout(() => {
43
+ const index = this.requestQueue.findIndex((req) => req === request);
44
+ if (index >= 0) {
45
+ this.requestQueue.splice(index, 1);
46
+ reject(new Error('Concurrency limit timeout'));
47
+ }
48
+ }, this.queueTimeout);
49
+ // Clear timeout when request resolves
50
+ const originalResolve = request.resolve;
51
+ request.resolve = () => {
52
+ clearTimeout(timeoutId);
53
+ originalResolve(undefined);
54
+ };
55
+ const originalReject = request.reject;
56
+ request.reject = (error) => {
57
+ clearTimeout(timeoutId);
58
+ originalReject(error);
59
+ };
60
+ });
61
+ }
62
+ /**
63
+ * Release a concurrency lock
64
+ */
65
+ releaseLock() {
66
+ this.activeRequests = Math.max(0, this.activeRequests - 1);
67
+ // Process next request in queue
68
+ this.processNextRequest();
69
+ }
70
+ /**
71
+ * Process the next request in the queue
72
+ */
73
+ processNextRequest() {
74
+ // Clean up expired requests first
75
+ this.cleanupExpiredRequests();
76
+ if (this.requestQueue.length > 0 && this.activeRequests < this.maxConcurrent) {
77
+ const next = this.requestQueue.shift();
78
+ if (next) {
79
+ this.activeRequests++;
80
+ next.resolve(undefined);
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Clean up expired requests from the queue
86
+ */
87
+ cleanupExpiredRequests() {
88
+ const now = Date.now();
89
+ const initialLength = this.requestQueue.length;
90
+ this.requestQueue = this.requestQueue.filter((request) => {
91
+ const isExpired = now - request.timestamp > this.queueTimeout;
92
+ if (isExpired) {
93
+ request.reject(new Error('Request expired in queue'));
94
+ return false;
95
+ }
96
+ return true;
97
+ });
98
+ // Log cleanup if any requests were removed
99
+ const removedCount = initialLength - this.requestQueue.length;
100
+ if (removedCount > 0) {
101
+ console.warn(`[ConcurrencyManager] Cleaned up ${removedCount} expired requests from queue`);
102
+ }
103
+ }
104
+ /**
105
+ * Check if concurrency limit is reached
106
+ * @returns True if at limit
107
+ */
108
+ isAtLimit() {
109
+ return this.activeRequests >= this.maxConcurrent;
110
+ }
111
+ /**
112
+ * Get current queue length
113
+ * @returns Number of queued requests
114
+ */
115
+ getQueueLength() {
116
+ return this.requestQueue.length;
117
+ }
118
+ /**
119
+ * Get current active request count
120
+ * @returns Number of active requests
121
+ */
122
+ getActiveRequestCount() {
123
+ return this.activeRequests;
124
+ }
125
+ /**
126
+ * Reset the concurrency manager (for testing purposes)
127
+ */
128
+ reset() {
129
+ this.activeRequests = 0;
130
+ this.requestQueue = [];
131
+ }
132
+ }
133
+ //# sourceMappingURL=concurrencyManager.js.map