latitude-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/.releaserc.json +34 -0
- package/README.md +687 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +43 -0
- package/dist/cli/latitude.cli.d.ts +10 -0
- package/dist/cli/latitude.cli.js +286 -0
- package/dist/controllers/latitude.controller.d.ts +115 -0
- package/dist/controllers/latitude.controller.js +287 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +166 -0
- package/dist/resources/latitude.resource.d.ts +12 -0
- package/dist/resources/latitude.resource.js +145 -0
- package/dist/services/vendor.latitude.service.d.ts +49 -0
- package/dist/services/vendor.latitude.service.js +294 -0
- package/dist/tools/latitude.tool.d.ts +6 -0
- package/dist/tools/latitude.tool.js +517 -0
- package/dist/types/common.types.d.ts +20 -0
- package/dist/types/common.types.js +7 -0
- package/dist/types/latitude.types.d.ts +487 -0
- package/dist/types/latitude.types.js +311 -0
- package/dist/utils/cli.test.util.d.ts +34 -0
- package/dist/utils/cli.test.util.js +143 -0
- package/dist/utils/config.util.d.ts +43 -0
- package/dist/utils/config.util.js +145 -0
- package/dist/utils/config.util.test.d.ts +1 -0
- package/dist/utils/constants.util.d.ts +26 -0
- package/dist/utils/constants.util.js +29 -0
- package/dist/utils/error-handler.util.d.ts +54 -0
- package/dist/utils/error-handler.util.js +202 -0
- package/dist/utils/error-handler.util.test.d.ts +1 -0
- package/dist/utils/error.util.d.ts +73 -0
- package/dist/utils/error.util.js +174 -0
- package/dist/utils/error.util.test.d.ts +1 -0
- package/dist/utils/formatter.util.d.ts +36 -0
- package/dist/utils/formatter.util.js +116 -0
- package/dist/utils/jest.setup.d.ts +5 -0
- package/dist/utils/jest.setup.js +36 -0
- package/dist/utils/jq.util.d.ts +34 -0
- package/dist/utils/jq.util.js +87 -0
- package/dist/utils/logger.util.d.ts +78 -0
- package/dist/utils/logger.util.js +344 -0
- package/dist/utils/toon.util.d.ts +15 -0
- package/dist/utils/toon.util.js +65 -0
- package/dist/utils/transport.util.d.ts +49 -0
- package/dist/utils/transport.util.js +162 -0
- package/eslint.config.mjs +46 -0
- package/openapi.json +12592 -0
- package/package.json +118 -0
- package/scripts/ensure-executable.js +38 -0
- package/scripts/package.json +3 -0
- package/scripts/update-version.js +204 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application constants
|
|
3
|
+
*
|
|
4
|
+
* This file contains constants used throughout the application.
|
|
5
|
+
* Centralizing these values makes them easier to maintain and update.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Current application version
|
|
9
|
+
* This should match the version in package.json
|
|
10
|
+
*/
|
|
11
|
+
export declare const VERSION = "1.0.0";
|
|
12
|
+
/**
|
|
13
|
+
* Package name with scope
|
|
14
|
+
* Used for initialization and identification
|
|
15
|
+
*/
|
|
16
|
+
export declare const PACKAGE_NAME = "@anthropic/latitude-mcp-server";
|
|
17
|
+
/**
|
|
18
|
+
* CLI command name
|
|
19
|
+
* Used for binary name and CLI help text
|
|
20
|
+
*/
|
|
21
|
+
export declare const CLI_NAME = "latitude-mcp";
|
|
22
|
+
/**
|
|
23
|
+
* Latitude API configuration
|
|
24
|
+
*/
|
|
25
|
+
export declare const LATITUDE_BASE_URL = "https://gateway.latitude.so";
|
|
26
|
+
export declare const LATITUDE_API_VERSION = "v3";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Application constants
|
|
4
|
+
*
|
|
5
|
+
* This file contains constants used throughout the application.
|
|
6
|
+
* Centralizing these values makes them easier to maintain and update.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.LATITUDE_API_VERSION = exports.LATITUDE_BASE_URL = exports.CLI_NAME = exports.PACKAGE_NAME = exports.VERSION = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* Current application version
|
|
12
|
+
* This should match the version in package.json
|
|
13
|
+
*/
|
|
14
|
+
exports.VERSION = '1.0.0';
|
|
15
|
+
/**
|
|
16
|
+
* Package name with scope
|
|
17
|
+
* Used for initialization and identification
|
|
18
|
+
*/
|
|
19
|
+
exports.PACKAGE_NAME = '@anthropic/latitude-mcp-server';
|
|
20
|
+
/**
|
|
21
|
+
* CLI command name
|
|
22
|
+
* Used for binary name and CLI help text
|
|
23
|
+
*/
|
|
24
|
+
exports.CLI_NAME = 'latitude-mcp';
|
|
25
|
+
/**
|
|
26
|
+
* Latitude API configuration
|
|
27
|
+
*/
|
|
28
|
+
exports.LATITUDE_BASE_URL = 'https://gateway.latitude.so';
|
|
29
|
+
exports.LATITUDE_API_VERSION = 'v3';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard error codes for consistent handling
|
|
3
|
+
*/
|
|
4
|
+
export declare enum ErrorCode {
|
|
5
|
+
NOT_FOUND = "NOT_FOUND",
|
|
6
|
+
INVALID_CURSOR = "INVALID_CURSOR",
|
|
7
|
+
ACCESS_DENIED = "ACCESS_DENIED",
|
|
8
|
+
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
9
|
+
UNEXPECTED_ERROR = "UNEXPECTED_ERROR",
|
|
10
|
+
NETWORK_ERROR = "NETWORK_ERROR",
|
|
11
|
+
RATE_LIMIT_ERROR = "RATE_LIMIT_ERROR"
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Context information for error handling
|
|
15
|
+
*/
|
|
16
|
+
export interface ErrorContext {
|
|
17
|
+
/**
|
|
18
|
+
* Source of the error (e.g., file path and function)
|
|
19
|
+
*/
|
|
20
|
+
source?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Type of entity being processed (e.g., 'IP Address', 'User')
|
|
23
|
+
*/
|
|
24
|
+
entityType?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Identifier of the entity being processed
|
|
27
|
+
*/
|
|
28
|
+
entityId?: string | Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Operation being performed (e.g., 'retrieving', 'searching')
|
|
31
|
+
*/
|
|
32
|
+
operation?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Additional information for debugging
|
|
35
|
+
*/
|
|
36
|
+
additionalInfo?: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Helper function to create a consistent error context object
|
|
40
|
+
* @param entityType Type of entity being processed
|
|
41
|
+
* @param operation Operation being performed
|
|
42
|
+
* @param source Source of the error (typically file path and function)
|
|
43
|
+
* @param entityId Optional identifier of the entity
|
|
44
|
+
* @param additionalInfo Optional additional information for debugging
|
|
45
|
+
* @returns A formatted ErrorContext object
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildErrorContext(entityType: string, operation: string, source: string, entityId?: string | Record<string, string>, additionalInfo?: Record<string, unknown>): ErrorContext;
|
|
48
|
+
/**
|
|
49
|
+
* Handle controller errors consistently
|
|
50
|
+
* @param error The error to handle
|
|
51
|
+
* @param context Context information for better error messages
|
|
52
|
+
* @returns Never returns, always throws an error
|
|
53
|
+
*/
|
|
54
|
+
export declare function handleControllerError(error: unknown, context?: ErrorContext): never;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorCode = void 0;
|
|
4
|
+
exports.buildErrorContext = buildErrorContext;
|
|
5
|
+
exports.handleControllerError = handleControllerError;
|
|
6
|
+
const error_util_js_1 = require("./error.util.js");
|
|
7
|
+
const logger_util_js_1 = require("./logger.util.js");
|
|
8
|
+
/**
|
|
9
|
+
* Standard error codes for consistent handling
|
|
10
|
+
*/
|
|
11
|
+
var ErrorCode;
|
|
12
|
+
(function (ErrorCode) {
|
|
13
|
+
ErrorCode["NOT_FOUND"] = "NOT_FOUND";
|
|
14
|
+
ErrorCode["INVALID_CURSOR"] = "INVALID_CURSOR";
|
|
15
|
+
ErrorCode["ACCESS_DENIED"] = "ACCESS_DENIED";
|
|
16
|
+
ErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
17
|
+
ErrorCode["UNEXPECTED_ERROR"] = "UNEXPECTED_ERROR";
|
|
18
|
+
ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
19
|
+
ErrorCode["RATE_LIMIT_ERROR"] = "RATE_LIMIT_ERROR";
|
|
20
|
+
})(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
|
|
21
|
+
/**
|
|
22
|
+
* Helper function to create a consistent error context object
|
|
23
|
+
* @param entityType Type of entity being processed
|
|
24
|
+
* @param operation Operation being performed
|
|
25
|
+
* @param source Source of the error (typically file path and function)
|
|
26
|
+
* @param entityId Optional identifier of the entity
|
|
27
|
+
* @param additionalInfo Optional additional information for debugging
|
|
28
|
+
* @returns A formatted ErrorContext object
|
|
29
|
+
*/
|
|
30
|
+
function buildErrorContext(entityType, operation, source, entityId, additionalInfo) {
|
|
31
|
+
return {
|
|
32
|
+
entityType,
|
|
33
|
+
operation,
|
|
34
|
+
source,
|
|
35
|
+
...(entityId && { entityId }),
|
|
36
|
+
...(additionalInfo && { additionalInfo }),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Detect specific error types from raw errors
|
|
41
|
+
* @param error The error to analyze
|
|
42
|
+
* @param context Context information for better error detection
|
|
43
|
+
* @returns Object containing the error code and status code
|
|
44
|
+
*/
|
|
45
|
+
function detectErrorType(error, context = {}) {
|
|
46
|
+
const methodLogger = logger_util_js_1.Logger.forContext('utils/error-handler.util.ts', 'detectErrorType');
|
|
47
|
+
methodLogger.debug(`Detecting error type`, { error, context });
|
|
48
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
49
|
+
const statusCode = error instanceof Error && 'statusCode' in error
|
|
50
|
+
? error.statusCode
|
|
51
|
+
: undefined;
|
|
52
|
+
// Network error detection
|
|
53
|
+
if (errorMessage.includes('network error') ||
|
|
54
|
+
errorMessage.includes('fetch failed') ||
|
|
55
|
+
errorMessage.includes('ECONNREFUSED') ||
|
|
56
|
+
errorMessage.includes('ENOTFOUND') ||
|
|
57
|
+
errorMessage.includes('Failed to fetch') ||
|
|
58
|
+
errorMessage.includes('Network request failed')) {
|
|
59
|
+
return { code: ErrorCode.NETWORK_ERROR, statusCode: 500 };
|
|
60
|
+
}
|
|
61
|
+
// Rate limiting detection
|
|
62
|
+
if (errorMessage.includes('rate limit') ||
|
|
63
|
+
errorMessage.includes('too many requests') ||
|
|
64
|
+
statusCode === 429) {
|
|
65
|
+
return { code: ErrorCode.RATE_LIMIT_ERROR, statusCode: 429 };
|
|
66
|
+
}
|
|
67
|
+
// Not Found detection
|
|
68
|
+
if (errorMessage.includes('not found') ||
|
|
69
|
+
errorMessage.includes('does not exist') ||
|
|
70
|
+
statusCode === 404) {
|
|
71
|
+
return { code: ErrorCode.NOT_FOUND, statusCode: 404 };
|
|
72
|
+
}
|
|
73
|
+
// Access Denied detection
|
|
74
|
+
if (errorMessage.includes('access') ||
|
|
75
|
+
errorMessage.includes('permission') ||
|
|
76
|
+
errorMessage.includes('authorize') ||
|
|
77
|
+
errorMessage.includes('authentication') ||
|
|
78
|
+
statusCode === 401 ||
|
|
79
|
+
statusCode === 403) {
|
|
80
|
+
return { code: ErrorCode.ACCESS_DENIED, statusCode: statusCode || 403 };
|
|
81
|
+
}
|
|
82
|
+
// Invalid Cursor detection
|
|
83
|
+
if ((errorMessage.includes('cursor') ||
|
|
84
|
+
errorMessage.includes('startAt') ||
|
|
85
|
+
errorMessage.includes('page')) &&
|
|
86
|
+
(errorMessage.includes('invalid') || errorMessage.includes('not valid'))) {
|
|
87
|
+
return { code: ErrorCode.INVALID_CURSOR, statusCode: 400 };
|
|
88
|
+
}
|
|
89
|
+
// Validation Error detection
|
|
90
|
+
if (errorMessage.includes('validation') ||
|
|
91
|
+
errorMessage.includes('invalid') ||
|
|
92
|
+
errorMessage.includes('required') ||
|
|
93
|
+
statusCode === 400 ||
|
|
94
|
+
statusCode === 422) {
|
|
95
|
+
return {
|
|
96
|
+
code: ErrorCode.VALIDATION_ERROR,
|
|
97
|
+
statusCode: statusCode || 400,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// Default to unexpected error
|
|
101
|
+
return {
|
|
102
|
+
code: ErrorCode.UNEXPECTED_ERROR,
|
|
103
|
+
statusCode: statusCode || 500,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Create user-friendly error messages based on error type and context
|
|
108
|
+
* @param code The error code
|
|
109
|
+
* @param context Context information for better error messages
|
|
110
|
+
* @param originalMessage The original error message
|
|
111
|
+
* @returns User-friendly error message
|
|
112
|
+
*/
|
|
113
|
+
function createUserFriendlyErrorMessage(code, context = {}, originalMessage) {
|
|
114
|
+
const methodLogger = logger_util_js_1.Logger.forContext('utils/error-handler.util.ts', 'createUserFriendlyErrorMessage');
|
|
115
|
+
const { entityType, entityId, operation } = context;
|
|
116
|
+
// Format entity ID for display
|
|
117
|
+
let entityIdStr = '';
|
|
118
|
+
if (entityId) {
|
|
119
|
+
if (typeof entityId === 'string') {
|
|
120
|
+
entityIdStr = entityId;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Handle object entityId
|
|
124
|
+
entityIdStr = Object.values(entityId).join('/');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Determine entity display name
|
|
128
|
+
const entity = entityType
|
|
129
|
+
? `${entityType}${entityIdStr ? ` ${entityIdStr}` : ''}`
|
|
130
|
+
: 'Resource';
|
|
131
|
+
let message = '';
|
|
132
|
+
switch (code) {
|
|
133
|
+
case ErrorCode.NOT_FOUND:
|
|
134
|
+
message = `${entity} not found${entityIdStr ? `: ${entityIdStr}` : ''}. Verify the ID is correct and that you have access to this ${entityType?.toLowerCase() || 'resource'}.`;
|
|
135
|
+
break;
|
|
136
|
+
case ErrorCode.ACCESS_DENIED:
|
|
137
|
+
message = `Access denied for ${entity.toLowerCase()}${entityIdStr ? ` ${entityIdStr}` : ''}. Verify your credentials and permissions.`;
|
|
138
|
+
break;
|
|
139
|
+
case ErrorCode.INVALID_CURSOR:
|
|
140
|
+
message = `Invalid pagination cursor. Use the exact cursor string returned from previous results.`;
|
|
141
|
+
break;
|
|
142
|
+
case ErrorCode.VALIDATION_ERROR:
|
|
143
|
+
message =
|
|
144
|
+
originalMessage ||
|
|
145
|
+
`Invalid data provided for ${operation || 'operation'} ${entity.toLowerCase()}.`;
|
|
146
|
+
break;
|
|
147
|
+
case ErrorCode.NETWORK_ERROR:
|
|
148
|
+
message = `Network error while ${operation || 'connecting to'} the service. Please check your internet connection and try again.`;
|
|
149
|
+
break;
|
|
150
|
+
case ErrorCode.RATE_LIMIT_ERROR:
|
|
151
|
+
message = `Rate limit exceeded. Please wait a moment and try again, or reduce the frequency of requests.`;
|
|
152
|
+
break;
|
|
153
|
+
default:
|
|
154
|
+
message = `An unexpected error occurred while ${operation || 'processing'} ${entity.toLowerCase()}.`;
|
|
155
|
+
}
|
|
156
|
+
// Include original message details if available and appropriate
|
|
157
|
+
if (originalMessage &&
|
|
158
|
+
code !== ErrorCode.NOT_FOUND &&
|
|
159
|
+
code !== ErrorCode.ACCESS_DENIED) {
|
|
160
|
+
message += ` Error details: ${originalMessage}`;
|
|
161
|
+
}
|
|
162
|
+
methodLogger.debug(`Created user-friendly message: ${message}`, {
|
|
163
|
+
code,
|
|
164
|
+
context,
|
|
165
|
+
});
|
|
166
|
+
return message;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Handle controller errors consistently
|
|
170
|
+
* @param error The error to handle
|
|
171
|
+
* @param context Context information for better error messages
|
|
172
|
+
* @returns Never returns, always throws an error
|
|
173
|
+
*/
|
|
174
|
+
function handleControllerError(error, context = {}) {
|
|
175
|
+
const methodLogger = logger_util_js_1.Logger.forContext('utils/error-handler.util.ts', 'handleControllerError');
|
|
176
|
+
// Extract error details
|
|
177
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
178
|
+
const statusCode = error instanceof Error && 'statusCode' in error
|
|
179
|
+
? error.statusCode
|
|
180
|
+
: undefined;
|
|
181
|
+
// Detect error type using utility
|
|
182
|
+
const { code, statusCode: detectedStatus } = detectErrorType(error, context);
|
|
183
|
+
// Combine detected status with explicit status
|
|
184
|
+
const finalStatusCode = statusCode || detectedStatus;
|
|
185
|
+
// Format entity information for logging
|
|
186
|
+
const { entityType, entityId, operation } = context;
|
|
187
|
+
const entity = entityType || 'resource';
|
|
188
|
+
const entityIdStr = entityId
|
|
189
|
+
? typeof entityId === 'string'
|
|
190
|
+
? entityId
|
|
191
|
+
: JSON.stringify(entityId)
|
|
192
|
+
: '';
|
|
193
|
+
const actionStr = operation || 'processing';
|
|
194
|
+
// Log detailed error information
|
|
195
|
+
methodLogger.error(`Error ${actionStr} ${entity}${entityIdStr ? `: ${entityIdStr}` : ''}: ${errorMessage}`, error);
|
|
196
|
+
// Create user-friendly error message for the response
|
|
197
|
+
const message = code === ErrorCode.VALIDATION_ERROR
|
|
198
|
+
? errorMessage
|
|
199
|
+
: createUserFriendlyErrorMessage(code, context, errorMessage);
|
|
200
|
+
// Throw an appropriate API error with the user-friendly message
|
|
201
|
+
throw (0, error_util_js_1.createApiError)(message, finalStatusCode, error);
|
|
202
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types for classification
|
|
3
|
+
*/
|
|
4
|
+
export declare enum ErrorType {
|
|
5
|
+
AUTH_MISSING = "AUTH_MISSING",
|
|
6
|
+
AUTH_INVALID = "AUTH_INVALID",
|
|
7
|
+
API_ERROR = "API_ERROR",
|
|
8
|
+
UNEXPECTED_ERROR = "UNEXPECTED_ERROR"
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Custom error class with type classification
|
|
12
|
+
*/
|
|
13
|
+
export declare class McpError extends Error {
|
|
14
|
+
type: ErrorType;
|
|
15
|
+
statusCode?: number;
|
|
16
|
+
originalError?: unknown;
|
|
17
|
+
constructor(message: string, type: ErrorType, statusCode?: number, originalError?: unknown);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create an authentication missing error
|
|
21
|
+
*/
|
|
22
|
+
export declare function createAuthMissingError(message?: string): McpError;
|
|
23
|
+
/**
|
|
24
|
+
* Create an authentication invalid error
|
|
25
|
+
*/
|
|
26
|
+
export declare function createAuthInvalidError(message?: string): McpError;
|
|
27
|
+
/**
|
|
28
|
+
* Create an API error
|
|
29
|
+
*/
|
|
30
|
+
export declare function createApiError(message: string, statusCode?: number, originalError?: unknown): McpError;
|
|
31
|
+
/**
|
|
32
|
+
* Create an unexpected error
|
|
33
|
+
*/
|
|
34
|
+
export declare function createUnexpectedError(message?: string, originalError?: unknown): McpError;
|
|
35
|
+
/**
|
|
36
|
+
* Ensure an error is an McpError
|
|
37
|
+
*/
|
|
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;
|
|
45
|
+
/**
|
|
46
|
+
* Format error for MCP tool response
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatErrorForMcpTool(error: unknown): {
|
|
49
|
+
content: Array<{
|
|
50
|
+
type: 'text';
|
|
51
|
+
text: string;
|
|
52
|
+
}>;
|
|
53
|
+
metadata?: {
|
|
54
|
+
errorType: ErrorType;
|
|
55
|
+
statusCode?: number;
|
|
56
|
+
errorDetails?: unknown;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Format error for MCP resource response
|
|
61
|
+
*/
|
|
62
|
+
export declare function formatErrorForMcpResource(error: unknown, uri: string): {
|
|
63
|
+
contents: Array<{
|
|
64
|
+
uri: string;
|
|
65
|
+
text: string;
|
|
66
|
+
mimeType: string;
|
|
67
|
+
description?: string;
|
|
68
|
+
}>;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Handle error in CLI context with improved user feedback
|
|
72
|
+
*/
|
|
73
|
+
export declare function handleCliError(error: unknown): never;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpError = exports.ErrorType = void 0;
|
|
4
|
+
exports.createAuthMissingError = createAuthMissingError;
|
|
5
|
+
exports.createAuthInvalidError = createAuthInvalidError;
|
|
6
|
+
exports.createApiError = createApiError;
|
|
7
|
+
exports.createUnexpectedError = createUnexpectedError;
|
|
8
|
+
exports.ensureMcpError = ensureMcpError;
|
|
9
|
+
exports.getDeepOriginalError = getDeepOriginalError;
|
|
10
|
+
exports.formatErrorForMcpTool = formatErrorForMcpTool;
|
|
11
|
+
exports.formatErrorForMcpResource = formatErrorForMcpResource;
|
|
12
|
+
exports.handleCliError = handleCliError;
|
|
13
|
+
const logger_util_js_1 = require("./logger.util.js");
|
|
14
|
+
/**
|
|
15
|
+
* Error types for classification
|
|
16
|
+
*/
|
|
17
|
+
var ErrorType;
|
|
18
|
+
(function (ErrorType) {
|
|
19
|
+
ErrorType["AUTH_MISSING"] = "AUTH_MISSING";
|
|
20
|
+
ErrorType["AUTH_INVALID"] = "AUTH_INVALID";
|
|
21
|
+
ErrorType["API_ERROR"] = "API_ERROR";
|
|
22
|
+
ErrorType["UNEXPECTED_ERROR"] = "UNEXPECTED_ERROR";
|
|
23
|
+
})(ErrorType || (exports.ErrorType = ErrorType = {}));
|
|
24
|
+
/**
|
|
25
|
+
* Custom error class with type classification
|
|
26
|
+
*/
|
|
27
|
+
class McpError extends Error {
|
|
28
|
+
constructor(message, type, statusCode, originalError) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = 'McpError';
|
|
31
|
+
this.type = type;
|
|
32
|
+
this.statusCode = statusCode;
|
|
33
|
+
this.originalError = originalError;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.McpError = McpError;
|
|
37
|
+
/**
|
|
38
|
+
* Create an authentication missing error
|
|
39
|
+
*/
|
|
40
|
+
function createAuthMissingError(message = 'Authentication credentials are missing') {
|
|
41
|
+
return new McpError(message, ErrorType.AUTH_MISSING);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create an authentication invalid error
|
|
45
|
+
*/
|
|
46
|
+
function createAuthInvalidError(message = 'Authentication credentials are invalid') {
|
|
47
|
+
return new McpError(message, ErrorType.AUTH_INVALID, 401);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create an API error
|
|
51
|
+
*/
|
|
52
|
+
function createApiError(message, statusCode, originalError) {
|
|
53
|
+
return new McpError(message, ErrorType.API_ERROR, statusCode, originalError);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create an unexpected error
|
|
57
|
+
*/
|
|
58
|
+
function createUnexpectedError(message = 'An unexpected error occurred', originalError) {
|
|
59
|
+
return new McpError(message, ErrorType.UNEXPECTED_ERROR, undefined, originalError);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Ensure an error is an McpError
|
|
63
|
+
*/
|
|
64
|
+
function ensureMcpError(error) {
|
|
65
|
+
if (error instanceof McpError) {
|
|
66
|
+
return error;
|
|
67
|
+
}
|
|
68
|
+
if (error instanceof Error) {
|
|
69
|
+
return createUnexpectedError(error.message, error);
|
|
70
|
+
}
|
|
71
|
+
return createUnexpectedError(String(error));
|
|
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
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Format error for MCP tool response
|
|
96
|
+
*/
|
|
97
|
+
function formatErrorForMcpTool(error) {
|
|
98
|
+
const methodLogger = logger_util_js_1.Logger.forContext('utils/error.util.ts', 'formatErrorForMcpTool');
|
|
99
|
+
const mcpError = ensureMcpError(error);
|
|
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;
|
|
107
|
+
return {
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: `Error: ${mcpError.message}`,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
metadata: {
|
|
115
|
+
errorType: mcpError.type,
|
|
116
|
+
statusCode: mcpError.statusCode,
|
|
117
|
+
errorDetails,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Format error for MCP resource response
|
|
123
|
+
*/
|
|
124
|
+
function formatErrorForMcpResource(error, uri) {
|
|
125
|
+
const methodLogger = logger_util_js_1.Logger.forContext('utils/error.util.ts', 'formatErrorForMcpResource');
|
|
126
|
+
const mcpError = ensureMcpError(error);
|
|
127
|
+
methodLogger.error(`${mcpError.type} error`, mcpError);
|
|
128
|
+
return {
|
|
129
|
+
contents: [
|
|
130
|
+
{
|
|
131
|
+
uri,
|
|
132
|
+
text: `Error: ${mcpError.message}`,
|
|
133
|
+
mimeType: 'text/plain',
|
|
134
|
+
description: `Error: ${mcpError.type}`,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Handle error in CLI context with improved user feedback
|
|
141
|
+
*/
|
|
142
|
+
function handleCliError(error) {
|
|
143
|
+
const methodLogger = logger_util_js_1.Logger.forContext('utils/error.util.ts', 'handleCliError');
|
|
144
|
+
const mcpError = ensureMcpError(error);
|
|
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
|
|
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 API error context if available
|
|
162
|
+
if (originalError && typeof originalError === 'object') {
|
|
163
|
+
const origErr = originalError;
|
|
164
|
+
if (origErr.message) {
|
|
165
|
+
console.error(`\nAPI error: ${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
|
+
}
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized formatting utilities for consistent output across all CLI and Tool interfaces.
|
|
3
|
+
* These functions should be used by all formatters to ensure consistent formatting.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Format a date in a standardized way: YYYY-MM-DD HH:MM:SS UTC
|
|
7
|
+
* @param dateString - ISO date string or Date object
|
|
8
|
+
* @returns Formatted date string
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatDate(dateString?: string | Date): string;
|
|
11
|
+
/**
|
|
12
|
+
* Format a URL as a markdown link
|
|
13
|
+
* @param url - URL to format
|
|
14
|
+
* @param title - Link title
|
|
15
|
+
* @returns Formatted markdown link
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatUrl(url?: string, title?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Format a heading with consistent style
|
|
20
|
+
* @param text - Heading text
|
|
21
|
+
* @param level - Heading level (1-6)
|
|
22
|
+
* @returns Formatted heading
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatHeading(text: string, level?: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* Format a list of key-value pairs as a bullet list
|
|
27
|
+
* @param items - Object with key-value pairs
|
|
28
|
+
* @param keyFormatter - Optional function to format keys
|
|
29
|
+
* @returns Formatted bullet list
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatBulletList(items: Record<string, unknown>, keyFormatter?: (key: string) => string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Format a separator line
|
|
34
|
+
* @returns Separator line
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatSeparator(): string;
|