@aashari/boilerplate-mcp-server 1.5.9 → 1.6.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/CHANGELOG.md +14 -0
- package/dist/controllers/ipaddress.controller.js +2 -6
- package/dist/services/vendor.ip-api.com.service.js +16 -19
- package/dist/utils/constants.util.d.ts +1 -1
- package/dist/utils/constants.util.js +1 -1
- package/dist/utils/error-handler.util.d.ts +15 -1
- package/dist/utils/error-handler.util.js +80 -0
- package/dist/utils/error-handler.util.test.d.ts +1 -0
- package/dist/utils/error.util.d.ts +12 -1
- package/dist/utils/error.util.js +60 -1
- package/dist/utils/error.util.test.d.ts +1 -0
- package/package.json +1 -1
- package/package.json.bak +1 -1
- package/Dockerfile +0 -25
- package/smithery.yaml +0 -34
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.6.0](https://github.com/aashari/boilerplate-mcp-server/compare/v1.5.10...v1.6.0) (2025-05-15)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* enhanced error handling across the application ([75aa905](https://github.com/aashari/boilerplate-mcp-server/commit/75aa90528e615d1c1a9a411ddd1bf1931edfde61))
|
|
7
|
+
|
|
8
|
+
## [1.5.10](https://github.com/aashari/boilerplate-mcp-server/compare/v1.5.9...v1.5.10) (2025-05-14)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* remove Dockerfile and smithery.yaml ([582e9f9](https://github.com/aashari/boilerplate-mcp-server/commit/582e9f9e66087fd2211d6fcf1aaa79c9ee54a123))
|
|
14
|
+
|
|
1
15
|
## [1.5.9](https://github.com/aashari/boilerplate-mcp-server/compare/v1.5.8...v1.5.9) (2025-05-13)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -9,6 +9,7 @@ const ipaddress_formatter_js_1 = require("./ipaddress.formatter.js");
|
|
|
9
9
|
const error_handler_util_js_1 = require("../utils/error-handler.util.js");
|
|
10
10
|
const config_util_js_1 = require("../utils/config.util.js");
|
|
11
11
|
const error_util_js_1 = require("../utils/error.util.js");
|
|
12
|
+
const error_handler_util_js_2 = require("../utils/error-handler.util.js");
|
|
12
13
|
/**
|
|
13
14
|
* @namespace IpAddressController
|
|
14
15
|
* @description Controller responsible for handling IP address lookup logic.
|
|
@@ -97,12 +98,7 @@ async function get(ipAddress, options = {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
catch (error) {
|
|
100
|
-
throw (0, error_handler_util_js_1.handleControllerError)(error, {
|
|
101
|
-
entityType: 'IP Address',
|
|
102
|
-
operation: 'get',
|
|
103
|
-
source: 'controllers/ipaddress.controller.ts@get',
|
|
104
|
-
additionalInfo: { ipAddress, options },
|
|
105
|
-
});
|
|
101
|
+
throw (0, error_handler_util_js_1.handleControllerError)(error, (0, error_handler_util_js_2.buildErrorContext)('IP Address', 'get', 'controllers/ipaddress.controller.ts@get', ipAddress || 'current device', { options }));
|
|
106
102
|
}
|
|
107
103
|
}
|
|
108
104
|
/** Helper to define all fields for extended data */
|
|
@@ -47,26 +47,23 @@ async function get(ipAddress, options = {}) {
|
|
|
47
47
|
// First check API-level success/failure before Zod validation
|
|
48
48
|
// This avoids unnecessary validation errors for known API errors
|
|
49
49
|
if (rawData.status !== 'success') {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
catch (zodError) {
|
|
59
|
-
// Throw error on validation failure
|
|
60
|
-
methodLogger.error('Zod validation failed', zodError);
|
|
61
|
-
if (zodError instanceof zod_1.z.ZodError) {
|
|
62
|
-
throw (0, error_util_js_1.createApiError)(`API response validation failed: ${zodError.errors
|
|
63
|
-
.map((e) => `${e.path.join('.')}: ${e.message}`)
|
|
64
|
-
.join(', ')}`, undefined, // No specific HTTP status for validation errors
|
|
65
|
-
zodError);
|
|
50
|
+
// Handle specific ip-api.com error responses
|
|
51
|
+
if (rawData.message) {
|
|
52
|
+
if (rawData.message.includes('private range')) {
|
|
53
|
+
throw (0, error_util_js_1.createApiError)(`Private IP addresses are not supported: ${rawData.message}`, 400, rawData);
|
|
54
|
+
}
|
|
55
|
+
else if (rawData.message.includes('reserved range')) {
|
|
56
|
+
throw (0, error_util_js_1.createApiError)(`Reserved IP addresses are not supported: ${rawData.message}`, 400, rawData);
|
|
57
|
+
}
|
|
66
58
|
}
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
throw (0, error_util_js_1.createApiError)(`IP API error: ${rawData.message || 'Unknown error'}`, 400, // Use 400 for client errors from ip-api.com
|
|
60
|
+
rawData);
|
|
69
61
|
}
|
|
62
|
+
// Now parse with Zod for successful responses
|
|
63
|
+
// Validate with Zod schema and return
|
|
64
|
+
const validatedData = vendor_ip_api_com_types_js_1.IPDetailSchema.parse(rawData);
|
|
65
|
+
methodLogger.debug(`Received and validated successful data from IP API`);
|
|
66
|
+
return validatedData;
|
|
70
67
|
}
|
|
71
68
|
catch (error) {
|
|
72
69
|
methodLogger.error(`Service error fetching IP data`, error);
|
|
@@ -74,7 +71,7 @@ async function get(ipAddress, options = {}) {
|
|
|
74
71
|
if (error instanceof zod_1.z.ZodError) {
|
|
75
72
|
throw (0, error_util_js_1.createApiError)(`API response validation failed: ${error.errors
|
|
76
73
|
.map((e) => `${e.path.join('.')}: ${e.message}`)
|
|
77
|
-
.join(', ')}`,
|
|
74
|
+
.join(', ')}`, 500, // Use 500 for validation errors as it's a server-side issue
|
|
78
75
|
error);
|
|
79
76
|
}
|
|
80
77
|
// Rethrow other McpErrors
|
|
@@ -11,7 +11,7 @@ exports.CLI_NAME = exports.PACKAGE_NAME = exports.VERSION = void 0;
|
|
|
11
11
|
* Current application version
|
|
12
12
|
* This should match the version in package.json
|
|
13
13
|
*/
|
|
14
|
-
exports.VERSION = '1.
|
|
14
|
+
exports.VERSION = '1.6.0';
|
|
15
15
|
/**
|
|
16
16
|
* Package name with scope
|
|
17
17
|
* Used for initialization and identification
|
|
@@ -6,7 +6,11 @@ export declare enum ErrorCode {
|
|
|
6
6
|
INVALID_CURSOR = "INVALID_CURSOR",
|
|
7
7
|
ACCESS_DENIED = "ACCESS_DENIED",
|
|
8
8
|
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
9
|
-
UNEXPECTED_ERROR = "UNEXPECTED_ERROR"
|
|
9
|
+
UNEXPECTED_ERROR = "UNEXPECTED_ERROR",
|
|
10
|
+
NETWORK_ERROR = "NETWORK_ERROR",
|
|
11
|
+
RATE_LIMIT_ERROR = "RATE_LIMIT_ERROR",
|
|
12
|
+
PRIVATE_IP_ERROR = "PRIVATE_IP_ERROR",
|
|
13
|
+
RESERVED_RANGE_ERROR = "RESERVED_RANGE_ERROR"
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
16
|
* Context information for error handling
|
|
@@ -33,6 +37,16 @@ export interface ErrorContext {
|
|
|
33
37
|
*/
|
|
34
38
|
additionalInfo?: Record<string, unknown>;
|
|
35
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Helper function to create a consistent error context object
|
|
42
|
+
* @param entityType Type of entity being processed
|
|
43
|
+
* @param operation Operation being performed
|
|
44
|
+
* @param source Source of the error (typically file path and function)
|
|
45
|
+
* @param entityId Optional identifier of the entity
|
|
46
|
+
* @param additionalInfo Optional additional information for debugging
|
|
47
|
+
* @returns A formatted ErrorContext object
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildErrorContext(entityType: string, operation: string, source: string, entityId?: string | Record<string, string>, additionalInfo?: Record<string, unknown>): ErrorContext;
|
|
36
50
|
/**
|
|
37
51
|
* Detect specific error types from raw errors
|
|
38
52
|
* @param error The error to analyze
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ErrorCode = void 0;
|
|
4
|
+
exports.buildErrorContext = buildErrorContext;
|
|
4
5
|
exports.detectErrorType = detectErrorType;
|
|
5
6
|
exports.createUserFriendlyErrorMessage = createUserFriendlyErrorMessage;
|
|
6
7
|
exports.handleControllerError = handleControllerError;
|
|
@@ -16,7 +17,29 @@ var ErrorCode;
|
|
|
16
17
|
ErrorCode["ACCESS_DENIED"] = "ACCESS_DENIED";
|
|
17
18
|
ErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
18
19
|
ErrorCode["UNEXPECTED_ERROR"] = "UNEXPECTED_ERROR";
|
|
20
|
+
ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
21
|
+
ErrorCode["RATE_LIMIT_ERROR"] = "RATE_LIMIT_ERROR";
|
|
22
|
+
ErrorCode["PRIVATE_IP_ERROR"] = "PRIVATE_IP_ERROR";
|
|
23
|
+
ErrorCode["RESERVED_RANGE_ERROR"] = "RESERVED_RANGE_ERROR";
|
|
19
24
|
})(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
|
|
25
|
+
/**
|
|
26
|
+
* Helper function to create a consistent error context object
|
|
27
|
+
* @param entityType Type of entity being processed
|
|
28
|
+
* @param operation Operation being performed
|
|
29
|
+
* @param source Source of the error (typically file path and function)
|
|
30
|
+
* @param entityId Optional identifier of the entity
|
|
31
|
+
* @param additionalInfo Optional additional information for debugging
|
|
32
|
+
* @returns A formatted ErrorContext object
|
|
33
|
+
*/
|
|
34
|
+
function buildErrorContext(entityType, operation, source, entityId, additionalInfo) {
|
|
35
|
+
return {
|
|
36
|
+
entityType,
|
|
37
|
+
operation,
|
|
38
|
+
source,
|
|
39
|
+
...(entityId && { entityId }),
|
|
40
|
+
...(additionalInfo && { additionalInfo }),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
20
43
|
/**
|
|
21
44
|
* Detect specific error types from raw errors
|
|
22
45
|
* @param error The error to analyze
|
|
@@ -30,6 +53,51 @@ function detectErrorType(error, context = {}) {
|
|
|
30
53
|
const statusCode = error instanceof Error && 'statusCode' in error
|
|
31
54
|
? error.statusCode
|
|
32
55
|
: undefined;
|
|
56
|
+
// Network error detection
|
|
57
|
+
if (errorMessage.includes('network error') ||
|
|
58
|
+
errorMessage.includes('fetch failed') ||
|
|
59
|
+
errorMessage.includes('ECONNREFUSED') ||
|
|
60
|
+
errorMessage.includes('ENOTFOUND') ||
|
|
61
|
+
errorMessage.includes('Failed to fetch') ||
|
|
62
|
+
errorMessage.includes('Network request failed')) {
|
|
63
|
+
return { code: ErrorCode.NETWORK_ERROR, statusCode: 500 };
|
|
64
|
+
}
|
|
65
|
+
// Rate limiting detection
|
|
66
|
+
if (errorMessage.includes('rate limit') ||
|
|
67
|
+
errorMessage.includes('too many requests') ||
|
|
68
|
+
statusCode === 429) {
|
|
69
|
+
return { code: ErrorCode.RATE_LIMIT_ERROR, statusCode: 429 };
|
|
70
|
+
}
|
|
71
|
+
// ip-api.com specific error detection
|
|
72
|
+
if (errorMessage.includes('private range') ||
|
|
73
|
+
errorMessage.includes('private IP')) {
|
|
74
|
+
return { code: ErrorCode.PRIVATE_IP_ERROR, statusCode: 400 };
|
|
75
|
+
}
|
|
76
|
+
if (errorMessage.includes('reserved range')) {
|
|
77
|
+
return { code: ErrorCode.RESERVED_RANGE_ERROR, statusCode: 400 };
|
|
78
|
+
}
|
|
79
|
+
// Check for ip-api.com status="fail" in originalError
|
|
80
|
+
if (error instanceof Error &&
|
|
81
|
+
'originalError' in error &&
|
|
82
|
+
error.originalError &&
|
|
83
|
+
typeof error.originalError === 'object') {
|
|
84
|
+
const originalError = error.originalError;
|
|
85
|
+
if (originalError.status === 'fail') {
|
|
86
|
+
const apiMessage = originalError.message
|
|
87
|
+
? String(originalError.message)
|
|
88
|
+
: '';
|
|
89
|
+
if (apiMessage.includes('private')) {
|
|
90
|
+
return { code: ErrorCode.PRIVATE_IP_ERROR, statusCode: 400 };
|
|
91
|
+
}
|
|
92
|
+
if (apiMessage.includes('reserved')) {
|
|
93
|
+
return {
|
|
94
|
+
code: ErrorCode.RESERVED_RANGE_ERROR,
|
|
95
|
+
statusCode: 400,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return { code: ErrorCode.VALIDATION_ERROR, statusCode: 400 };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
33
101
|
// Not Found detection
|
|
34
102
|
if (errorMessage.includes('not found') ||
|
|
35
103
|
errorMessage.includes('does not exist') ||
|
|
@@ -110,6 +178,18 @@ function createUserFriendlyErrorMessage(code, context = {}, originalMessage) {
|
|
|
110
178
|
originalMessage ||
|
|
111
179
|
`Invalid data provided for ${operation || 'operation'} ${entity.toLowerCase()}.`;
|
|
112
180
|
break;
|
|
181
|
+
case ErrorCode.NETWORK_ERROR:
|
|
182
|
+
message = `Network error while ${operation || 'connecting to'} the service. Please check your internet connection and try again.`;
|
|
183
|
+
break;
|
|
184
|
+
case ErrorCode.RATE_LIMIT_ERROR:
|
|
185
|
+
message = `Rate limit exceeded. Please wait a moment and try again, or reduce the frequency of requests.`;
|
|
186
|
+
break;
|
|
187
|
+
case ErrorCode.PRIVATE_IP_ERROR:
|
|
188
|
+
message = `Private IP addresses are not supported. Please provide a public IP address.`;
|
|
189
|
+
break;
|
|
190
|
+
case ErrorCode.RESERVED_RANGE_ERROR:
|
|
191
|
+
message = `Reserved range IP addresses are not supported. Please provide a public IP address.`;
|
|
192
|
+
break;
|
|
113
193
|
default:
|
|
114
194
|
message = `An unexpected error occurred while ${operation || 'processing'} ${entity.toLowerCase()}.`;
|
|
115
195
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -36,6 +36,12 @@ export declare function createUnexpectedError(message?: string, originalError?:
|
|
|
36
36
|
* Ensure an error is an McpError
|
|
37
37
|
*/
|
|
38
38
|
export declare function ensureMcpError(error: unknown): McpError;
|
|
39
|
+
/**
|
|
40
|
+
* Get the deepest original error from an error chain
|
|
41
|
+
* @param error The error to extract the original cause from
|
|
42
|
+
* @returns The deepest original error or the error itself
|
|
43
|
+
*/
|
|
44
|
+
export declare function getDeepOriginalError(error: unknown): unknown;
|
|
39
45
|
/**
|
|
40
46
|
* Format error for MCP tool response
|
|
41
47
|
*/
|
|
@@ -44,6 +50,11 @@ export declare function formatErrorForMcpTool(error: unknown): {
|
|
|
44
50
|
type: 'text';
|
|
45
51
|
text: string;
|
|
46
52
|
}>;
|
|
53
|
+
metadata?: {
|
|
54
|
+
errorType: ErrorType;
|
|
55
|
+
statusCode?: number;
|
|
56
|
+
errorDetails?: unknown;
|
|
57
|
+
};
|
|
47
58
|
};
|
|
48
59
|
/**
|
|
49
60
|
* Format error for MCP resource response
|
|
@@ -57,6 +68,6 @@ export declare function formatErrorForMcpResource(error: unknown, uri: string):
|
|
|
57
68
|
}>;
|
|
58
69
|
};
|
|
59
70
|
/**
|
|
60
|
-
* Handle error in CLI context
|
|
71
|
+
* Handle error in CLI context with improved user feedback
|
|
61
72
|
*/
|
|
62
73
|
export declare function handleCliError(error: unknown): never;
|
package/dist/utils/error.util.js
CHANGED
|
@@ -6,6 +6,7 @@ exports.createAuthInvalidError = createAuthInvalidError;
|
|
|
6
6
|
exports.createApiError = createApiError;
|
|
7
7
|
exports.createUnexpectedError = createUnexpectedError;
|
|
8
8
|
exports.ensureMcpError = ensureMcpError;
|
|
9
|
+
exports.getDeepOriginalError = getDeepOriginalError;
|
|
9
10
|
exports.formatErrorForMcpTool = formatErrorForMcpTool;
|
|
10
11
|
exports.formatErrorForMcpResource = formatErrorForMcpResource;
|
|
11
12
|
exports.handleCliError = handleCliError;
|
|
@@ -69,6 +70,27 @@ function ensureMcpError(error) {
|
|
|
69
70
|
}
|
|
70
71
|
return createUnexpectedError(String(error));
|
|
71
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the deepest original error from an error chain
|
|
75
|
+
* @param error The error to extract the original cause from
|
|
76
|
+
* @returns The deepest original error or the error itself
|
|
77
|
+
*/
|
|
78
|
+
function getDeepOriginalError(error) {
|
|
79
|
+
if (!error) {
|
|
80
|
+
return error;
|
|
81
|
+
}
|
|
82
|
+
let current = error;
|
|
83
|
+
let depth = 0;
|
|
84
|
+
const maxDepth = 10; // Prevent infinite recursion
|
|
85
|
+
while (depth < maxDepth &&
|
|
86
|
+
current instanceof Error &&
|
|
87
|
+
'originalError' in current &&
|
|
88
|
+
current.originalError) {
|
|
89
|
+
current = current.originalError;
|
|
90
|
+
depth++;
|
|
91
|
+
}
|
|
92
|
+
return current;
|
|
93
|
+
}
|
|
72
94
|
/**
|
|
73
95
|
* Format error for MCP tool response
|
|
74
96
|
*/
|
|
@@ -76,6 +98,12 @@ function formatErrorForMcpTool(error) {
|
|
|
76
98
|
const methodLogger = logger_util_js_1.Logger.forContext('utils/error.util.ts', 'formatErrorForMcpTool');
|
|
77
99
|
const mcpError = ensureMcpError(error);
|
|
78
100
|
methodLogger.error(`${mcpError.type} error`, mcpError);
|
|
101
|
+
// Get the deep original error for additional context
|
|
102
|
+
const originalError = getDeepOriginalError(mcpError.originalError);
|
|
103
|
+
// Safely extract details from the original error
|
|
104
|
+
const errorDetails = originalError instanceof Error
|
|
105
|
+
? { message: originalError.message }
|
|
106
|
+
: originalError;
|
|
79
107
|
return {
|
|
80
108
|
content: [
|
|
81
109
|
{
|
|
@@ -83,6 +111,11 @@ function formatErrorForMcpTool(error) {
|
|
|
83
111
|
text: `Error: ${mcpError.message}`,
|
|
84
112
|
},
|
|
85
113
|
],
|
|
114
|
+
metadata: {
|
|
115
|
+
errorType: mcpError.type,
|
|
116
|
+
statusCode: mcpError.statusCode,
|
|
117
|
+
errorDetails,
|
|
118
|
+
},
|
|
86
119
|
};
|
|
87
120
|
}
|
|
88
121
|
/**
|
|
@@ -104,12 +137,38 @@ function formatErrorForMcpResource(error, uri) {
|
|
|
104
137
|
};
|
|
105
138
|
}
|
|
106
139
|
/**
|
|
107
|
-
* Handle error in CLI context
|
|
140
|
+
* Handle error in CLI context with improved user feedback
|
|
108
141
|
*/
|
|
109
142
|
function handleCliError(error) {
|
|
110
143
|
const methodLogger = logger_util_js_1.Logger.forContext('utils/error.util.ts', 'handleCliError');
|
|
111
144
|
const mcpError = ensureMcpError(error);
|
|
112
145
|
methodLogger.error(`${mcpError.type} error`, mcpError);
|
|
146
|
+
// Get the deep original error for more context
|
|
147
|
+
const originalError = getDeepOriginalError(mcpError.originalError);
|
|
148
|
+
// Print the error message
|
|
113
149
|
console.error(`Error: ${mcpError.message}`);
|
|
150
|
+
// Provide helpful context based on error type
|
|
151
|
+
if (mcpError.type === ErrorType.AUTH_MISSING) {
|
|
152
|
+
console.error('\nTip: Make sure to set up your API token in the configuration file or environment variables.');
|
|
153
|
+
}
|
|
154
|
+
else if (mcpError.type === ErrorType.AUTH_INVALID) {
|
|
155
|
+
console.error('\nTip: Check that your API token is correct and has not expired.');
|
|
156
|
+
}
|
|
157
|
+
else if (mcpError.type === ErrorType.API_ERROR) {
|
|
158
|
+
if (mcpError.statusCode === 429) {
|
|
159
|
+
console.error('\nTip: You may have exceeded your API rate limits. Try again later or upgrade your API plan.');
|
|
160
|
+
}
|
|
161
|
+
// Add ip-api.com specific context if available
|
|
162
|
+
if (originalError && typeof originalError === 'object') {
|
|
163
|
+
const origErr = originalError;
|
|
164
|
+
if (origErr.status === 'fail' && origErr.message) {
|
|
165
|
+
console.error(`\nAPI returned failure: ${String(origErr.message)}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Display DEBUG tip
|
|
170
|
+
if (process.env.DEBUG !== 'mcp:*') {
|
|
171
|
+
console.error('\nFor more detailed error information, run with DEBUG=mcp:* environment variable.');
|
|
172
|
+
}
|
|
114
173
|
process.exit(1);
|
|
115
174
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aashari/boilerplate-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "TypeScript Model Context Protocol (MCP) server boilerplate providing IP lookup tools/resources. Includes CLI support and extensible structure for connecting AI systems (LLMs) to external data sources like ip-api.com. Ideal template for creating new MCP integrations via Node.js.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/package.json.bak
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aashari/boilerplate-mcp-server",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.10",
|
|
4
4
|
"description": "TypeScript Model Context Protocol (MCP) server boilerplate providing IP lookup tools/resources. Includes CLI support and extensible structure for connecting AI systems (LLMs) to external data sources like ip-api.com. Ideal template for creating new MCP integrations via Node.js.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/Dockerfile
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
|
|
2
|
-
FROM node:lts-alpine
|
|
3
|
-
|
|
4
|
-
# Create app directory
|
|
5
|
-
WORKDIR /usr/src/app
|
|
6
|
-
|
|
7
|
-
# Copy package files
|
|
8
|
-
COPY package*.json ./
|
|
9
|
-
|
|
10
|
-
# Install dependencies without running prepare scripts
|
|
11
|
-
RUN npm install --ignore-scripts
|
|
12
|
-
|
|
13
|
-
# Copy source code
|
|
14
|
-
COPY . .
|
|
15
|
-
|
|
16
|
-
# Build the TypeScript code
|
|
17
|
-
RUN npm run build
|
|
18
|
-
|
|
19
|
-
# Ensure the entrypoint is executable (already set in prepare, but reensure here)
|
|
20
|
-
RUN chmod +x dist/index.js
|
|
21
|
-
|
|
22
|
-
EXPOSE 3000
|
|
23
|
-
|
|
24
|
-
# Start the MCP server
|
|
25
|
-
CMD [ "npm", "start" ]
|
package/smithery.yaml
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
|
|
2
|
-
|
|
3
|
-
startCommand:
|
|
4
|
-
type: stdio
|
|
5
|
-
configSchema:
|
|
6
|
-
# JSON Schema defining the configuration options for the MCP.
|
|
7
|
-
type: object
|
|
8
|
-
required: []
|
|
9
|
-
properties:
|
|
10
|
-
debug:
|
|
11
|
-
type: boolean
|
|
12
|
-
default: false
|
|
13
|
-
description: Enable debug logging
|
|
14
|
-
ipapiApiToken:
|
|
15
|
-
type: string
|
|
16
|
-
default: ""
|
|
17
|
-
description: API token for the IP API service
|
|
18
|
-
commandFunction:
|
|
19
|
-
# A JS function that produces the CLI command based on the given config to start the MCP on stdio.
|
|
20
|
-
|-
|
|
21
|
-
(config) => {
|
|
22
|
-
// Setup environment variables based on provided config
|
|
23
|
-
const env = Object.assign({}, process.env);
|
|
24
|
-
if (config.debug) {
|
|
25
|
-
env.DEBUG = 'true';
|
|
26
|
-
}
|
|
27
|
-
if (config.ipapiApiToken) {
|
|
28
|
-
env.IPAPI_API_TOKEN = config.ipapiApiToken;
|
|
29
|
-
}
|
|
30
|
-
return { command: 'node', args: ['dist/index.js'], env };
|
|
31
|
-
}
|
|
32
|
-
exampleConfig:
|
|
33
|
-
debug: true
|
|
34
|
-
ipapiApiToken: YOUR_API_TOKEN
|