@cyanheads/pubmed-mcp-server 1.2.3 → 1.3.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/README.md +2 -2
- package/dist/config/index.d.ts +13 -52
- package/dist/config/index.js +51 -222
- package/dist/mcp-server/server.d.ts +0 -5
- package/dist/mcp-server/server.js +18 -34
- package/dist/mcp-server/tools/fetchPubMedContent/logic.d.ts +8 -8
- package/dist/mcp-server/tools/fetchPubMedContent/logic.js +6 -5
- package/dist/mcp-server/tools/generatePubMedChart/logic.js +19 -19
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/citationFormatter.js +65 -240
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/elinkHandler.js +3 -3
- package/dist/mcp-server/tools/searchPubMedArticles/logic.js +10 -11
- package/dist/mcp-server/transports/auth/authFactory.d.ts +10 -0
- package/dist/mcp-server/transports/auth/authFactory.js +41 -0
- package/dist/mcp-server/transports/auth/authMiddleware.d.ts +19 -0
- package/dist/mcp-server/transports/auth/authMiddleware.js +57 -0
- package/dist/mcp-server/transports/auth/index.d.ts +8 -5
- package/dist/mcp-server/transports/auth/index.js +6 -4
- package/dist/mcp-server/transports/auth/{core → lib}/authTypes.d.ts +0 -5
- package/dist/mcp-server/transports/auth/lib/authTypes.js +8 -0
- package/dist/mcp-server/transports/auth/{core → lib}/authUtils.js +21 -14
- package/dist/mcp-server/transports/auth/strategies/authStrategy.d.ts +17 -0
- package/dist/mcp-server/transports/auth/strategies/authStrategy.js +1 -0
- package/dist/mcp-server/transports/auth/strategies/jwtStrategy.d.ts +7 -0
- package/dist/mcp-server/transports/auth/strategies/jwtStrategy.js +112 -0
- package/dist/mcp-server/transports/auth/strategies/oauthStrategy.d.ts +7 -0
- package/dist/mcp-server/transports/auth/strategies/oauthStrategy.js +101 -0
- package/dist/mcp-server/transports/core/baseTransportManager.d.ts +17 -0
- package/dist/mcp-server/transports/core/baseTransportManager.js +18 -0
- package/dist/mcp-server/transports/core/honoNodeBridge.d.ts +23 -0
- package/dist/mcp-server/transports/core/honoNodeBridge.js +51 -0
- package/dist/mcp-server/transports/core/statefulTransportManager.d.ts +31 -0
- package/dist/mcp-server/transports/core/statefulTransportManager.js +233 -0
- package/dist/mcp-server/transports/core/statelessTransportManager.d.ts +20 -0
- package/dist/mcp-server/transports/core/statelessTransportManager.js +92 -0
- package/dist/mcp-server/transports/core/transportTypes.d.ts +68 -0
- package/dist/mcp-server/transports/core/transportTypes.js +5 -0
- package/dist/mcp-server/transports/{httpErrorHandler.d.ts → http/httpErrorHandler.d.ts} +4 -9
- package/dist/mcp-server/transports/{httpErrorHandler.js → http/httpErrorHandler.js} +33 -8
- package/dist/mcp-server/transports/http/httpTransport.d.ts +22 -0
- package/dist/mcp-server/transports/http/httpTransport.js +251 -0
- package/dist/mcp-server/transports/http/httpTypes.d.ts +16 -0
- package/dist/mcp-server/transports/http/httpTypes.js +5 -0
- package/dist/mcp-server/transports/http/index.d.ts +7 -0
- package/dist/mcp-server/transports/http/index.js +6 -0
- package/dist/mcp-server/transports/http/mcpTransportMiddleware.d.ts +25 -0
- package/dist/mcp-server/transports/http/mcpTransportMiddleware.js +63 -0
- package/dist/mcp-server/transports/stdio/index.d.ts +5 -0
- package/dist/mcp-server/transports/stdio/index.js +5 -0
- package/dist/mcp-server/transports/{stdioTransport.d.ts → stdio/stdioTransport.d.ts} +2 -2
- package/dist/mcp-server/transports/{stdioTransport.js → stdio/stdioTransport.js} +10 -5
- package/dist/services/NCBI/{ncbiConstants.d.ts → core/ncbiConstants.d.ts} +1 -1
- package/dist/services/NCBI/{ncbiConstants.js → core/ncbiConstants.js} +1 -1
- package/dist/services/NCBI/{ncbiCoreApiClient.d.ts → core/ncbiCoreApiClient.d.ts} +3 -3
- package/dist/services/NCBI/core/ncbiCoreApiClient.js +117 -0
- package/dist/services/NCBI/{ncbiRequestQueueManager.d.ts → core/ncbiRequestQueueManager.d.ts} +2 -2
- package/dist/services/NCBI/{ncbiRequestQueueManager.js → core/ncbiRequestQueueManager.js} +3 -3
- package/dist/services/NCBI/{ncbiResponseHandler.d.ts → core/ncbiResponseHandler.d.ts} +2 -2
- package/dist/services/NCBI/{ncbiResponseHandler.js → core/ncbiResponseHandler.js} +3 -3
- package/dist/services/NCBI/{ncbiService.d.ts → core/ncbiService.d.ts} +5 -4
- package/dist/services/NCBI/{ncbiService.js → core/ncbiService.js} +15 -3
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/eSummaryResultParser.d.ts +1 -1
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/eSummaryResultParser.js +1 -1
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/index.d.ts +1 -1
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/index.js +1 -1
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/pubmedArticleStructureParser.d.ts +1 -1
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/pubmedArticleStructureParser.js +5 -1
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/xmlGenericHelpers.d.ts +1 -1
- package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/xmlGenericHelpers.js +1 -1
- package/dist/types-global/errors.d.ts +2 -0
- package/dist/types-global/errors.js +2 -0
- package/dist/types-global/pubmedXml.d.ts +15 -0
- package/dist/utils/internal/errorHandler.js +1 -1
- package/dist/utils/internal/logger.d.ts +13 -1
- package/dist/utils/internal/logger.js +43 -9
- 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/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 +150 -0
- package/dist/utils/security/sanitization.js +35 -18
- package/package.json +17 -13
- package/dist/mcp-server/transports/auth/core/authTypes.js +0 -5
- package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.d.ts +0 -27
- package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.js +0 -149
- package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.d.ts +0 -20
- package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.js +0 -124
- package/dist/mcp-server/transports/httpTransport.d.ts +0 -21
- package/dist/mcp-server/transports/httpTransport.js +0 -208
- package/dist/services/NCBI/ncbiCoreApiClient.js +0 -113
- /package/dist/mcp-server/transports/auth/{core → lib}/authContext.d.ts +0 -0
- /package/dist/mcp-server/transports/auth/{core → lib}/authContext.js +0 -0
- /package/dist/mcp-server/transports/auth/{core → lib}/authUtils.d.ts +0 -0
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* retries, and parsing of XML/JSON responses. It aims to provide a robust
|
|
6
6
|
* and compliant interface for other parts of the pubmed-mcp-server to
|
|
7
7
|
* access PubMed data.
|
|
8
|
-
* @module src/services/NCBI/ncbiService
|
|
8
|
+
* @module src/services/NCBI/core/ncbiService
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { ESearchResult, EFetchArticleSet } from "../../../types-global/pubmedXml.js";
|
|
11
|
+
import { RequestContext } from "../../../utils/index.js";
|
|
11
12
|
import { NcbiRequestParams, NcbiRequestOptions } from "./ncbiConstants.js";
|
|
12
13
|
export declare class NcbiService {
|
|
13
14
|
private queueManager;
|
|
@@ -15,9 +16,9 @@ export declare class NcbiService {
|
|
|
15
16
|
private responseHandler;
|
|
16
17
|
constructor();
|
|
17
18
|
private performNcbiRequest;
|
|
18
|
-
eSearch(params: NcbiRequestParams, context: RequestContext): Promise<
|
|
19
|
+
eSearch(params: NcbiRequestParams, context: RequestContext): Promise<ESearchResult>;
|
|
19
20
|
eSummary(params: NcbiRequestParams, context: RequestContext): Promise<any>;
|
|
20
|
-
eFetch(params: NcbiRequestParams, context: RequestContext, options?: NcbiRequestOptions): Promise<
|
|
21
|
+
eFetch(params: NcbiRequestParams, context: RequestContext, options?: NcbiRequestOptions): Promise<EFetchArticleSet>;
|
|
21
22
|
eLink(params: NcbiRequestParams, context: RequestContext): Promise<any>;
|
|
22
23
|
eInfo(params: NcbiRequestParams, context: RequestContext): Promise<any>;
|
|
23
24
|
}
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* retries, and parsing of XML/JSON responses. It aims to provide a robust
|
|
6
6
|
* and compliant interface for other parts of the pubmed-mcp-server to
|
|
7
7
|
* access PubMed data.
|
|
8
|
-
* @module src/services/NCBI/ncbiService
|
|
8
|
+
* @module src/services/NCBI/core/ncbiService
|
|
9
9
|
*/
|
|
10
|
-
import { logger, requestContextService, } from "
|
|
10
|
+
import { logger, requestContextService, } from "../../../utils/index.js";
|
|
11
11
|
import { NcbiCoreApiClient } from "./ncbiCoreApiClient.js";
|
|
12
12
|
import { NcbiRequestQueueManager } from "./ncbiRequestQueueManager.js";
|
|
13
13
|
import { NcbiResponseHandler } from "./ncbiResponseHandler.js";
|
|
@@ -25,9 +25,21 @@ export class NcbiService {
|
|
|
25
25
|
return this.queueManager.enqueueRequest(task, context, endpoint, params);
|
|
26
26
|
}
|
|
27
27
|
async eSearch(params, context) {
|
|
28
|
-
|
|
28
|
+
const response = await this.performNcbiRequest("esearch", params, context, {
|
|
29
29
|
retmode: "xml",
|
|
30
30
|
});
|
|
31
|
+
const esResult = response.eSearchResult;
|
|
32
|
+
return {
|
|
33
|
+
count: parseInt(esResult.Count, 10) || 0,
|
|
34
|
+
retmax: parseInt(esResult.RetMax, 10) || 0,
|
|
35
|
+
retstart: parseInt(esResult.RetStart, 10) || 0,
|
|
36
|
+
queryKey: esResult.QueryKey,
|
|
37
|
+
webEnv: esResult.WebEnv,
|
|
38
|
+
idList: esResult.IdList?.Id || [],
|
|
39
|
+
queryTranslation: esResult.QueryTranslation,
|
|
40
|
+
errorList: esResult.ErrorList,
|
|
41
|
+
warningList: esResult.WarningList,
|
|
42
|
+
};
|
|
31
43
|
}
|
|
32
44
|
async eSummary(params, context) {
|
|
33
45
|
// Determine retmode based on params, default to xml
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Helper functions for parsing ESummary results from NCBI.
|
|
3
3
|
* Handles different ESummary XML structures and formats the data into
|
|
4
4
|
* consistent ParsedBriefSummary objects.
|
|
5
|
-
* @module src/
|
|
5
|
+
* @module src/services/NCBI/parsing/eSummaryResultParser
|
|
6
6
|
*/
|
|
7
7
|
import { ESummaryResult, ParsedBriefSummary, ESummaryAuthor as XmlESummaryAuthor } from "../../../types-global/pubmedXml.js";
|
|
8
8
|
import { RequestContext } from "../../../utils/index.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Helper functions for parsing ESummary results from NCBI.
|
|
3
3
|
* Handles different ESummary XML structures and formats the data into
|
|
4
4
|
* consistent ParsedBriefSummary objects.
|
|
5
|
-
* @module src/
|
|
5
|
+
* @module src/services/NCBI/parsing/eSummaryResultParser
|
|
6
6
|
*/
|
|
7
7
|
import { dateParser, logger, requestContextService, } from "../../../utils/index.js"; // Note: utils/index.js is the barrel file
|
|
8
8
|
import { ensureArray, getAttribute, getText } from "./xmlGenericHelpers.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Barrel file for NCBI XML parsing helper utilities.
|
|
3
3
|
* Re-exports functions from more specific parser modules.
|
|
4
|
-
* @module src/
|
|
4
|
+
* @module src/services/NCBI/parsing/index
|
|
5
5
|
*/
|
|
6
6
|
export * from "./xmlGenericHelpers.js";
|
|
7
7
|
export * from "./pubmedArticleStructureParser.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Barrel file for NCBI XML parsing helper utilities.
|
|
3
3
|
* Re-exports functions from more specific parser modules.
|
|
4
|
-
* @module src/
|
|
4
|
+
* @module src/services/NCBI/parsing/index
|
|
5
5
|
*/
|
|
6
6
|
export * from "./xmlGenericHelpers.js";
|
|
7
7
|
export * from "./pubmedArticleStructureParser.js";
|
package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/pubmedArticleStructureParser.d.ts
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Helper functions for parsing detailed PubMed Article XML structures,
|
|
3
3
|
* typically from EFetch results.
|
|
4
|
-
* @module src/
|
|
4
|
+
* @module src/services/NCBI/parsing/pubmedArticleStructureParser
|
|
5
5
|
*/
|
|
6
6
|
import { XmlArticle, XmlAuthorList, XmlGrantList, XmlJournal, XmlKeywordList, XmlMedlineCitation, XmlMeshHeadingList, XmlPublicationTypeList, ParsedArticleAuthor, ParsedJournalInfo, ParsedMeshTerm, ParsedGrant, ParsedArticleDate } from "../../../types-global/pubmedXml.js";
|
|
7
7
|
/**
|
package/dist/{utils/parsing/ncbi-parsing → services/NCBI/parsing}/pubmedArticleStructureParser.js
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Helper functions for parsing detailed PubMed Article XML structures,
|
|
3
3
|
* typically from EFetch results.
|
|
4
|
-
* @module src/
|
|
4
|
+
* @module src/services/NCBI/parsing/pubmedArticleStructureParser
|
|
5
5
|
*/
|
|
6
6
|
import { ensureArray, getText, getAttribute } from "./xmlGenericHelpers.js";
|
|
7
7
|
/**
|
|
@@ -14,6 +14,10 @@ export function extractAuthors(authorListXml) {
|
|
|
14
14
|
return [];
|
|
15
15
|
const authors = ensureArray(authorListXml.Author);
|
|
16
16
|
return authors.map((auth) => {
|
|
17
|
+
const collectiveName = getText(auth.CollectiveName);
|
|
18
|
+
if (collectiveName) {
|
|
19
|
+
return { collectiveName };
|
|
20
|
+
}
|
|
17
21
|
let affiliation = "";
|
|
18
22
|
const affiliations = ensureArray(auth.AffiliationInfo);
|
|
19
23
|
if (affiliations.length > 0) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Generic helper functions for parsing XML data, particularly
|
|
3
3
|
* structures from fast-xml-parser.
|
|
4
|
-
* @module src/
|
|
4
|
+
* @module src/services/NCBI/parsing/xmlGenericHelpers
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* Ensures that the input is an array. If it's not an array, it wraps it in one.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Generic helper functions for parsing XML data, particularly
|
|
3
3
|
* structures from fast-xml-parser.
|
|
4
|
-
* @module src/
|
|
4
|
+
* @module src/services/NCBI/parsing/xmlGenericHelpers
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* Ensures that the input is an array. If it's not an array, it wraps it in one.
|
|
@@ -23,6 +23,8 @@ export declare enum BaseErrorCode {
|
|
|
23
23
|
CONFLICT = "CONFLICT",
|
|
24
24
|
/** The request failed due to invalid input parameters or data. */
|
|
25
25
|
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
26
|
+
/** The provided input is invalid, but not necessarily a schema validation failure. */
|
|
27
|
+
INVALID_INPUT = "INVALID_INPUT",
|
|
26
28
|
/** An error occurred while parsing input data (e.g., date string, JSON). */
|
|
27
29
|
PARSING_ERROR = "PARSING_ERROR",
|
|
28
30
|
/** The request was rejected because the client has exceeded rate limits. */
|
|
@@ -24,6 +24,8 @@ export var BaseErrorCode;
|
|
|
24
24
|
BaseErrorCode["CONFLICT"] = "CONFLICT";
|
|
25
25
|
/** The request failed due to invalid input parameters or data. */
|
|
26
26
|
BaseErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
27
|
+
/** The provided input is invalid, but not necessarily a schema validation failure. */
|
|
28
|
+
BaseErrorCode["INVALID_INPUT"] = "INVALID_INPUT";
|
|
27
29
|
/** An error occurred while parsing input data (e.g., date string, JSON). */
|
|
28
30
|
BaseErrorCode["PARSING_ERROR"] = "PARSING_ERROR";
|
|
29
31
|
/** The request was rejected because the client has exceeded rate limits. */
|
|
@@ -166,6 +166,7 @@ export interface ParsedArticleAuthor {
|
|
|
166
166
|
firstName?: string;
|
|
167
167
|
initials?: string;
|
|
168
168
|
affiliation?: string;
|
|
169
|
+
collectiveName?: string;
|
|
169
170
|
}
|
|
170
171
|
export interface ParsedArticleDate {
|
|
171
172
|
dateType?: string;
|
|
@@ -348,3 +349,17 @@ export interface ESearchResultContent {
|
|
|
348
349
|
export interface ESearchResponseContainer {
|
|
349
350
|
eSearchResult: ESearchResultContent;
|
|
350
351
|
}
|
|
352
|
+
export interface ESearchResult {
|
|
353
|
+
count: number;
|
|
354
|
+
retmax: number;
|
|
355
|
+
retstart: number;
|
|
356
|
+
queryKey?: string;
|
|
357
|
+
webEnv?: string;
|
|
358
|
+
idList: string[];
|
|
359
|
+
queryTranslation: string;
|
|
360
|
+
errorList?: ESearchErrorList;
|
|
361
|
+
warningList?: ESearchWarningList;
|
|
362
|
+
}
|
|
363
|
+
export interface EFetchArticleSet {
|
|
364
|
+
articles: ParsedArticle[];
|
|
365
|
+
}
|
|
@@ -126,7 +126,7 @@ function getErrorMessage(error) {
|
|
|
126
126
|
try {
|
|
127
127
|
return `Non-Error object encountered: ${JSON.stringify(error)}`;
|
|
128
128
|
}
|
|
129
|
-
catch
|
|
129
|
+
catch {
|
|
130
130
|
return `Unstringifyable non-Error object encountered (constructor: ${error.constructor?.name || "Unknown"})`;
|
|
131
131
|
}
|
|
132
132
|
}
|
|
@@ -17,7 +17,7 @@ export interface McpLogPayload {
|
|
|
17
17
|
message: string;
|
|
18
18
|
stack?: string;
|
|
19
19
|
};
|
|
20
|
-
[key: string]:
|
|
20
|
+
[key: string]: unknown;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Type for the `data` parameter of the `McpNotificationSender` function.
|
|
@@ -38,6 +38,7 @@ export type McpNotificationSender = (level: McpLogLevel, data: McpNotificationDa
|
|
|
38
38
|
export declare class Logger {
|
|
39
39
|
private static instance;
|
|
40
40
|
private winstonLogger?;
|
|
41
|
+
private interactionLogger?;
|
|
41
42
|
private initialized;
|
|
42
43
|
private mcpNotificationSender?;
|
|
43
44
|
private currentMcpLevel;
|
|
@@ -75,6 +76,11 @@ export declare class Logger {
|
|
|
75
76
|
* @returns The singleton Logger instance.
|
|
76
77
|
*/
|
|
77
78
|
static getInstance(): Logger;
|
|
79
|
+
/**
|
|
80
|
+
* Resets the singleton instance.
|
|
81
|
+
* This is intended for use in testing environments only.
|
|
82
|
+
*/
|
|
83
|
+
static resetForTesting(): void;
|
|
78
84
|
/**
|
|
79
85
|
* Ensures the logger has been initialized.
|
|
80
86
|
* @returns True if initialized, false otherwise.
|
|
@@ -133,6 +139,12 @@ export declare class Logger {
|
|
|
133
139
|
* @param context - Optional. RequestContext if `err` is an Error.
|
|
134
140
|
*/
|
|
135
141
|
fatal(msg: string, err?: Error | RequestContext, context?: RequestContext): void;
|
|
142
|
+
/**
|
|
143
|
+
* Logs a structured interaction object to a dedicated file.
|
|
144
|
+
* @param interactionName - A name for the interaction type (e.g., 'OpenRouterIO').
|
|
145
|
+
* @param data - The structured data to log.
|
|
146
|
+
*/
|
|
147
|
+
logInteraction(interactionName: string, data: Record<string, unknown>): void;
|
|
136
148
|
}
|
|
137
149
|
/**
|
|
138
150
|
* The singleton instance of the Logger.
|
|
@@ -35,9 +35,8 @@ const mcpToWinstonLevel = {
|
|
|
35
35
|
alert: "error",
|
|
36
36
|
emerg: "error",
|
|
37
37
|
};
|
|
38
|
-
// The logsPath from config is
|
|
39
|
-
|
|
40
|
-
const isLogsDirSafe = !!resolvedLogsDir; // If logsPath is set, it's considered safe by config logic.
|
|
38
|
+
// The logsPath from config is resolved and validated by src/config/index.ts.
|
|
39
|
+
// It can be null if the directory is invalid or inaccessible, in which case file logging will be disabled.
|
|
41
40
|
/**
|
|
42
41
|
* Creates the Winston console log format.
|
|
43
42
|
* @returns The Winston log format for console output.
|
|
@@ -107,10 +106,7 @@ export class Logger {
|
|
|
107
106
|
this.initialized = true;
|
|
108
107
|
this.currentMcpLevel = level;
|
|
109
108
|
this.currentWinstonLevel = mcpToWinstonLevel[level];
|
|
110
|
-
|
|
111
|
-
// by the configuration module (src/config/index.ts) before logger initialization.
|
|
112
|
-
// If isLogsDirSafe is true, we assume resolvedLogsDir exists and is usable.
|
|
113
|
-
// No redundant directory creation logic here.
|
|
109
|
+
const resolvedLogsDir = config.logsPath;
|
|
114
110
|
const fileFormat = winston.format.combine(winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json());
|
|
115
111
|
const transports = [];
|
|
116
112
|
const fileTransportOptions = {
|
|
@@ -119,7 +115,7 @@ export class Logger {
|
|
|
119
115
|
maxFiles: this.LOG_MAX_FILES,
|
|
120
116
|
tailable: true,
|
|
121
117
|
};
|
|
122
|
-
if (
|
|
118
|
+
if (resolvedLogsDir) {
|
|
123
119
|
transports.push(new winston.transports.File({
|
|
124
120
|
filename: path.join(resolvedLogsDir, "error.log"),
|
|
125
121
|
level: "error",
|
|
@@ -151,6 +147,18 @@ export class Logger {
|
|
|
151
147
|
transports,
|
|
152
148
|
exitOnError: false,
|
|
153
149
|
});
|
|
150
|
+
// Initialize a separate logger for structured interactions
|
|
151
|
+
if (resolvedLogsDir) {
|
|
152
|
+
this.interactionLogger = winston.createLogger({
|
|
153
|
+
format: winston.format.combine(winston.format.timestamp(), winston.format.json({ space: 2 })),
|
|
154
|
+
transports: [
|
|
155
|
+
new winston.transports.File({
|
|
156
|
+
filename: path.join(resolvedLogsDir, "interactions.log"),
|
|
157
|
+
...fileTransportOptions,
|
|
158
|
+
}),
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
}
|
|
154
162
|
// Configure console transport after Winston logger is created
|
|
155
163
|
const consoleStatus = this._configureConsoleTransport();
|
|
156
164
|
const initialContext = {
|
|
@@ -167,7 +175,7 @@ export class Logger {
|
|
|
167
175
|
loggerSetup: true,
|
|
168
176
|
requestId: "logger-post-init",
|
|
169
177
|
timestamp: new Date().toISOString(),
|
|
170
|
-
logsPathUsed: resolvedLogsDir,
|
|
178
|
+
logsPathUsed: resolvedLogsDir ?? "none",
|
|
171
179
|
});
|
|
172
180
|
}
|
|
173
181
|
/**
|
|
@@ -262,6 +270,20 @@ export class Logger {
|
|
|
262
270
|
}
|
|
263
271
|
return Logger.instance;
|
|
264
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Resets the singleton instance.
|
|
275
|
+
* This is intended for use in testing environments only.
|
|
276
|
+
*/
|
|
277
|
+
static resetForTesting() {
|
|
278
|
+
// This is a clear indication that this method is for testing purposes.
|
|
279
|
+
if (process.env.NODE_ENV !== "test") {
|
|
280
|
+
console.warn("Warning: `resetForTesting` should only be called in a test environment.");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
// De-reference the instance to allow garbage collection
|
|
284
|
+
// and force re-creation on next getInstance() call.
|
|
285
|
+
Logger.instance = undefined;
|
|
286
|
+
}
|
|
265
287
|
/**
|
|
266
288
|
* Ensures the logger has been initialized.
|
|
267
289
|
* @returns True if initialized, false otherwise.
|
|
@@ -398,6 +420,18 @@ export class Logger {
|
|
|
398
420
|
const actualContext = err instanceof Error ? context : err;
|
|
399
421
|
this.log("emerg", msg, actualContext, errorObj);
|
|
400
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* Logs a structured interaction object to a dedicated file.
|
|
425
|
+
* @param interactionName - A name for the interaction type (e.g., 'OpenRouterIO').
|
|
426
|
+
* @param data - The structured data to log.
|
|
427
|
+
*/
|
|
428
|
+
logInteraction(interactionName, data) {
|
|
429
|
+
if (!this.interactionLogger) {
|
|
430
|
+
this.warning("Interaction logger not available. File logging may be disabled.", data.context);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
this.interactionLogger.info({ interactionName, ...data });
|
|
434
|
+
}
|
|
401
435
|
}
|
|
402
436
|
/**
|
|
403
437
|
* The singleton instance of the Logger.
|
|
@@ -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,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a singleton service for scheduling and managing cron jobs.
|
|
3
|
+
* This service wraps the 'node-cron' library to offer a unified interface for
|
|
4
|
+
* defining, starting, stopping, and listing recurring tasks within the application.
|
|
5
|
+
* @module src/utils/scheduling/scheduler
|
|
6
|
+
*/
|
|
7
|
+
import { ScheduledTask } from "node-cron";
|
|
8
|
+
import { RequestContext } from "../internal/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Represents a scheduled job managed by the SchedulerService.
|
|
11
|
+
*/
|
|
12
|
+
export interface Job {
|
|
13
|
+
/** A unique identifier for the job. */
|
|
14
|
+
id: string;
|
|
15
|
+
/** The cron pattern defining the job's schedule. */
|
|
16
|
+
schedule: string;
|
|
17
|
+
/** A description of what the job does. */
|
|
18
|
+
description: string;
|
|
19
|
+
/** The underlying 'node-cron' task instance. */
|
|
20
|
+
task: ScheduledTask;
|
|
21
|
+
/** Indicates whether the job is currently running. */
|
|
22
|
+
isRunning: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A singleton service for scheduling and managing cron jobs.
|
|
26
|
+
*/
|
|
27
|
+
export declare class SchedulerService {
|
|
28
|
+
private static instance;
|
|
29
|
+
private jobs;
|
|
30
|
+
/** @private */
|
|
31
|
+
private constructor();
|
|
32
|
+
/**
|
|
33
|
+
* Gets the singleton instance of the SchedulerService.
|
|
34
|
+
* @returns The singleton SchedulerService instance.
|
|
35
|
+
*/
|
|
36
|
+
static getInstance(): SchedulerService;
|
|
37
|
+
/**
|
|
38
|
+
* Schedules a new job.
|
|
39
|
+
*
|
|
40
|
+
* @param id - A unique identifier for the job.
|
|
41
|
+
* @param schedule - The cron pattern for the schedule (e.g., '* * * * *').
|
|
42
|
+
* @param taskFunction - The function to execute on schedule. It receives a RequestContext.
|
|
43
|
+
* @param description - A description of the job.
|
|
44
|
+
* @returns The newly created Job object.
|
|
45
|
+
*/
|
|
46
|
+
schedule(id: string, schedule: string, taskFunction: (context: RequestContext) => void | Promise<void>, description: string): Job;
|
|
47
|
+
/**
|
|
48
|
+
* Starts a scheduled job.
|
|
49
|
+
* @param id - The ID of the job to start.
|
|
50
|
+
*/
|
|
51
|
+
start(id: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Stops a scheduled job.
|
|
54
|
+
* @param id - The ID of the job to stop.
|
|
55
|
+
*/
|
|
56
|
+
stop(id: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Removes a job from the scheduler. The job is stopped before being removed.
|
|
59
|
+
* @param id - The ID of the job to remove.
|
|
60
|
+
*/
|
|
61
|
+
remove(id: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Gets a list of all scheduled jobs.
|
|
64
|
+
* @returns An array of all Job objects.
|
|
65
|
+
*/
|
|
66
|
+
listJobs(): Job[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The singleton instance of the SchedulerService.
|
|
70
|
+
* Use this instance for all job scheduling operations.
|
|
71
|
+
*/
|
|
72
|
+
export declare const schedulerService: SchedulerService;
|