@novorb/mcp-core 2.1.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/dist/logger.js ADDED
@@ -0,0 +1,236 @@
1
+ /**
2
+ * @novorb/mcp-core — Logger
3
+ *
4
+ * Unified logger for MCP servers. Supports two output modes:
5
+ * - file: writes to rotating log files (for stdio-based MCP servers)
6
+ * - stderr: writes to stderr (for Docker / HTTP transport)
7
+ *
8
+ * Log format (text): 2026-03-22T13:27:58.513Z | INFO | Server | Starting...
9
+ * Log format (json): {"level":"INFO","timestamp":"...","component":"Server","message":"Starting..."}
10
+ *
11
+ * Environment variables (read once at first logger creation):
12
+ * - LOG_LEVEL: DEBUG, INFO, WARN, ERROR (default: INFO)
13
+ * - LOG_PATH: log directory (default: ./logs)
14
+ * - LOG_FILE: log file name (default: mcp.log)
15
+ *
16
+ * Security: `meta` is passed through `redactSecrets()` before serialisation — sensitive-keyed fields
17
+ * (authorization/token/api_key/secret/password/cookie/...) are replaced with `[REDACTED]` so a
18
+ * consumer that logs an error object or request params never writes a credential in cleartext. In
19
+ * text mode the message + component are also stripped of CR/LF so a logged value can't forge log lines.
20
+ */
21
+ import * as fs from 'fs';
22
+ import * as path from 'path';
23
+ export var LogLevel;
24
+ (function (LogLevel) {
25
+ LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
26
+ LogLevel[LogLevel["INFO"] = 1] = "INFO";
27
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
28
+ LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
29
+ })(LogLevel || (LogLevel = {}));
30
+ /** Map string → LogLevel, case-insensitive */
31
+ function parseLogLevel(value) {
32
+ if (!value)
33
+ return undefined;
34
+ const upper = value.toUpperCase();
35
+ if (upper in LogLevel && typeof LogLevel[upper] === 'number') {
36
+ return LogLevel[upper];
37
+ }
38
+ return undefined;
39
+ }
40
+ const DEFAULT_CONFIG = {
41
+ level: LogLevel.INFO,
42
+ output: 'stderr',
43
+ format: 'text',
44
+ logDir: 'logs',
45
+ logFile: 'mcp.log',
46
+ maxLogSize: 10 * 1024 * 1024,
47
+ maxLogFiles: 5,
48
+ };
49
+ /** Build config from defaults + env vars + explicit overrides */
50
+ function buildConfig(overrides) {
51
+ const envLevel = parseLogLevel(process.env.LOG_LEVEL);
52
+ const envDir = process.env.LOG_PATH;
53
+ const envFile = process.env.LOG_FILE;
54
+ return {
55
+ ...DEFAULT_CONFIG,
56
+ ...(envLevel !== undefined ? { level: envLevel } : {}),
57
+ ...(envDir ? { logDir: envDir } : {}),
58
+ ...(envFile ? { logFile: envFile } : {}),
59
+ ...overrides,
60
+ };
61
+ }
62
+ // Keys whose values are redacted before a `meta` object is serialised. Defense-in-depth: consumers
63
+ // commonly pass error objects / request params carrying credentials, and a log sink must never write
64
+ // them in cleartext. Matched case-insensitively against each object key.
65
+ const SENSITIVE_KEY = /(authorization|cookie|password|secret|client[_-]?secret|access[_-]?token|refresh[_-]?token|token|api[_-]?key|apikey|bearer|private[_-]?key|signature|x-api-key)/i;
66
+ const REDACTED = '[REDACTED]';
67
+ /** Recursively copy a value, replacing any sensitive-keyed field with `[REDACTED]`. */
68
+ export function redactSecrets(value, depth = 0) {
69
+ if (depth > 6 || value === null || typeof value !== 'object')
70
+ return value;
71
+ if (Array.isArray(value))
72
+ return value.map(v => redactSecrets(v, depth + 1));
73
+ const out = {};
74
+ for (const [k, v] of Object.entries(value)) {
75
+ out[k] = SENSITIVE_KEY.test(k) ? REDACTED : redactSecrets(v, depth + 1);
76
+ }
77
+ return out;
78
+ }
79
+ /** Collapse C0 control chars (incl. CR/LF) + DEL to spaces so a logged value can't forge log lines. */
80
+ function stripControlChars(s) {
81
+ let out = '';
82
+ for (let i = 0; i < s.length; i++) {
83
+ const code = s.charCodeAt(i);
84
+ out += (code < 0x20 || code === 0x7f) ? ' ' : s[i];
85
+ }
86
+ return out;
87
+ }
88
+ // Padded level names — fixed 5 chars for alignment
89
+ const LEVEL_NAMES = {
90
+ [LogLevel.DEBUG]: 'DEBUG',
91
+ [LogLevel.INFO]: 'INFO ',
92
+ [LogLevel.WARN]: 'WARN ',
93
+ [LogLevel.ERROR]: 'ERROR',
94
+ };
95
+ export class Logger {
96
+ config;
97
+ logPath;
98
+ constructor(config) {
99
+ this.config = buildConfig(config);
100
+ this.logPath = path.join(this.config.logDir, this.config.logFile);
101
+ if (this.config.output === 'file') {
102
+ this.ensureLogDirectory();
103
+ }
104
+ }
105
+ ensureLogDirectory() {
106
+ if (!fs.existsSync(this.config.logDir)) {
107
+ fs.mkdirSync(this.config.logDir, { recursive: true });
108
+ }
109
+ }
110
+ shouldLog(level) {
111
+ return level >= this.config.level;
112
+ }
113
+ formatText(level, message, context, meta) {
114
+ const timestamp = new Date().toISOString();
115
+ const levelStr = LEVEL_NAMES[level] ?? LogLevel[level].padEnd(5);
116
+ const contextStr = stripControlChars(context ?? 'General');
117
+ const safeMessage = stripControlChars(message);
118
+ const metaStr = meta !== undefined ? ` | ${JSON.stringify(redactSecrets(meta))}` : '';
119
+ return `${timestamp} | ${levelStr} | ${contextStr} | ${safeMessage}${metaStr}\n`;
120
+ }
121
+ formatJson(level, message, context, meta) {
122
+ const entry = {
123
+ level: LogLevel[level],
124
+ timestamp: new Date().toISOString(),
125
+ component: context ?? 'General',
126
+ message,
127
+ };
128
+ if (meta !== undefined) {
129
+ const safeMeta = redactSecrets(meta);
130
+ if (typeof safeMeta === 'object' && safeMeta !== null) {
131
+ Object.assign(entry, safeMeta);
132
+ }
133
+ else {
134
+ entry.meta = safeMeta;
135
+ }
136
+ }
137
+ return JSON.stringify(entry) + '\n';
138
+ }
139
+ format(level, message, context, meta) {
140
+ return this.config.format === 'json'
141
+ ? this.formatJson(level, message, context, meta)
142
+ : this.formatText(level, message, context, meta);
143
+ }
144
+ write(level, message, context, meta) {
145
+ if (!this.shouldLog(level))
146
+ return;
147
+ const formatted = this.format(level, message, context, meta);
148
+ if (this.config.output === 'file') {
149
+ this.writeToFile(formatted);
150
+ }
151
+ else {
152
+ process.stderr.write(formatted);
153
+ }
154
+ }
155
+ writeToFile(message) {
156
+ try {
157
+ if (fs.existsSync(this.logPath)) {
158
+ const stats = fs.statSync(this.logPath);
159
+ if (stats.size > this.config.maxLogSize) {
160
+ this.rotateLog();
161
+ }
162
+ }
163
+ fs.appendFileSync(this.logPath, message, 'utf8');
164
+ }
165
+ catch {
166
+ // Silently fail — can't log to console in MCP stdio context
167
+ }
168
+ }
169
+ rotateLog() {
170
+ try {
171
+ for (let i = this.config.maxLogFiles - 1; i > 0; i--) {
172
+ const oldPath = `${this.logPath}.${i}`;
173
+ const newPath = `${this.logPath}.${i + 1}`;
174
+ if (fs.existsSync(oldPath)) {
175
+ if (i === this.config.maxLogFiles - 1) {
176
+ fs.unlinkSync(oldPath);
177
+ }
178
+ else {
179
+ fs.renameSync(oldPath, newPath);
180
+ }
181
+ }
182
+ }
183
+ if (fs.existsSync(this.logPath)) {
184
+ fs.renameSync(this.logPath, `${this.logPath}.1`);
185
+ }
186
+ }
187
+ catch {
188
+ // Silently fail
189
+ }
190
+ }
191
+ debug(message, context, meta) {
192
+ this.write(LogLevel.DEBUG, message, context, meta);
193
+ }
194
+ info(message, context, meta) {
195
+ this.write(LogLevel.INFO, message, context, meta);
196
+ }
197
+ warn(message, context, meta) {
198
+ this.write(LogLevel.WARN, message, context, meta);
199
+ }
200
+ error(message, context, meta) {
201
+ this.write(LogLevel.ERROR, message, context, meta);
202
+ }
203
+ setLevel(level) {
204
+ this.config.level = level;
205
+ }
206
+ }
207
+ // Singleton management
208
+ let loggerInstance = null;
209
+ /**
210
+ * Initialize logger with custom config.
211
+ * Should be called once at application startup.
212
+ * Reads LOG_LEVEL, LOG_PATH, LOG_FILE from env (overrides take precedence).
213
+ */
214
+ export function initLogger(config) {
215
+ loggerInstance = new Logger(config);
216
+ return loggerInstance;
217
+ }
218
+ /**
219
+ * Get the logger instance.
220
+ * Creates a default stderr/text instance if initLogger was not called.
221
+ * Reads LOG_LEVEL, LOG_PATH, LOG_FILE from env on first creation.
222
+ */
223
+ export function getLogger(config) {
224
+ if (!loggerInstance) {
225
+ loggerInstance = new Logger(config);
226
+ }
227
+ return loggerInstance;
228
+ }
229
+ /**
230
+ * Reset the singleton (for testing).
231
+ */
232
+ export function resetLogger() {
233
+ loggerInstance = null;
234
+ }
235
+ export default getLogger;
236
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @novorb/mcp-core — Pagination utilities
3
+ *
4
+ * Normalize and compute pagination metadata across MCP servers.
5
+ */
6
+ export interface PaginationParams {
7
+ /** Page number (1-based, default: 1) */
8
+ page?: number;
9
+ /** Items per page (default: 20, max: 100) */
10
+ per_page?: number;
11
+ }
12
+ export interface NormalizedPagination {
13
+ page: number;
14
+ per_page: number;
15
+ }
16
+ export interface PaginationMetadata {
17
+ totalCount: number;
18
+ page: number;
19
+ perPage: number;
20
+ totalPages: number;
21
+ }
22
+ /**
23
+ * Normalize pagination parameters with sensible bounds.
24
+ *
25
+ * @param params - Raw pagination params
26
+ * @param maxPerPage - Maximum allowed per_page (default: 100)
27
+ * @param defaultPerPage - Default per_page (default: 20)
28
+ */
29
+ export declare function normalizePagination(params?: PaginationParams, maxPerPage?: number, defaultPerPage?: number): NormalizedPagination;
30
+ /**
31
+ * Create pagination metadata from total count and normalized params.
32
+ */
33
+ export declare function createPaginationMetadata(totalCount: number, params: NormalizedPagination): PaginationMetadata;
34
+ /**
35
+ * Calculate offset for SQL/API pagination from 1-based page number.
36
+ */
37
+ export declare function pageToOffset(page: number, perPage: number): number;
38
+ /**
39
+ * Apply in-memory pagination to an array.
40
+ */
41
+ export declare function paginateArray<T>(items: T[], params: NormalizedPagination): {
42
+ data: T[];
43
+ metadata: PaginationMetadata;
44
+ };
45
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,CAAC,EAAE,gBAAgB,EACzB,UAAU,SAAM,EAChB,cAAc,SAAK,GAClB,oBAAoB,CAItB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,oBAAoB,GAC3B,kBAAkB,CAOpB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,CAAC,EAAE,EACV,MAAM,EAAE,oBAAoB,GAC3B;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,QAAQ,EAAE,kBAAkB,CAAA;CAAE,CAO7C"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @novorb/mcp-core — Pagination utilities
3
+ *
4
+ * Normalize and compute pagination metadata across MCP servers.
5
+ */
6
+ /**
7
+ * Normalize pagination parameters with sensible bounds.
8
+ *
9
+ * @param params - Raw pagination params
10
+ * @param maxPerPage - Maximum allowed per_page (default: 100)
11
+ * @param defaultPerPage - Default per_page (default: 20)
12
+ */
13
+ export function normalizePagination(params, maxPerPage = 100, defaultPerPage = 20) {
14
+ const page = Math.max(1, params?.page ?? 1);
15
+ const per_page = Math.min(maxPerPage, Math.max(1, params?.per_page ?? defaultPerPage));
16
+ return { page, per_page };
17
+ }
18
+ /**
19
+ * Create pagination metadata from total count and normalized params.
20
+ */
21
+ export function createPaginationMetadata(totalCount, params) {
22
+ return {
23
+ totalCount,
24
+ page: params.page,
25
+ perPage: params.per_page,
26
+ totalPages: Math.ceil(totalCount / params.per_page),
27
+ };
28
+ }
29
+ /**
30
+ * Calculate offset for SQL/API pagination from 1-based page number.
31
+ */
32
+ export function pageToOffset(page, perPage) {
33
+ return (Math.max(1, page) - 1) * perPage;
34
+ }
35
+ /**
36
+ * Apply in-memory pagination to an array.
37
+ */
38
+ export function paginateArray(items, params) {
39
+ const offset = pageToOffset(params.page, params.per_page);
40
+ const data = items.slice(offset, offset + params.per_page);
41
+ return {
42
+ data,
43
+ metadata: createPaginationMetadata(items.length, params),
44
+ };
45
+ }
46
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqBH;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAyB,EACzB,UAAU,GAAG,GAAG,EAChB,cAAc,GAAG,EAAE;IAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,IAAI,cAAc,CAAC,CAAC,CAAC;IACvF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,UAAkB,EAClB,MAA4B;IAE5B,OAAO;QACL,UAAU;QACV,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,OAAO,EAAE,MAAM,CAAC,QAAQ;QACxB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC;KACpD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,OAAe;IACxD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAU,EACV,MAA4B;IAE5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3D,OAAO;QACL,IAAI;QACJ,QAAQ,EAAE,wBAAwB,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;KACzD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @novorb/mcp-core — Retry utilities
3
+ *
4
+ * Exponential backoff with jitter for retrying failed HTTP requests.
5
+ */
6
+ export interface RetryOptions {
7
+ /** Maximum number of retries (default: 3) */
8
+ maxRetries?: number;
9
+ /** Initial delay in milliseconds (default: 1000) */
10
+ initialDelayMs?: number;
11
+ /** Maximum delay in milliseconds (default: 10000) */
12
+ maxDelayMs?: number;
13
+ /** Backoff multiplier (default: 2) */
14
+ backoffMultiplier?: number;
15
+ /** Jitter factor 0-1 (default: 0.1 = 10%) */
16
+ jitterFactor?: number;
17
+ }
18
+ export interface RetryContext {
19
+ /** Current attempt number (0-based) */
20
+ attempt: number;
21
+ /** Maximum retries configured */
22
+ maxRetries: number;
23
+ /** Last error encountered */
24
+ lastError?: Error;
25
+ }
26
+ /**
27
+ * Calculate retry delay with exponential backoff and jitter.
28
+ */
29
+ export declare function calculateRetryDelay(attempt: number, options?: RetryOptions): number;
30
+ /**
31
+ * Sleep for specified milliseconds.
32
+ */
33
+ export declare function sleep(ms: number): Promise<void>;
34
+ /**
35
+ * Determine if an error is retryable.
36
+ */
37
+ export declare function isRetryableError(error: unknown): boolean;
38
+ /**
39
+ * Retry a function with exponential backoff.
40
+ *
41
+ * @param fn - Async function to retry (receives RetryContext)
42
+ * @param options - Retry options
43
+ * @returns Result of successful function call
44
+ * @throws Last error if all retries exhausted or error is not retryable
45
+ */
46
+ export declare function retryWithBackoff<T>(fn: (context: RetryContext) => Promise<T>, options?: RetryOptions): Promise<T>;
47
+ /**
48
+ * Parse Retry-After header value to milliseconds.
49
+ */
50
+ export declare function parseRetryAfter(retryAfter: string | undefined): number | undefined;
51
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB;AAUD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,YAAiB,GACzB,MAAM,CAOR;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAQD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAiBxD;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,EAAE,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAUlF"}
package/dist/retry.js ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @novorb/mcp-core — Retry utilities
3
+ *
4
+ * Exponential backoff with jitter for retrying failed HTTP requests.
5
+ */
6
+ const DEFAULT_OPTIONS = {
7
+ maxRetries: 3,
8
+ initialDelayMs: 1000,
9
+ maxDelayMs: 10000,
10
+ backoffMultiplier: 2,
11
+ jitterFactor: 0.1,
12
+ };
13
+ /**
14
+ * Calculate retry delay with exponential backoff and jitter.
15
+ */
16
+ export function calculateRetryDelay(attempt, options = {}) {
17
+ const opts = { ...DEFAULT_OPTIONS, ...options };
18
+ const exponentialDelay = opts.initialDelayMs * Math.pow(opts.backoffMultiplier, attempt);
19
+ const cappedDelay = Math.min(exponentialDelay, opts.maxDelayMs);
20
+ const jitterRange = cappedDelay * opts.jitterFactor;
21
+ const jitter = (Math.random() * 2 - 1) * jitterRange;
22
+ return Math.max(0, cappedDelay + jitter);
23
+ }
24
+ /**
25
+ * Sleep for specified milliseconds.
26
+ */
27
+ export function sleep(ms) {
28
+ return new Promise(resolve => setTimeout(resolve, ms));
29
+ }
30
+ /** HTTP status codes that should be retried */
31
+ const RETRYABLE_STATUS_CODES = [408, 429, 502, 503, 504];
32
+ /** Network error codes that should be retried */
33
+ const RETRYABLE_NETWORK_CODES = ['ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED'];
34
+ /**
35
+ * Determine if an error is retryable.
36
+ */
37
+ export function isRetryableError(error) {
38
+ if (error && typeof error === 'object') {
39
+ const err = error;
40
+ // Network errors
41
+ if (typeof err.code === 'string' && RETRYABLE_NETWORK_CODES.includes(err.code)) {
42
+ return true;
43
+ }
44
+ // HTTP status codes
45
+ const response = err.response;
46
+ const status = response?.status;
47
+ if (typeof status === 'number') {
48
+ return RETRYABLE_STATUS_CODES.includes(status);
49
+ }
50
+ }
51
+ return false;
52
+ }
53
+ /**
54
+ * Retry a function with exponential backoff.
55
+ *
56
+ * @param fn - Async function to retry (receives RetryContext)
57
+ * @param options - Retry options
58
+ * @returns Result of successful function call
59
+ * @throws Last error if all retries exhausted or error is not retryable
60
+ */
61
+ export async function retryWithBackoff(fn, options = {}) {
62
+ const opts = { ...DEFAULT_OPTIONS, ...options };
63
+ let lastError;
64
+ for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
65
+ const context = { attempt, maxRetries: opts.maxRetries, lastError };
66
+ try {
67
+ return await fn(context);
68
+ }
69
+ catch (error) {
70
+ lastError = error;
71
+ if (attempt === opts.maxRetries || !isRetryableError(error)) {
72
+ throw error;
73
+ }
74
+ const delay = calculateRetryDelay(attempt, options);
75
+ await sleep(delay);
76
+ }
77
+ }
78
+ throw lastError || new Error('Retry exhausted');
79
+ }
80
+ /**
81
+ * Parse Retry-After header value to milliseconds.
82
+ */
83
+ export function parseRetryAfter(retryAfter) {
84
+ if (!retryAfter)
85
+ return undefined;
86
+ const seconds = parseInt(retryAfter, 10);
87
+ if (!isNaN(seconds))
88
+ return seconds * 1000;
89
+ const date = new Date(retryAfter);
90
+ if (!isNaN(date.getTime()))
91
+ return Math.max(0, date.getTime() - Date.now());
92
+ return undefined;
93
+ }
94
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @novorb/mcp-core — Server
3
+ *
4
+ * Re-exports and base patterns for building MCP servers with the high-level McpServer API.
5
+ * Import from here instead of the SDK directly — one centralised import point for all
6
+ * server-building primitives.
7
+ *
8
+ * Usage:
9
+ * import { createMcpServer, TOOL_ANNOTATIONS, completable } from '@novorb/mcp-core/server';
10
+ * import type { McpToolAnnotations, McpCallToolResult } from '@novorb/mcp-core/server';
11
+ *
12
+ * const server = createMcpServer('my-mcp', '1.0.0');
13
+ *
14
+ * server.registerTool('lookup', {
15
+ * description: 'Look up data by key',
16
+ * inputSchema: { key: z.string() },
17
+ * outputSchema: { value: z.string(), found: z.boolean() },
18
+ * annotations: TOOL_ANNOTATIONS.readOnly,
19
+ * }, async ({ key }) => {
20
+ * const value = await lookup(key);
21
+ * return {
22
+ * content: [{ type: 'text', text: value ?? 'not found' }],
23
+ * structuredContent: { value: value ?? '', found: value !== null },
24
+ * };
25
+ * });
26
+ *
27
+ * server.registerPrompt('find-and-summarise', {
28
+ * title: 'Find and summarise',
29
+ * description: 'Look up a key and summarise the value',
30
+ * argsSchema: { key: completable(z.string(), val => ['foo', 'bar'].filter(k => k.startsWith(val))) },
31
+ * }, ({ key }) => ({
32
+ * messages: [{ role: 'user', content: { type: 'text', text: `Look up "${key}" and summarise the result.` } }],
33
+ * }));
34
+ */
35
+ export { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
36
+ export { completable } from '@modelcontextprotocol/sdk/server/completable.js';
37
+ export type { ToolAnnotations as McpToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
38
+ export type { CallToolResult as McpCallToolResult } from '@modelcontextprotocol/sdk/types.js';
39
+ /**
40
+ * Standard tool annotation presets.
41
+ *
42
+ * Pass one of these (or a spread of multiple) to `annotations` in `registerTool`.
43
+ * These are HINTS — clients may or may not act on them.
44
+ *
45
+ * @example
46
+ * annotations: TOOL_ANNOTATIONS.readOnly
47
+ * annotations: { ...TOOL_ANNOTATIONS.readOnly, title: 'Domain lookup' }
48
+ */
49
+ export declare const TOOL_ANNOTATIONS: {
50
+ /** Read-only, safe-to-retry. Use for all lookup / search / status tools. */
51
+ readonly readOnly: {
52
+ readOnlyHint: true;
53
+ idempotentHint: true;
54
+ };
55
+ /** Write that is idempotent (calling N times = calling once). */
56
+ readonly idempotentWrite: {
57
+ readOnlyHint: false;
58
+ idempotentHint: true;
59
+ };
60
+ /** Mutating write that may behave differently on repeat calls. */
61
+ readonly mutableWrite: {
62
+ readOnlyHint: false;
63
+ idempotentHint: false;
64
+ };
65
+ /** Destructive / irreversible (delete, overwrite). */
66
+ readonly destructive: {
67
+ readOnlyHint: false;
68
+ destructiveHint: true;
69
+ idempotentHint: false;
70
+ };
71
+ };
72
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
73
+ /**
74
+ * Create a pre-configured McpServer instance.
75
+ *
76
+ * Thin wrapper kept so individual servers import only from @novorb/mcp-core and
77
+ * don't carry a direct @modelcontextprotocol/sdk import.
78
+ */
79
+ export declare function createMcpServer(name: string, version: string): McpServer;
80
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAMH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAC;AAC9E,YAAY,EAAE,eAAe,IAAI,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAChG,YAAY,EAAE,cAAc,IAAI,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAQ9F;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB;IAC3B,4EAA4E;;;;;IAE5E,iEAAiE;;;;;IAEjE,kEAAkE;;;;;IAElE,sDAAsD;;;;;;CAE9C,CAAC;AAMX,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAExE"}
package/dist/server.js ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @novorb/mcp-core — Server
3
+ *
4
+ * Re-exports and base patterns for building MCP servers with the high-level McpServer API.
5
+ * Import from here instead of the SDK directly — one centralised import point for all
6
+ * server-building primitives.
7
+ *
8
+ * Usage:
9
+ * import { createMcpServer, TOOL_ANNOTATIONS, completable } from '@novorb/mcp-core/server';
10
+ * import type { McpToolAnnotations, McpCallToolResult } from '@novorb/mcp-core/server';
11
+ *
12
+ * const server = createMcpServer('my-mcp', '1.0.0');
13
+ *
14
+ * server.registerTool('lookup', {
15
+ * description: 'Look up data by key',
16
+ * inputSchema: { key: z.string() },
17
+ * outputSchema: { value: z.string(), found: z.boolean() },
18
+ * annotations: TOOL_ANNOTATIONS.readOnly,
19
+ * }, async ({ key }) => {
20
+ * const value = await lookup(key);
21
+ * return {
22
+ * content: [{ type: 'text', text: value ?? 'not found' }],
23
+ * structuredContent: { value: value ?? '', found: value !== null },
24
+ * };
25
+ * });
26
+ *
27
+ * server.registerPrompt('find-and-summarise', {
28
+ * title: 'Find and summarise',
29
+ * description: 'Look up a key and summarise the value',
30
+ * argsSchema: { key: completable(z.string(), val => ['foo', 'bar'].filter(k => k.startsWith(val))) },
31
+ * }, ({ key }) => ({
32
+ * messages: [{ role: 'user', content: { type: 'text', text: `Look up "${key}" and summarise the result.` } }],
33
+ * }));
34
+ */
35
+ // ---------------------------------------------------------------------------
36
+ // Re-exports — individual servers import ONLY from @novorb/mcp-core
37
+ // ---------------------------------------------------------------------------
38
+ export { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
39
+ export { completable } from '@modelcontextprotocol/sdk/server/completable.js';
40
+ /**
41
+ * Standard tool annotation presets.
42
+ *
43
+ * Pass one of these (or a spread of multiple) to `annotations` in `registerTool`.
44
+ * These are HINTS — clients may or may not act on them.
45
+ *
46
+ * @example
47
+ * annotations: TOOL_ANNOTATIONS.readOnly
48
+ * annotations: { ...TOOL_ANNOTATIONS.readOnly, title: 'Domain lookup' }
49
+ */
50
+ export const TOOL_ANNOTATIONS = {
51
+ /** Read-only, safe-to-retry. Use for all lookup / search / status tools. */
52
+ readOnly: { readOnlyHint: true, idempotentHint: true },
53
+ /** Write that is idempotent (calling N times = calling once). */
54
+ idempotentWrite: { readOnlyHint: false, idempotentHint: true },
55
+ /** Mutating write that may behave differently on repeat calls. */
56
+ mutableWrite: { readOnlyHint: false, idempotentHint: false },
57
+ /** Destructive / irreversible (delete, overwrite). */
58
+ destructive: { readOnlyHint: false, destructiveHint: true, idempotentHint: false },
59
+ };
60
+ // ---------------------------------------------------------------------------
61
+ // Factory
62
+ // ---------------------------------------------------------------------------
63
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
64
+ /**
65
+ * Create a pre-configured McpServer instance.
66
+ *
67
+ * Thin wrapper kept so individual servers import only from @novorb/mcp-core and
68
+ * don't carry a direct @modelcontextprotocol/sdk import.
69
+ */
70
+ export function createMcpServer(name, version) {
71
+ return new McpServer({ name, version });
72
+ }
73
+ //# sourceMappingURL=server.js.map