@cyanheads/pubmed-mcp-server 1.0.12

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 (121) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +174 -0
  3. package/dist/config/index.d.ts +91 -0
  4. package/dist/config/index.js +324 -0
  5. package/dist/index.d.ts +24 -0
  6. package/dist/index.js +190 -0
  7. package/dist/mcp-server/resources/echoResource/echoResourceLogic.d.ts +79 -0
  8. package/dist/mcp-server/resources/echoResource/echoResourceLogic.js +82 -0
  9. package/dist/mcp-server/resources/echoResource/index.d.ts +13 -0
  10. package/dist/mcp-server/resources/echoResource/index.js +13 -0
  11. package/dist/mcp-server/resources/echoResource/registration.d.ts +30 -0
  12. package/dist/mcp-server/resources/echoResource/registration.js +168 -0
  13. package/dist/mcp-server/server.d.ts +28 -0
  14. package/dist/mcp-server/server.js +159 -0
  15. package/dist/mcp-server/tools/fetchPubMedContent/index.d.ts +6 -0
  16. package/dist/mcp-server/tools/fetchPubMedContent/index.js +6 -0
  17. package/dist/mcp-server/tools/fetchPubMedContent/logic.d.ts +63 -0
  18. package/dist/mcp-server/tools/fetchPubMedContent/logic.js +518 -0
  19. package/dist/mcp-server/tools/fetchPubMedContent/registration.d.ts +10 -0
  20. package/dist/mcp-server/tools/fetchPubMedContent/registration.js +37 -0
  21. package/dist/mcp-server/tools/getPubMedArticleConnections/index.d.ts +6 -0
  22. package/dist/mcp-server/tools/getPubMedArticleConnections/index.js +6 -0
  23. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/citationFormatter.d.ts +9 -0
  24. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/citationFormatter.js +288 -0
  25. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/elinkHandler.d.ts +9 -0
  26. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/elinkHandler.js +208 -0
  27. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/index.d.ts +15 -0
  28. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/index.js +82 -0
  29. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/types.d.ts +27 -0
  30. package/dist/mcp-server/tools/getPubMedArticleConnections/logic/types.js +5 -0
  31. package/dist/mcp-server/tools/getPubMedArticleConnections/logic.d.ts +6 -0
  32. package/dist/mcp-server/tools/getPubMedArticleConnections/logic.js +6 -0
  33. package/dist/mcp-server/tools/getPubMedArticleConnections/registration.d.ts +36 -0
  34. package/dist/mcp-server/tools/getPubMedArticleConnections/registration.js +76 -0
  35. package/dist/mcp-server/tools/pubmedResearchAgent/index.d.ts +6 -0
  36. package/dist/mcp-server/tools/pubmedResearchAgent/index.js +6 -0
  37. package/dist/mcp-server/tools/pubmedResearchAgent/logic/index.d.ts +7 -0
  38. package/dist/mcp-server/tools/pubmedResearchAgent/logic/index.js +9 -0
  39. package/dist/mcp-server/tools/pubmedResearchAgent/logic/inputSchema.d.ts +111 -0
  40. package/dist/mcp-server/tools/pubmedResearchAgent/logic/inputSchema.js +149 -0
  41. package/dist/mcp-server/tools/pubmedResearchAgent/logic/outputTypes.d.ts +106 -0
  42. package/dist/mcp-server/tools/pubmedResearchAgent/logic/outputTypes.js +7 -0
  43. package/dist/mcp-server/tools/pubmedResearchAgent/logic/planOrchestrator.d.ts +10 -0
  44. package/dist/mcp-server/tools/pubmedResearchAgent/logic/planOrchestrator.js +251 -0
  45. package/dist/mcp-server/tools/pubmedResearchAgent/logic.d.ts +12 -0
  46. package/dist/mcp-server/tools/pubmedResearchAgent/logic.js +55 -0
  47. package/dist/mcp-server/tools/pubmedResearchAgent/registration.d.ts +10 -0
  48. package/dist/mcp-server/tools/pubmedResearchAgent/registration.js +36 -0
  49. package/dist/mcp-server/tools/searchPubMedArticles/index.d.ts +6 -0
  50. package/dist/mcp-server/tools/searchPubMedArticles/index.js +6 -0
  51. package/dist/mcp-server/tools/searchPubMedArticles/logic.d.ts +61 -0
  52. package/dist/mcp-server/tools/searchPubMedArticles/logic.js +229 -0
  53. package/dist/mcp-server/tools/searchPubMedArticles/registration.d.ts +10 -0
  54. package/dist/mcp-server/tools/searchPubMedArticles/registration.js +38 -0
  55. package/dist/mcp-server/transports/authentication/authMiddleware.d.ts +29 -0
  56. package/dist/mcp-server/transports/authentication/authMiddleware.js +174 -0
  57. package/dist/mcp-server/transports/httpTransport.d.ts +23 -0
  58. package/dist/mcp-server/transports/httpTransport.js +463 -0
  59. package/dist/mcp-server/transports/stdioTransport.d.ts +42 -0
  60. package/dist/mcp-server/transports/stdioTransport.js +63 -0
  61. package/dist/services/NCBI/ncbiConstants.d.ts +22 -0
  62. package/dist/services/NCBI/ncbiConstants.js +5 -0
  63. package/dist/services/NCBI/ncbiCoreApiClient.d.ts +24 -0
  64. package/dist/services/NCBI/ncbiCoreApiClient.js +118 -0
  65. package/dist/services/NCBI/ncbiRequestQueueManager.d.ts +36 -0
  66. package/dist/services/NCBI/ncbiRequestQueueManager.js +96 -0
  67. package/dist/services/NCBI/ncbiResponseHandler.d.ts +22 -0
  68. package/dist/services/NCBI/ncbiResponseHandler.js +192 -0
  69. package/dist/services/NCBI/ncbiService.d.ts +24 -0
  70. package/dist/services/NCBI/ncbiService.js +57 -0
  71. package/dist/services/index.d.ts +7 -0
  72. package/dist/services/index.js +7 -0
  73. package/dist/services/llm-providers/index.d.ts +7 -0
  74. package/dist/services/llm-providers/index.js +7 -0
  75. package/dist/services/llm-providers/llmFactory.d.ts +69 -0
  76. package/dist/services/llm-providers/llmFactory.js +132 -0
  77. package/dist/services/llm-providers/openRouter/index.d.ts +6 -0
  78. package/dist/services/llm-providers/openRouter/index.js +7 -0
  79. package/dist/services/llm-providers/openRouter/openRouterProvider.d.ts +99 -0
  80. package/dist/services/llm-providers/openRouter/openRouterProvider.js +329 -0
  81. package/dist/types-global/errors.d.ts +119 -0
  82. package/dist/types-global/errors.js +119 -0
  83. package/dist/types-global/pubmedXml.d.ts +350 -0
  84. package/dist/types-global/pubmedXml.js +7 -0
  85. package/dist/utils/index.d.ts +10 -0
  86. package/dist/utils/index.js +18 -0
  87. package/dist/utils/internal/errorHandler.d.ts +176 -0
  88. package/dist/utils/internal/errorHandler.js +335 -0
  89. package/dist/utils/internal/index.d.ts +9 -0
  90. package/dist/utils/internal/index.js +9 -0
  91. package/dist/utils/internal/logger.d.ts +141 -0
  92. package/dist/utils/internal/logger.js +426 -0
  93. package/dist/utils/internal/requestContext.d.ts +83 -0
  94. package/dist/utils/internal/requestContext.js +72 -0
  95. package/dist/utils/metrics/index.d.ts +7 -0
  96. package/dist/utils/metrics/index.js +7 -0
  97. package/dist/utils/metrics/tokenCounter.d.ts +35 -0
  98. package/dist/utils/metrics/tokenCounter.js +110 -0
  99. package/dist/utils/parsing/dateParser.d.ts +73 -0
  100. package/dist/utils/parsing/dateParser.js +107 -0
  101. package/dist/utils/parsing/index.d.ts +8 -0
  102. package/dist/utils/parsing/index.js +8 -0
  103. package/dist/utils/parsing/jsonParser.d.ts +82 -0
  104. package/dist/utils/parsing/jsonParser.js +126 -0
  105. package/dist/utils/parsing/ncbi-parsing/eSummaryResultParser.d.ts +32 -0
  106. package/dist/utils/parsing/ncbi-parsing/eSummaryResultParser.js +295 -0
  107. package/dist/utils/parsing/ncbi-parsing/index.d.ts +8 -0
  108. package/dist/utils/parsing/ncbi-parsing/index.js +8 -0
  109. package/dist/utils/parsing/ncbi-parsing/pubmedArticleStructureParser.d.ts +70 -0
  110. package/dist/utils/parsing/ncbi-parsing/pubmedArticleStructureParser.js +229 -0
  111. package/dist/utils/parsing/ncbi-parsing/xmlGenericHelpers.d.ts +31 -0
  112. package/dist/utils/parsing/ncbi-parsing/xmlGenericHelpers.js +76 -0
  113. package/dist/utils/security/idGenerator.d.ts +134 -0
  114. package/dist/utils/security/idGenerator.js +198 -0
  115. package/dist/utils/security/index.d.ts +9 -0
  116. package/dist/utils/security/index.js +9 -0
  117. package/dist/utils/security/rateLimiter.d.ts +108 -0
  118. package/dist/utils/security/rateLimiter.js +179 -0
  119. package/dist/utils/security/sanitization.d.ts +173 -0
  120. package/dist/utils/security/sanitization.js +439 -0
  121. package/package.json +97 -0
@@ -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,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;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @fileoverview Provides a utility class for parsing potentially partial JSON strings.
3
+ * It wraps the 'partial-json' npm library and includes functionality to handle
4
+ * optional <think>...</think> blocks often found at the beginning of LLM outputs.
5
+ * @module src/utils/parsing/jsonParser
6
+ */
7
+ import { parse as parsePartialJson, Allow as PartialJsonAllow, } from "partial-json";
8
+ import { BaseErrorCode, McpError } from "../../types-global/errors.js";
9
+ import { logger, requestContextService } from "../index.js";
10
+ /**
11
+ * Enum mirroring `partial-json`'s `Allow` constants. These specify
12
+ * what types of partial JSON structures are permissible during parsing.
13
+ * They can be combined using bitwise OR (e.g., `Allow.STR | Allow.OBJ`).
14
+ *
15
+ * The available properties are:
16
+ * - `STR`: Allow partial string.
17
+ * - `NUM`: Allow partial number.
18
+ * - `ARR`: Allow partial array.
19
+ * - `OBJ`: Allow partial object.
20
+ * - `NULL`: Allow partial null.
21
+ * - `BOOL`: Allow partial boolean.
22
+ * - `NAN`: Allow partial NaN. (Note: Standard JSON does not support NaN)
23
+ * - `INFINITY`: Allow partial Infinity. (Note: Standard JSON does not support Infinity)
24
+ * - `_INFINITY`: Allow partial -Infinity. (Note: Standard JSON does not support -Infinity)
25
+ * - `INF`: Allow both partial Infinity and -Infinity.
26
+ * - `SPECIAL`: Allow all special values (NaN, Infinity, -Infinity).
27
+ * - `ATOM`: Allow all atomic values (strings, numbers, booleans, null, special values).
28
+ * - `COLLECTION`: Allow all collection values (objects, arrays).
29
+ * - `ALL`: Allow all value types to be partial (default for `partial-json`'s parse).
30
+ * @see {@link https://github.com/promplate/partial-json-parser-js} for more details.
31
+ */
32
+ export const Allow = PartialJsonAllow;
33
+ /**
34
+ * Regular expression to find a <think> block at the start of a string.
35
+ * Captures content within <think>...</think> (Group 1) and the rest of the string (Group 2).
36
+ * @private
37
+ */
38
+ const thinkBlockRegex = /^<think>([\s\S]*?)<\/think>\s*([\s\S]*)$/;
39
+ /**
40
+ * Utility class for parsing potentially partial JSON strings.
41
+ * Wraps the 'partial-json' library for robust JSON parsing, handling
42
+ * incomplete structures and optional <think> blocks from LLMs.
43
+ */
44
+ export class JsonParser {
45
+ /**
46
+ * Parses a JSON string, which may be partial or prefixed with a <think> block.
47
+ * If a <think> block is present, its content is logged, and parsing proceeds on the
48
+ * remainder. Uses 'partial-json' to handle incomplete JSON.
49
+ *
50
+ * @template T The expected type of the parsed JSON object. Defaults to `any`.
51
+ * @param jsonString - The JSON string to parse.
52
+ * @param allowPartial - Bitwise OR combination of `Allow` constants specifying permissible
53
+ * partial JSON types. Defaults to `Allow.ALL`.
54
+ * @param context - Optional `RequestContext` for logging and error correlation.
55
+ * @returns The parsed JavaScript value.
56
+ * @throws {McpError} If the string is empty after processing or if `partial-json` fails.
57
+ */
58
+ parse(jsonString, allowPartial = Allow.ALL, context) {
59
+ let stringToParse = jsonString;
60
+ const match = jsonString.match(thinkBlockRegex);
61
+ if (match) {
62
+ const thinkContent = match[1].trim();
63
+ const restOfString = match[2];
64
+ const logContext = context ||
65
+ requestContextService.createRequestContext({
66
+ operation: "JsonParser.thinkBlock",
67
+ });
68
+ if (thinkContent) {
69
+ logger.debug("LLM <think> block detected and logged.", {
70
+ ...logContext,
71
+ thinkContent,
72
+ });
73
+ }
74
+ else {
75
+ logger.debug("Empty LLM <think> block detected.", logContext);
76
+ }
77
+ stringToParse = restOfString;
78
+ }
79
+ stringToParse = stringToParse.trim();
80
+ if (!stringToParse) {
81
+ throw new McpError(BaseErrorCode.VALIDATION_ERROR, "JSON string is empty after removing <think> block and trimming.", context);
82
+ }
83
+ try {
84
+ return parsePartialJson(stringToParse, allowPartial);
85
+ }
86
+ catch (error) {
87
+ const errorLogContext = context ||
88
+ requestContextService.createRequestContext({
89
+ operation: "JsonParser.parseError",
90
+ });
91
+ logger.error("Failed to parse JSON content.", {
92
+ ...errorLogContext,
93
+ errorDetails: error.message,
94
+ contentAttempted: stringToParse.substring(0, 200),
95
+ });
96
+ throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Failed to parse JSON: ${error.message}`, {
97
+ ...context,
98
+ originalContentSample: stringToParse.substring(0, 200) +
99
+ (stringToParse.length > 200 ? "..." : ""),
100
+ rawError: error instanceof Error ? error.stack : String(error),
101
+ });
102
+ }
103
+ }
104
+ }
105
+ /**
106
+ * Singleton instance of the `JsonParser`.
107
+ * Use this instance to parse JSON strings, with support for partial JSON and <think> blocks.
108
+ * @example
109
+ * ```typescript
110
+ * import { jsonParser, Allow, requestContextService } from './utils';
111
+ * const context = requestContextService.createRequestContext({ operation: 'TestJsonParsing' });
112
+ *
113
+ * const fullJson = '{"key": "value"}';
114
+ * const parsedFull = jsonParser.parse(fullJson, Allow.ALL, context);
115
+ * console.log(parsedFull); // Output: { key: 'value' }
116
+ *
117
+ * const partialObject = '<think>This is a thought.</think>{"key": "value", "arr": [1,';
118
+ * try {
119
+ * const parsedPartial = jsonParser.parse(partialObject, undefined, context);
120
+ * console.log(parsedPartial);
121
+ * } catch (e) {
122
+ * console.error("Parsing partial object failed:", e);
123
+ * }
124
+ * ```
125
+ */
126
+ export const jsonParser = new JsonParser();
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview Helper functions for parsing ESummary results from NCBI.
3
+ * Handles different ESummary XML structures and formats the data into
4
+ * consistent ParsedBriefSummary objects.
5
+ * @module src/utils/parsing/ncbi-parsing/eSummaryResultParser
6
+ */
7
+ import { ESummaryResult, ParsedBriefSummary, ESummaryAuthor as XmlESummaryAuthor } from "../../../types-global/pubmedXml.js";
8
+ import { RequestContext } from "../../../utils/index.js";
9
+ /**
10
+ * Formats an array of ESummary authors into a string.
11
+ * Limits to the first 3 authors and adds "et al." if more exist.
12
+ * @param authors - Array of ESummary author objects (normalized).
13
+ * @returns A string like "Doe J, Smith A, Brown B, et al." or empty if no authors.
14
+ */
15
+ export declare function formatESummaryAuthors(authors?: XmlESummaryAuthor[]): string;
16
+ /**
17
+ * Standardizes date strings from ESummary to "YYYY-MM-DD" format.
18
+ * Uses the dateParser utility.
19
+ * @param dateStr - Date string from ESummary (e.g., "2023/01/15", "2023 Jan 15", "2023").
20
+ * @param parentContext - Optional parent request context for logging.
21
+ * @returns A promise resolving to a standardized date string ("YYYY-MM-DD") or undefined if parsing fails.
22
+ */
23
+ export declare function standardizeESummaryDate(dateStr?: string, parentContext?: RequestContext): Promise<string | undefined>;
24
+ /**
25
+ * Extracts and formats brief summaries from ESummary XML result.
26
+ * Handles both DocumentSummarySet (newer) and older DocSum structures.
27
+ * Asynchronously standardizes dates.
28
+ * @param eSummaryResult - The parsed XML object from ESummary (eSummaryResult part).
29
+ * @param context - Request context for logging and passing to date standardization.
30
+ * @returns A promise resolving to an array of parsed brief summary objects.
31
+ */
32
+ export declare function extractBriefSummaries(eSummaryResult?: ESummaryResult, context?: RequestContext): Promise<ParsedBriefSummary[]>;