@cyanheads/pubchem-mcp-server 1.0.1
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/LICENSE +201 -0
- package/README.md +236 -0
- package/dist/config/index.d.ts +98 -0
- package/dist/config/index.js +326 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +214 -0
- package/dist/mcp-server/server.d.ts +21 -0
- package/dist/mcp-server/server.js +124 -0
- package/dist/mcp-server/tools/fetchAssaySummary/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchAssaySummary/index.js +7 -0
- package/dist/mcp-server/tools/fetchAssaySummary/logic.d.ts +71 -0
- package/dist/mcp-server/tools/fetchAssaySummary/logic.js +96 -0
- package/dist/mcp-server/tools/fetchAssaySummary/registration.d.ts +12 -0
- package/dist/mcp-server/tools/fetchAssaySummary/registration.js +68 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/index.js +7 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/logic.d.ts +131 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/logic.js +100 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/registration.d.ts +13 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/registration.js +52 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/index.js +7 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/logic.d.ts +89 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/logic.js +145 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/registration.d.ts +13 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/registration.js +52 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/index.js +7 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/logic.d.ts +69 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/logic.js +97 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/registration.d.ts +13 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/registration.js +79 -0
- package/dist/mcp-server/tools/getCompoundImage/index.d.ts +7 -0
- package/dist/mcp-server/tools/getCompoundImage/index.js +7 -0
- package/dist/mcp-server/tools/getCompoundImage/logic.d.ts +42 -0
- package/dist/mcp-server/tools/getCompoundImage/logic.js +68 -0
- package/dist/mcp-server/tools/getCompoundImage/registration.d.ts +12 -0
- package/dist/mcp-server/tools/getCompoundImage/registration.js +57 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/index.js +7 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/logic.d.ts +35 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/logic.js +64 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/registration.js +62 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/logic.d.ts +35 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/logic.js +59 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/registration.js +51 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/logic.d.ts +38 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/logic.js +75 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/registration.js +62 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/logic.d.ts +41 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/logic.js +82 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/registration.js +62 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/logic.d.ts +41 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/logic.js +78 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/registration.d.ts +13 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/registration.js +63 -0
- package/dist/mcp-server/transports/auth/core/authContext.d.ts +33 -0
- package/dist/mcp-server/transports/auth/core/authContext.js +24 -0
- package/dist/mcp-server/transports/auth/core/authTypes.d.ts +17 -0
- package/dist/mcp-server/transports/auth/core/authTypes.js +5 -0
- package/dist/mcp-server/transports/auth/core/authUtils.d.ts +18 -0
- package/dist/mcp-server/transports/auth/core/authUtils.js +45 -0
- package/dist/mcp-server/transports/auth/index.d.ts +10 -0
- package/dist/mcp-server/transports/auth/index.js +9 -0
- package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.d.ts +27 -0
- package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.js +149 -0
- package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.d.ts +20 -0
- package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.js +124 -0
- package/dist/mcp-server/transports/httpErrorHandler.d.ts +26 -0
- package/dist/mcp-server/transports/httpErrorHandler.js +73 -0
- package/dist/mcp-server/transports/httpTransport.d.ts +21 -0
- package/dist/mcp-server/transports/httpTransport.js +208 -0
- package/dist/mcp-server/transports/stdioTransport.d.ts +42 -0
- package/dist/mcp-server/transports/stdioTransport.js +63 -0
- package/dist/services/pubchem/pubchemApiClient.d.ts +52 -0
- package/dist/services/pubchem/pubchemApiClient.js +120 -0
- package/dist/types-global/errors.d.ts +127 -0
- package/dist/types-global/errors.js +126 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.js +20 -0
- package/dist/utils/internal/errorHandler.d.ts +176 -0
- package/dist/utils/internal/errorHandler.js +335 -0
- package/dist/utils/internal/index.d.ts +9 -0
- package/dist/utils/internal/index.js +9 -0
- package/dist/utils/internal/logger.d.ts +148 -0
- package/dist/utils/internal/logger.js +430 -0
- package/dist/utils/internal/requestContext.d.ts +83 -0
- package/dist/utils/internal/requestContext.js +72 -0
- package/dist/utils/metrics/index.d.ts +7 -0
- package/dist/utils/metrics/index.js +7 -0
- package/dist/utils/metrics/tokenCounter.d.ts +35 -0
- package/dist/utils/metrics/tokenCounter.js +110 -0
- package/dist/utils/network/fetchWithTimeout.d.ts +21 -0
- package/dist/utils/network/fetchWithTimeout.js +59 -0
- package/dist/utils/network/index.d.ts +6 -0
- package/dist/utils/network/index.js +5 -0
- package/dist/utils/parsing/dateParser.d.ts +73 -0
- package/dist/utils/parsing/dateParser.js +107 -0
- package/dist/utils/parsing/index.d.ts +8 -0
- package/dist/utils/parsing/index.js +8 -0
- package/dist/utils/parsing/jsonParser.d.ts +82 -0
- package/dist/utils/parsing/jsonParser.js +126 -0
- package/dist/utils/scheduling/index.d.ts +6 -0
- package/dist/utils/scheduling/index.js +6 -0
- package/dist/utils/scheduling/scheduler.d.ts +72 -0
- package/dist/utils/scheduling/scheduler.js +152 -0
- package/dist/utils/security/idGenerator.d.ts +137 -0
- package/dist/utils/security/idGenerator.js +215 -0
- package/dist/utils/security/index.d.ts +9 -0
- package/dist/utils/security/index.js +9 -0
- package/dist/utils/security/rateLimiter.d.ts +108 -0
- package/dist/utils/security/rateLimiter.js +179 -0
- package/dist/utils/security/sanitization.d.ts +184 -0
- package/dist/utils/security/sanitization.js +453 -0
- package/package.json +108 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utilities for creating and managing request contexts.
|
|
3
|
+
* A request context is an object carrying a unique ID, timestamp, and other
|
|
4
|
+
* relevant data for logging, tracing, and processing. It also defines
|
|
5
|
+
* configuration and operational context structures.
|
|
6
|
+
* @module src/utils/internal/requestContext
|
|
7
|
+
*/
|
|
8
|
+
import { generateUUID } from "../index.js";
|
|
9
|
+
import { logger } from "./logger.js";
|
|
10
|
+
/**
|
|
11
|
+
* Singleton-like service object for managing request context operations.
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
const requestContextServiceInstance = {
|
|
15
|
+
/**
|
|
16
|
+
* Internal configuration store for the service.
|
|
17
|
+
*/
|
|
18
|
+
config: {},
|
|
19
|
+
/**
|
|
20
|
+
* Configures the request context service with new settings.
|
|
21
|
+
* Merges the provided partial configuration with existing settings.
|
|
22
|
+
*
|
|
23
|
+
* @param config - A partial `ContextConfig` object containing settings to update or add.
|
|
24
|
+
* @returns A shallow copy of the newly updated configuration.
|
|
25
|
+
*/
|
|
26
|
+
configure(config) {
|
|
27
|
+
this.config = {
|
|
28
|
+
...this.config,
|
|
29
|
+
...config,
|
|
30
|
+
};
|
|
31
|
+
const logContext = this.createRequestContext({
|
|
32
|
+
operation: "RequestContextService.configure",
|
|
33
|
+
newConfigState: { ...this.config },
|
|
34
|
+
});
|
|
35
|
+
logger.debug("RequestContextService configuration updated", logContext);
|
|
36
|
+
return { ...this.config };
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Retrieves a shallow copy of the current service configuration.
|
|
40
|
+
* This prevents direct mutation of the internal configuration state.
|
|
41
|
+
*
|
|
42
|
+
* @returns A shallow copy of the current `ContextConfig`.
|
|
43
|
+
*/
|
|
44
|
+
getConfig() {
|
|
45
|
+
return { ...this.config };
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
* Creates a new {@link RequestContext} instance.
|
|
49
|
+
* Each context is assigned a unique `requestId` (UUID) and a current `timestamp` (ISO 8601).
|
|
50
|
+
* Additional custom properties can be merged into the context.
|
|
51
|
+
*
|
|
52
|
+
* @param additionalContext - An optional record of key-value pairs to be
|
|
53
|
+
* included in the created request context.
|
|
54
|
+
* @returns A new `RequestContext` object.
|
|
55
|
+
*/
|
|
56
|
+
createRequestContext(additionalContext = {}) {
|
|
57
|
+
const requestId = generateUUID();
|
|
58
|
+
const timestamp = new Date().toISOString();
|
|
59
|
+
const context = {
|
|
60
|
+
requestId,
|
|
61
|
+
timestamp,
|
|
62
|
+
...additionalContext,
|
|
63
|
+
};
|
|
64
|
+
return context;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Primary export for request context functionalities.
|
|
69
|
+
* This service provides methods to create and manage {@link RequestContext} instances,
|
|
70
|
+
* which are essential for logging, tracing, and correlating operations.
|
|
71
|
+
*/
|
|
72
|
+
export const requestContextService = requestContextServiceInstance;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides utility functions for counting tokens in text and chat messages
|
|
3
|
+
* using the `tiktoken` library, specifically configured for 'gpt-4o' tokenization.
|
|
4
|
+
* These functions are essential for managing token limits and estimating costs
|
|
5
|
+
* when interacting with language models.
|
|
6
|
+
* @module src/utils/metrics/tokenCounter
|
|
7
|
+
*/
|
|
8
|
+
import { ChatCompletionMessageParam } from "openai/resources/chat/completions";
|
|
9
|
+
import { RequestContext } from "../index.js";
|
|
10
|
+
/**
|
|
11
|
+
* Calculates the number of tokens for a given text string using the
|
|
12
|
+
* tokenizer specified by `TOKENIZATION_MODEL`.
|
|
13
|
+
* Wraps tokenization in `ErrorHandler.tryCatch` for robust error management.
|
|
14
|
+
*
|
|
15
|
+
* @param text - The input text to tokenize.
|
|
16
|
+
* @param context - Optional request context for logging and error handling.
|
|
17
|
+
* @returns A promise that resolves with the number of tokens in the text.
|
|
18
|
+
* @throws {McpError} If tokenization fails.
|
|
19
|
+
*/
|
|
20
|
+
export declare function countTokens(text: string, context?: RequestContext): Promise<number>;
|
|
21
|
+
/**
|
|
22
|
+
* Calculates the estimated number of tokens for an array of chat messages.
|
|
23
|
+
* Uses the tokenizer specified by `TOKENIZATION_MODEL` and accounts for
|
|
24
|
+
* special tokens and message overhead according to OpenAI's guidelines.
|
|
25
|
+
*
|
|
26
|
+
* For multi-part content, only text parts are currently tokenized.
|
|
27
|
+
*
|
|
28
|
+
* Reference: {@link https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb}
|
|
29
|
+
*
|
|
30
|
+
* @param messages - An array of chat messages.
|
|
31
|
+
* @param context - Optional request context for logging and error handling.
|
|
32
|
+
* @returns A promise that resolves with the estimated total number of tokens.
|
|
33
|
+
* @throws {McpError} If tokenization fails.
|
|
34
|
+
*/
|
|
35
|
+
export declare function countChatTokens(messages: ReadonlyArray<ChatCompletionMessageParam>, context?: RequestContext): Promise<number>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { encoding_for_model } from "tiktoken";
|
|
2
|
+
import { BaseErrorCode } from "../../types-global/errors.js";
|
|
3
|
+
import { ErrorHandler, logger } from "../index.js";
|
|
4
|
+
/**
|
|
5
|
+
* The specific Tiktoken model used for all tokenization operations in this module.
|
|
6
|
+
* This ensures consistent token counting.
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
const TOKENIZATION_MODEL = "gpt-4o";
|
|
10
|
+
/**
|
|
11
|
+
* Calculates the number of tokens for a given text string using the
|
|
12
|
+
* tokenizer specified by `TOKENIZATION_MODEL`.
|
|
13
|
+
* Wraps tokenization in `ErrorHandler.tryCatch` for robust error management.
|
|
14
|
+
*
|
|
15
|
+
* @param text - The input text to tokenize.
|
|
16
|
+
* @param context - Optional request context for logging and error handling.
|
|
17
|
+
* @returns A promise that resolves with the number of tokens in the text.
|
|
18
|
+
* @throws {McpError} If tokenization fails.
|
|
19
|
+
*/
|
|
20
|
+
export async function countTokens(text, context) {
|
|
21
|
+
return ErrorHandler.tryCatch(() => {
|
|
22
|
+
let encoding = null;
|
|
23
|
+
try {
|
|
24
|
+
encoding = encoding_for_model(TOKENIZATION_MODEL);
|
|
25
|
+
const tokens = encoding.encode(text);
|
|
26
|
+
return tokens.length;
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
encoding?.free();
|
|
30
|
+
}
|
|
31
|
+
}, {
|
|
32
|
+
operation: "countTokens",
|
|
33
|
+
context: context,
|
|
34
|
+
input: { textSample: text.substring(0, 50) + "..." },
|
|
35
|
+
errorCode: BaseErrorCode.INTERNAL_ERROR,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the estimated number of tokens for an array of chat messages.
|
|
40
|
+
* Uses the tokenizer specified by `TOKENIZATION_MODEL` and accounts for
|
|
41
|
+
* special tokens and message overhead according to OpenAI's guidelines.
|
|
42
|
+
*
|
|
43
|
+
* For multi-part content, only text parts are currently tokenized.
|
|
44
|
+
*
|
|
45
|
+
* Reference: {@link https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb}
|
|
46
|
+
*
|
|
47
|
+
* @param messages - An array of chat messages.
|
|
48
|
+
* @param context - Optional request context for logging and error handling.
|
|
49
|
+
* @returns A promise that resolves with the estimated total number of tokens.
|
|
50
|
+
* @throws {McpError} If tokenization fails.
|
|
51
|
+
*/
|
|
52
|
+
export async function countChatTokens(messages, context) {
|
|
53
|
+
return ErrorHandler.tryCatch(() => {
|
|
54
|
+
let encoding = null;
|
|
55
|
+
let num_tokens = 0;
|
|
56
|
+
try {
|
|
57
|
+
encoding = encoding_for_model(TOKENIZATION_MODEL);
|
|
58
|
+
const tokens_per_message = 3; // For gpt-4o, gpt-4, gpt-3.5-turbo
|
|
59
|
+
const tokens_per_name = 1; // For gpt-4o, gpt-4, gpt-3.5-turbo
|
|
60
|
+
for (const message of messages) {
|
|
61
|
+
num_tokens += tokens_per_message;
|
|
62
|
+
num_tokens += encoding.encode(message.role).length;
|
|
63
|
+
if (typeof message.content === "string") {
|
|
64
|
+
num_tokens += encoding.encode(message.content).length;
|
|
65
|
+
}
|
|
66
|
+
else if (Array.isArray(message.content)) {
|
|
67
|
+
for (const part of message.content) {
|
|
68
|
+
if (part.type === "text") {
|
|
69
|
+
num_tokens += encoding.encode(part.text).length;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
logger.warning(`Non-text content part found (type: ${part.type}), token count contribution ignored.`, context);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if ("name" in message && message.name) {
|
|
77
|
+
num_tokens += tokens_per_name;
|
|
78
|
+
num_tokens += encoding.encode(message.name).length;
|
|
79
|
+
}
|
|
80
|
+
if (message.role === "assistant" &&
|
|
81
|
+
"tool_calls" in message &&
|
|
82
|
+
message.tool_calls) {
|
|
83
|
+
for (const tool_call of message.tool_calls) {
|
|
84
|
+
if (tool_call.function.name) {
|
|
85
|
+
num_tokens += encoding.encode(tool_call.function.name).length;
|
|
86
|
+
}
|
|
87
|
+
if (tool_call.function.arguments) {
|
|
88
|
+
num_tokens += encoding.encode(tool_call.function.arguments).length;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (message.role === "tool" &&
|
|
93
|
+
"tool_call_id" in message &&
|
|
94
|
+
message.tool_call_id) {
|
|
95
|
+
num_tokens += encoding.encode(message.tool_call_id).length;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
num_tokens += 3; // Every reply is primed with <|start|>assistant<|message|>
|
|
99
|
+
return num_tokens;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
encoding?.free();
|
|
103
|
+
}
|
|
104
|
+
}, {
|
|
105
|
+
operation: "countChatTokens",
|
|
106
|
+
context: context,
|
|
107
|
+
input: { messageCount: messages.length },
|
|
108
|
+
errorCode: BaseErrorCode.INTERNAL_ERROR,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a utility function to make fetch requests with a specified timeout.
|
|
3
|
+
* @module src/utils/network/fetchWithTimeout
|
|
4
|
+
*/
|
|
5
|
+
import type { RequestContext } from "../internal/requestContext.js";
|
|
6
|
+
/**
|
|
7
|
+
* Options for the fetchWithTimeout utility.
|
|
8
|
+
* Extends standard RequestInit but omits 'signal' as it's handled internally.
|
|
9
|
+
*/
|
|
10
|
+
export type FetchWithTimeoutOptions = Omit<RequestInit, "signal">;
|
|
11
|
+
/**
|
|
12
|
+
* Fetches a resource with a specified timeout.
|
|
13
|
+
*
|
|
14
|
+
* @param url - The URL to fetch.
|
|
15
|
+
* @param timeoutMs - The timeout duration in milliseconds.
|
|
16
|
+
* @param context - The request context for logging.
|
|
17
|
+
* @param options - Optional fetch options (RequestInit), excluding 'signal'.
|
|
18
|
+
* @returns A promise that resolves to the Response object.
|
|
19
|
+
* @throws {McpError} If the request times out or another fetch-related error occurs.
|
|
20
|
+
*/
|
|
21
|
+
export declare function fetchWithTimeout(url: string | URL, timeoutMs: number, context: RequestContext, options?: FetchWithTimeoutOptions): Promise<Response>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a utility function to make fetch requests with a specified timeout.
|
|
3
|
+
* @module src/utils/network/fetchWithTimeout
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from "../internal/logger.js"; // Adjusted import path
|
|
6
|
+
import { McpError, BaseErrorCode } from "../../types-global/errors.js";
|
|
7
|
+
/**
|
|
8
|
+
* Fetches a resource with a specified timeout.
|
|
9
|
+
*
|
|
10
|
+
* @param url - The URL to fetch.
|
|
11
|
+
* @param timeoutMs - The timeout duration in milliseconds.
|
|
12
|
+
* @param context - The request context for logging.
|
|
13
|
+
* @param options - Optional fetch options (RequestInit), excluding 'signal'.
|
|
14
|
+
* @returns A promise that resolves to the Response object.
|
|
15
|
+
* @throws {McpError} If the request times out or another fetch-related error occurs.
|
|
16
|
+
*/
|
|
17
|
+
export async function fetchWithTimeout(url, timeoutMs, context, options) {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
20
|
+
const urlString = url.toString();
|
|
21
|
+
const operationDescription = `fetch ${options?.method || "GET"} ${urlString}`;
|
|
22
|
+
logger.debug(`Attempting ${operationDescription} with ${timeoutMs}ms timeout.`, context);
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(url, {
|
|
25
|
+
...options,
|
|
26
|
+
signal: controller.signal,
|
|
27
|
+
});
|
|
28
|
+
clearTimeout(timeoutId);
|
|
29
|
+
logger.debug(`Successfully fetched ${urlString}. Status: ${response.status}`, context);
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
clearTimeout(timeoutId);
|
|
34
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
35
|
+
logger.error(`${operationDescription} timed out after ${timeoutMs}ms.`, {
|
|
36
|
+
...context,
|
|
37
|
+
errorSource: "FetchTimeout",
|
|
38
|
+
});
|
|
39
|
+
throw new McpError(BaseErrorCode.TIMEOUT, `${operationDescription} timed out.`, { ...context, errorSource: "FetchTimeout" });
|
|
40
|
+
}
|
|
41
|
+
// Log and re-throw other errors as McpError
|
|
42
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
43
|
+
logger.error(`Network error during ${operationDescription}: ${errorMessage}`, {
|
|
44
|
+
...context,
|
|
45
|
+
originalErrorName: error instanceof Error ? error.name : "UnknownError",
|
|
46
|
+
errorSource: "FetchNetworkError",
|
|
47
|
+
});
|
|
48
|
+
if (error instanceof McpError) {
|
|
49
|
+
// If it's already an McpError, re-throw it
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
throw new McpError(BaseErrorCode.SERVICE_UNAVAILABLE, // Generic error for network/service issues
|
|
53
|
+
`Network error during ${operationDescription}: ${errorMessage}`, {
|
|
54
|
+
...context,
|
|
55
|
+
originalErrorName: error instanceof Error ? error.name : "UnknownError",
|
|
56
|
+
errorSource: "FetchNetworkErrorWrapper",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides utility functions for parsing natural language date strings
|
|
3
|
+
* into Date objects or detailed parsing results using the `chrono-node` library.
|
|
4
|
+
* @module src/utils/parsing/dateParser
|
|
5
|
+
*/
|
|
6
|
+
import * as chrono from "chrono-node";
|
|
7
|
+
import { RequestContext } from "../index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Parses a natural language date string into a JavaScript Date object.
|
|
10
|
+
* Uses `chrono.parseDate` for lenient parsing of various date formats.
|
|
11
|
+
*
|
|
12
|
+
* @param text - The natural language date string to parse.
|
|
13
|
+
* @param context - The request context for logging and error tracking.
|
|
14
|
+
* @param refDate - Optional reference date for parsing relative dates. Defaults to current date/time.
|
|
15
|
+
* @returns A promise resolving with a Date object or `null` if parsing fails.
|
|
16
|
+
* @throws {McpError} If an unexpected error occurs during parsing.
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
declare function parseDateString(text: string, context: RequestContext, refDate?: Date): Promise<Date | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Parses a natural language date string and returns detailed parsing results.
|
|
22
|
+
* Provides more information than just the Date object, including matched text and components.
|
|
23
|
+
*
|
|
24
|
+
* @param text - The natural language date string to parse.
|
|
25
|
+
* @param context - The request context for logging and error tracking.
|
|
26
|
+
* @param refDate - Optional reference date for parsing relative dates. Defaults to current date/time.
|
|
27
|
+
* @returns A promise resolving with an array of `chrono.ParsedResult` objects. Empty if no dates found.
|
|
28
|
+
* @throws {McpError} If an unexpected error occurs during parsing.
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
31
|
+
declare function parseDateStringDetailed(text: string, context: RequestContext, refDate?: Date): Promise<chrono.ParsedResult[]>;
|
|
32
|
+
/**
|
|
33
|
+
* An object providing date parsing functionalities.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { dateParser, requestContextService } from './utils'; // Assuming utils/index.js exports these
|
|
38
|
+
* const context = requestContextService.createRequestContext({ operation: 'TestDateParsing' });
|
|
39
|
+
*
|
|
40
|
+
* async function testParsing() {
|
|
41
|
+
* const dateObj = await dateParser.parseDate("next Friday at 3pm", context);
|
|
42
|
+
* if (dateObj) {
|
|
43
|
+
* console.log("Parsed Date:", dateObj.toISOString());
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* const detailedResults = await dateParser.parse("Meeting on 2024-12-25 and another one tomorrow", context);
|
|
47
|
+
* detailedResults.forEach(result => {
|
|
48
|
+
* console.log("Detailed Result:", result.text, result.start.date());
|
|
49
|
+
* });
|
|
50
|
+
* }
|
|
51
|
+
* testParsing();
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare const dateParser: {
|
|
55
|
+
/**
|
|
56
|
+
* Parses a natural language date string and returns detailed parsing results
|
|
57
|
+
* from `chrono-node`.
|
|
58
|
+
* @param text - The natural language date string to parse.
|
|
59
|
+
* @param context - The request context for logging and error tracking.
|
|
60
|
+
* @param refDate - Optional reference date for parsing relative dates.
|
|
61
|
+
* @returns A promise resolving with an array of `chrono.ParsedResult` objects.
|
|
62
|
+
*/
|
|
63
|
+
parse: typeof parseDateStringDetailed;
|
|
64
|
+
/**
|
|
65
|
+
* Parses a natural language date string into a single JavaScript Date object.
|
|
66
|
+
* @param text - The natural language date string to parse.
|
|
67
|
+
* @param context - The request context for logging and error tracking.
|
|
68
|
+
* @param refDate - Optional reference date for parsing relative dates.
|
|
69
|
+
* @returns A promise resolving with a Date object or `null`.
|
|
70
|
+
*/
|
|
71
|
+
parseDate: typeof parseDateString;
|
|
72
|
+
};
|
|
73
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides utility functions for parsing natural language date strings
|
|
3
|
+
* into Date objects or detailed parsing results using the `chrono-node` library.
|
|
4
|
+
* @module src/utils/parsing/dateParser
|
|
5
|
+
*/
|
|
6
|
+
import * as chrono from "chrono-node";
|
|
7
|
+
import { BaseErrorCode } from "../../types-global/errors.js";
|
|
8
|
+
import { ErrorHandler, logger } from "../index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Parses a natural language date string into a JavaScript Date object.
|
|
11
|
+
* Uses `chrono.parseDate` for lenient parsing of various date formats.
|
|
12
|
+
*
|
|
13
|
+
* @param text - The natural language date string to parse.
|
|
14
|
+
* @param context - The request context for logging and error tracking.
|
|
15
|
+
* @param refDate - Optional reference date for parsing relative dates. Defaults to current date/time.
|
|
16
|
+
* @returns A promise resolving with a Date object or `null` if parsing fails.
|
|
17
|
+
* @throws {McpError} If an unexpected error occurs during parsing.
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
async function parseDateString(text, context, refDate) {
|
|
21
|
+
const operation = "parseDateString";
|
|
22
|
+
const logContext = { ...context, operation, inputText: text, refDate };
|
|
23
|
+
logger.debug(`Attempting to parse date string: "${text}"`, logContext);
|
|
24
|
+
return await ErrorHandler.tryCatch(async () => {
|
|
25
|
+
const parsedDate = chrono.parseDate(text, refDate, { forwardDate: true });
|
|
26
|
+
if (parsedDate) {
|
|
27
|
+
logger.debug(`Successfully parsed "${text}" to ${parsedDate.toISOString()}`, logContext);
|
|
28
|
+
return parsedDate;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logger.warning(`Failed to parse date string: "${text}"`, logContext);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}, {
|
|
35
|
+
operation,
|
|
36
|
+
context: logContext,
|
|
37
|
+
input: { text, refDate },
|
|
38
|
+
errorCode: BaseErrorCode.PARSING_ERROR,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Parses a natural language date string and returns detailed parsing results.
|
|
43
|
+
* Provides more information than just the Date object, including matched text and components.
|
|
44
|
+
*
|
|
45
|
+
* @param text - The natural language date string to parse.
|
|
46
|
+
* @param context - The request context for logging and error tracking.
|
|
47
|
+
* @param refDate - Optional reference date for parsing relative dates. Defaults to current date/time.
|
|
48
|
+
* @returns A promise resolving with an array of `chrono.ParsedResult` objects. Empty if no dates found.
|
|
49
|
+
* @throws {McpError} If an unexpected error occurs during parsing.
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
async function parseDateStringDetailed(text, context, refDate) {
|
|
53
|
+
const operation = "parseDateStringDetailed";
|
|
54
|
+
const logContext = { ...context, operation, inputText: text, refDate };
|
|
55
|
+
logger.debug(`Attempting detailed parse of date string: "${text}"`, logContext);
|
|
56
|
+
return await ErrorHandler.tryCatch(async () => {
|
|
57
|
+
const results = chrono.parse(text, refDate, { forwardDate: true });
|
|
58
|
+
logger.debug(`Detailed parse of "${text}" resulted in ${results.length} result(s)`, logContext);
|
|
59
|
+
return results;
|
|
60
|
+
}, {
|
|
61
|
+
operation,
|
|
62
|
+
context: logContext,
|
|
63
|
+
input: { text, refDate },
|
|
64
|
+
errorCode: BaseErrorCode.PARSING_ERROR,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* An object providing date parsing functionalities.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { dateParser, requestContextService } from './utils'; // Assuming utils/index.js exports these
|
|
73
|
+
* const context = requestContextService.createRequestContext({ operation: 'TestDateParsing' });
|
|
74
|
+
*
|
|
75
|
+
* async function testParsing() {
|
|
76
|
+
* const dateObj = await dateParser.parseDate("next Friday at 3pm", context);
|
|
77
|
+
* if (dateObj) {
|
|
78
|
+
* console.log("Parsed Date:", dateObj.toISOString());
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* const detailedResults = await dateParser.parse("Meeting on 2024-12-25 and another one tomorrow", context);
|
|
82
|
+
* detailedResults.forEach(result => {
|
|
83
|
+
* console.log("Detailed Result:", result.text, result.start.date());
|
|
84
|
+
* });
|
|
85
|
+
* }
|
|
86
|
+
* testParsing();
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export const dateParser = {
|
|
90
|
+
/**
|
|
91
|
+
* Parses a natural language date string and returns detailed parsing results
|
|
92
|
+
* from `chrono-node`.
|
|
93
|
+
* @param text - The natural language date string to parse.
|
|
94
|
+
* @param context - The request context for logging and error tracking.
|
|
95
|
+
* @param refDate - Optional reference date for parsing relative dates.
|
|
96
|
+
* @returns A promise resolving with an array of `chrono.ParsedResult` objects.
|
|
97
|
+
*/
|
|
98
|
+
parse: parseDateStringDetailed,
|
|
99
|
+
/**
|
|
100
|
+
* Parses a natural language date string into a single JavaScript Date object.
|
|
101
|
+
* @param text - The natural language date string to parse.
|
|
102
|
+
* @param context - The request context for logging and error tracking.
|
|
103
|
+
* @param refDate - Optional reference date for parsing relative dates.
|
|
104
|
+
* @returns A promise resolving with a Date object or `null`.
|
|
105
|
+
*/
|
|
106
|
+
parseDate: parseDateString,
|
|
107
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Barrel file for parsing utility modules.
|
|
3
|
+
* This file re-exports utilities related to parsing various data formats,
|
|
4
|
+
* such as JSON and dates.
|
|
5
|
+
* @module src/utils/parsing
|
|
6
|
+
*/
|
|
7
|
+
export * from "./dateParser.js";
|
|
8
|
+
export * from "./jsonParser.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Barrel file for parsing utility modules.
|
|
3
|
+
* This file re-exports utilities related to parsing various data formats,
|
|
4
|
+
* such as JSON and dates.
|
|
5
|
+
* @module src/utils/parsing
|
|
6
|
+
*/
|
|
7
|
+
export * from "./dateParser.js";
|
|
8
|
+
export * from "./jsonParser.js";
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { RequestContext } from "../index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Enum mirroring `partial-json`'s `Allow` constants. These specify
|
|
4
|
+
* what types of partial JSON structures are permissible during parsing.
|
|
5
|
+
* They can be combined using bitwise OR (e.g., `Allow.STR | Allow.OBJ`).
|
|
6
|
+
*
|
|
7
|
+
* The available properties are:
|
|
8
|
+
* - `STR`: Allow partial string.
|
|
9
|
+
* - `NUM`: Allow partial number.
|
|
10
|
+
* - `ARR`: Allow partial array.
|
|
11
|
+
* - `OBJ`: Allow partial object.
|
|
12
|
+
* - `NULL`: Allow partial null.
|
|
13
|
+
* - `BOOL`: Allow partial boolean.
|
|
14
|
+
* - `NAN`: Allow partial NaN. (Note: Standard JSON does not support NaN)
|
|
15
|
+
* - `INFINITY`: Allow partial Infinity. (Note: Standard JSON does not support Infinity)
|
|
16
|
+
* - `_INFINITY`: Allow partial -Infinity. (Note: Standard JSON does not support -Infinity)
|
|
17
|
+
* - `INF`: Allow both partial Infinity and -Infinity.
|
|
18
|
+
* - `SPECIAL`: Allow all special values (NaN, Infinity, -Infinity).
|
|
19
|
+
* - `ATOM`: Allow all atomic values (strings, numbers, booleans, null, special values).
|
|
20
|
+
* - `COLLECTION`: Allow all collection values (objects, arrays).
|
|
21
|
+
* - `ALL`: Allow all value types to be partial (default for `partial-json`'s parse).
|
|
22
|
+
* @see {@link https://github.com/promplate/partial-json-parser-js} for more details.
|
|
23
|
+
*/
|
|
24
|
+
export declare const Allow: {
|
|
25
|
+
STR: number;
|
|
26
|
+
NUM: number;
|
|
27
|
+
ARR: number;
|
|
28
|
+
OBJ: number;
|
|
29
|
+
NULL: number;
|
|
30
|
+
BOOL: number;
|
|
31
|
+
NAN: number;
|
|
32
|
+
INFINITY: number;
|
|
33
|
+
_INFINITY: number;
|
|
34
|
+
INF: number;
|
|
35
|
+
SPECIAL: number;
|
|
36
|
+
ATOM: number;
|
|
37
|
+
COLLECTION: number;
|
|
38
|
+
ALL: number;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Utility class for parsing potentially partial JSON strings.
|
|
42
|
+
* Wraps the 'partial-json' library for robust JSON parsing, handling
|
|
43
|
+
* incomplete structures and optional <think> blocks from LLMs.
|
|
44
|
+
*/
|
|
45
|
+
export declare class JsonParser {
|
|
46
|
+
/**
|
|
47
|
+
* Parses a JSON string, which may be partial or prefixed with a <think> block.
|
|
48
|
+
* If a <think> block is present, its content is logged, and parsing proceeds on the
|
|
49
|
+
* remainder. Uses 'partial-json' to handle incomplete JSON.
|
|
50
|
+
*
|
|
51
|
+
* @template T The expected type of the parsed JSON object. Defaults to `any`.
|
|
52
|
+
* @param jsonString - The JSON string to parse.
|
|
53
|
+
* @param allowPartial - Bitwise OR combination of `Allow` constants specifying permissible
|
|
54
|
+
* partial JSON types. Defaults to `Allow.ALL`.
|
|
55
|
+
* @param context - Optional `RequestContext` for logging and error correlation.
|
|
56
|
+
* @returns The parsed JavaScript value.
|
|
57
|
+
* @throws {McpError} If the string is empty after processing or if `partial-json` fails.
|
|
58
|
+
*/
|
|
59
|
+
parse<T = any>(jsonString: string, allowPartial?: number, context?: RequestContext): T;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Singleton instance of the `JsonParser`.
|
|
63
|
+
* Use this instance to parse JSON strings, with support for partial JSON and <think> blocks.
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* import { jsonParser, Allow, requestContextService } from './utils';
|
|
67
|
+
* const context = requestContextService.createRequestContext({ operation: 'TestJsonParsing' });
|
|
68
|
+
*
|
|
69
|
+
* const fullJson = '{"key": "value"}';
|
|
70
|
+
* const parsedFull = jsonParser.parse(fullJson, Allow.ALL, context);
|
|
71
|
+
* console.log(parsedFull); // Output: { key: 'value' }
|
|
72
|
+
*
|
|
73
|
+
* const partialObject = '<think>This is a thought.</think>{"key": "value", "arr": [1,';
|
|
74
|
+
* try {
|
|
75
|
+
* const parsedPartial = jsonParser.parse(partialObject, undefined, context);
|
|
76
|
+
* console.log(parsedPartial);
|
|
77
|
+
* } catch (e) {
|
|
78
|
+
* console.error("Parsing partial object failed:", e);
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare const jsonParser: JsonParser;
|