mcp-resend 1.0.0-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +257 -0
- package/data/embeddings.json +245241 -0
- package/dist/config/environment.d.ts +152 -0
- package/dist/config/environment.d.ts.map +1 -0
- package/dist/config/environment.js +217 -0
- package/dist/config/environment.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +119 -0
- package/dist/index.js.map +1 -0
- package/dist/services/rate-limiter.d.ts +90 -0
- package/dist/services/rate-limiter.d.ts.map +1 -0
- package/dist/services/rate-limiter.js +267 -0
- package/dist/services/rate-limiter.js.map +1 -0
- package/dist/services/tool-registry.d.ts +219 -0
- package/dist/services/tool-registry.d.ts.map +1 -0
- package/dist/services/tool-registry.js +459 -0
- package/dist/services/tool-registry.js.map +1 -0
- package/dist/tools/docs/embeddings-loader.d.ts +69 -0
- package/dist/tools/docs/embeddings-loader.d.ts.map +1 -0
- package/dist/tools/docs/embeddings-loader.js +218 -0
- package/dist/tools/docs/embeddings-loader.js.map +1 -0
- package/dist/tools/docs/errors.d.ts +75 -0
- package/dist/tools/docs/errors.d.ts.map +1 -0
- package/dist/tools/docs/errors.js +145 -0
- package/dist/tools/docs/errors.js.map +1 -0
- package/dist/tools/docs/index.d.ts +11 -0
- package/dist/tools/docs/index.d.ts.map +1 -0
- package/dist/tools/docs/index.js +14 -0
- package/dist/tools/docs/index.js.map +1 -0
- package/dist/tools/docs/metrics.d.ts +94 -0
- package/dist/tools/docs/metrics.d.ts.map +1 -0
- package/dist/tools/docs/metrics.js +174 -0
- package/dist/tools/docs/metrics.js.map +1 -0
- package/dist/tools/docs/search-docs-tool.d.ts +54 -0
- package/dist/tools/docs/search-docs-tool.d.ts.map +1 -0
- package/dist/tools/docs/search-docs-tool.js +231 -0
- package/dist/tools/docs/search-docs-tool.js.map +1 -0
- package/dist/tools/docs/types.d.ts +70 -0
- package/dist/tools/docs/types.d.ts.map +1 -0
- package/dist/tools/docs/types.js +7 -0
- package/dist/tools/docs/types.js.map +1 -0
- package/dist/tools/docs/vector-search.d.ts +80 -0
- package/dist/tools/docs/vector-search.d.ts.map +1 -0
- package/dist/tools/docs/vector-search.js +297 -0
- package/dist/tools/docs/vector-search.js.map +1 -0
- package/dist/tools/index.d.ts +27 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +3413 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/utils/mcp-errors.d.ts +109 -0
- package/dist/utils/mcp-errors.d.ts.map +1 -0
- package/dist/utils/mcp-errors.js +306 -0
- package/dist/utils/mcp-errors.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter for Resend API
|
|
3
|
+
*
|
|
4
|
+
* Provides rate limiting with queue-based processing and exponential backoff retry
|
|
5
|
+
* to ensure compliance with Resend API rate limits.
|
|
6
|
+
*
|
|
7
|
+
* @module services/rate-limiter
|
|
8
|
+
*/
|
|
9
|
+
// NOTE: Use console.error for logging - stdout is reserved for MCP protocol
|
|
10
|
+
const log = (message) => console.error(`[rate-limiter] ${message}`);
|
|
11
|
+
/**
|
|
12
|
+
* Default minimum interval between API calls in milliseconds.
|
|
13
|
+
* Resend free tier allows 2 requests/second, so 500ms provides safety margin.
|
|
14
|
+
*/
|
|
15
|
+
export const RATE_LIMIT_INTERVAL_MS = 500;
|
|
16
|
+
/**
|
|
17
|
+
* Default maximum number of retries for rate-limited requests.
|
|
18
|
+
*/
|
|
19
|
+
export const DEFAULT_MAX_RETRIES = 3;
|
|
20
|
+
/**
|
|
21
|
+
* Base delay for exponential backoff in milliseconds.
|
|
22
|
+
*/
|
|
23
|
+
const BASE_BACKOFF_MS = 1000;
|
|
24
|
+
/**
|
|
25
|
+
* Maximum delay for exponential backoff in milliseconds.
|
|
26
|
+
*/
|
|
27
|
+
const MAX_BACKOFF_MS = 32000;
|
|
28
|
+
/**
|
|
29
|
+
* Module-level state for the rate limiter.
|
|
30
|
+
*/
|
|
31
|
+
let lastCallTime = 0;
|
|
32
|
+
let rateLimitIntervalMs = RATE_LIMIT_INTERVAL_MS;
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
const queue = [];
|
|
35
|
+
let isProcessing = false;
|
|
36
|
+
let debugMode = false;
|
|
37
|
+
/**
|
|
38
|
+
* Configure the rate limiter settings.
|
|
39
|
+
*
|
|
40
|
+
* @param options - Configuration options
|
|
41
|
+
*/
|
|
42
|
+
export function configureRateLimiter(options) {
|
|
43
|
+
if (options.intervalMs !== undefined) {
|
|
44
|
+
rateLimitIntervalMs = Math.max(0, options.intervalMs);
|
|
45
|
+
log(`Rate limit interval set to ${rateLimitIntervalMs}ms`);
|
|
46
|
+
}
|
|
47
|
+
if (options.debug !== undefined) {
|
|
48
|
+
debugMode = options.debug;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the current rate limiter configuration.
|
|
53
|
+
*
|
|
54
|
+
* @returns Current configuration
|
|
55
|
+
*/
|
|
56
|
+
export function getRateLimiterConfig() {
|
|
57
|
+
return {
|
|
58
|
+
intervalMs: rateLimitIntervalMs,
|
|
59
|
+
queueLength: queue.length,
|
|
60
|
+
isProcessing,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Sleep for a specified number of milliseconds.
|
|
65
|
+
*
|
|
66
|
+
* @param ms - Milliseconds to sleep
|
|
67
|
+
*/
|
|
68
|
+
function sleep(ms) {
|
|
69
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Process the next item in the queue.
|
|
73
|
+
* Ensures sequential execution with minimum interval between calls.
|
|
74
|
+
*/
|
|
75
|
+
async function processQueue() {
|
|
76
|
+
if (isProcessing || queue.length === 0) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
isProcessing = true;
|
|
80
|
+
while (queue.length > 0) {
|
|
81
|
+
const item = queue.shift();
|
|
82
|
+
// Calculate time to wait before next call
|
|
83
|
+
const now = Date.now();
|
|
84
|
+
const timeSinceLastCall = now - lastCallTime;
|
|
85
|
+
const waitTime = Math.max(0, rateLimitIntervalMs - timeSinceLastCall);
|
|
86
|
+
if (waitTime > 0) {
|
|
87
|
+
if (debugMode) {
|
|
88
|
+
log(`Waiting ${waitTime}ms before next API call`);
|
|
89
|
+
}
|
|
90
|
+
await sleep(waitTime);
|
|
91
|
+
}
|
|
92
|
+
// Execute the function
|
|
93
|
+
try {
|
|
94
|
+
lastCallTime = Date.now();
|
|
95
|
+
const result = await item.fn();
|
|
96
|
+
item.resolve(result);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
item.reject(error instanceof Error ? error : new Error(String(error)));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
isProcessing = false;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Execute a function with rate limiting.
|
|
106
|
+
* Queues the function and processes it when the rate limit allows.
|
|
107
|
+
*
|
|
108
|
+
* @param fn - Async function to execute
|
|
109
|
+
* @returns Promise resolving to the function result
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const result = await withRateLimit(() => resendClient.emails.send(params));
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export function withRateLimit(fn) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
queue.push({ fn, resolve, reject });
|
|
119
|
+
// Start processing if not already running
|
|
120
|
+
// NOTE: Using void to explicitly ignore the promise (fire and forget)
|
|
121
|
+
void processQueue();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if an error is a rate limit error (HTTP 429).
|
|
126
|
+
*
|
|
127
|
+
* @param error - Error to check
|
|
128
|
+
* @returns True if the error is a rate limit error
|
|
129
|
+
*/
|
|
130
|
+
function isRateLimitError(error) {
|
|
131
|
+
if (error instanceof Error) {
|
|
132
|
+
// Check error message for 429 status
|
|
133
|
+
if (error.message.includes("429") || error.message.includes("rate limit")) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
// Check if error has a status property
|
|
137
|
+
const errorWithStatus = error;
|
|
138
|
+
return errorWithStatus.status === 429 || errorWithStatus.statusCode === 429;
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Extract Retry-After value from error response.
|
|
144
|
+
* Supports both seconds (integer) and HTTP-date formats.
|
|
145
|
+
*
|
|
146
|
+
* @param error - Error that may contain Retry-After header
|
|
147
|
+
* @returns Delay in milliseconds, or undefined if not present
|
|
148
|
+
*/
|
|
149
|
+
function extractRetryAfter(error) {
|
|
150
|
+
if (typeof error !== "object" || error === null) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
const errorObj = error;
|
|
154
|
+
// Check for headers object (common in HTTP client errors)
|
|
155
|
+
const headers = errorObj.headers;
|
|
156
|
+
const retryAfterValue = headers?.["retry-after"] ||
|
|
157
|
+
headers?.["Retry-After"] ||
|
|
158
|
+
errorObj.retryAfter;
|
|
159
|
+
if (retryAfterValue === undefined) {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
// If it's a number, treat as seconds
|
|
163
|
+
if (typeof retryAfterValue === "number") {
|
|
164
|
+
return retryAfterValue * 1000;
|
|
165
|
+
}
|
|
166
|
+
// Try to parse as integer (seconds)
|
|
167
|
+
const seconds = parseInt(retryAfterValue, 10);
|
|
168
|
+
if (!isNaN(seconds)) {
|
|
169
|
+
return seconds * 1000;
|
|
170
|
+
}
|
|
171
|
+
// Try to parse as HTTP-date
|
|
172
|
+
const date = new Date(retryAfterValue);
|
|
173
|
+
if (!isNaN(date.getTime())) {
|
|
174
|
+
const delayMs = date.getTime() - Date.now();
|
|
175
|
+
return delayMs > 0 ? delayMs : undefined;
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Calculate exponential backoff delay.
|
|
181
|
+
*
|
|
182
|
+
* @param attempt - Current attempt number (0-indexed)
|
|
183
|
+
* @returns Delay in milliseconds
|
|
184
|
+
*/
|
|
185
|
+
function calculateBackoff(attempt) {
|
|
186
|
+
// Exponential backoff: base * 2^attempt with jitter
|
|
187
|
+
const exponentialDelay = BASE_BACKOFF_MS * Math.pow(2, attempt);
|
|
188
|
+
// Add random jitter (0-25% of delay)
|
|
189
|
+
const jitter = Math.random() * 0.25 * exponentialDelay;
|
|
190
|
+
return Math.min(exponentialDelay + jitter, MAX_BACKOFF_MS);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Execute a function with automatic retry on rate limit errors.
|
|
194
|
+
* Uses exponential backoff with jitter.
|
|
195
|
+
*
|
|
196
|
+
* @param fn - Async function to execute
|
|
197
|
+
* @param maxRetries - Maximum number of retry attempts (default: 3)
|
|
198
|
+
* @returns Promise resolving to the function result
|
|
199
|
+
* @throws Error if all retries are exhausted
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* const result = await withRetry(
|
|
204
|
+
* () => resendClient.emails.send(params),
|
|
205
|
+
* 3
|
|
206
|
+
* );
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
export async function withRetry(fn, maxRetries = DEFAULT_MAX_RETRIES) {
|
|
210
|
+
let lastError;
|
|
211
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
212
|
+
try {
|
|
213
|
+
return await fn();
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
217
|
+
// Only retry on rate limit errors
|
|
218
|
+
if (!isRateLimitError(error)) {
|
|
219
|
+
throw lastError;
|
|
220
|
+
}
|
|
221
|
+
// Check if we have retries left
|
|
222
|
+
if (attempt < maxRetries) {
|
|
223
|
+
// Prefer Retry-After header if present, otherwise use exponential backoff
|
|
224
|
+
const retryAfterDelay = extractRetryAfter(error);
|
|
225
|
+
const delay = retryAfterDelay ?? calculateBackoff(attempt);
|
|
226
|
+
const delaySource = retryAfterDelay ? "Retry-After header" : "exponential backoff";
|
|
227
|
+
log(`Rate limited (attempt ${attempt + 1}/${maxRetries + 1}), ` +
|
|
228
|
+
`retrying in ${Math.round(delay)}ms (${delaySource})`);
|
|
229
|
+
await sleep(delay);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// All retries exhausted
|
|
234
|
+
throw new Error(`Rate limit exceeded after ${maxRetries + 1} attempts: ${lastError?.message || "Unknown error"}`);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Execute a function with both rate limiting and retry logic.
|
|
238
|
+
* This is the recommended function for most Resend API calls.
|
|
239
|
+
*
|
|
240
|
+
* @param fn - Async function to execute
|
|
241
|
+
* @param maxRetries - Maximum number of retry attempts (default: 3)
|
|
242
|
+
* @returns Promise resolving to the function result
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const result = await withRateLimitAndRetry(
|
|
247
|
+
* () => resendClient.emails.send(params),
|
|
248
|
+
* 3
|
|
249
|
+
* );
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
export async function withRateLimitAndRetry(fn, maxRetries = DEFAULT_MAX_RETRIES) {
|
|
253
|
+
return withRateLimit(() => withRetry(fn, maxRetries));
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Reset the rate limiter state.
|
|
257
|
+
* Useful for testing or reconfiguration.
|
|
258
|
+
*/
|
|
259
|
+
export function resetRateLimiter() {
|
|
260
|
+
lastCallTime = 0;
|
|
261
|
+
queue.length = 0;
|
|
262
|
+
isProcessing = false;
|
|
263
|
+
rateLimitIntervalMs = RATE_LIMIT_INTERVAL_MS;
|
|
264
|
+
debugMode = false;
|
|
265
|
+
log("Rate limiter reset");
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/services/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4EAA4E;AAC5E,MAAM,GAAG,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;AAE5E;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC;;GAEG;AACH,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B;;GAEG;AACH,MAAM,cAAc,GAAG,KAAK,CAAC;AAc7B;;GAEG;AACH,IAAI,YAAY,GAAG,CAAC,CAAC;AACrB,IAAI,mBAAmB,GAAG,sBAAsB,CAAC;AACjD,8DAA8D;AAC9D,MAAM,KAAK,GAAqB,EAAE,CAAC;AACnC,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAGpC;IACC,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACtD,GAAG,CAAC,8BAA8B,mBAAmB,IAAI,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAKlC,OAAO;QACL,UAAU,EAAE,mBAAmB;QAC/B,WAAW,EAAE,KAAK,CAAC,MAAM;QACzB,YAAY;KACb,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,YAAY;IACzB,IAAI,YAAY,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO;IACT,CAAC;IAED,YAAY,GAAG,IAAI,CAAC;IAEpB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAE5B,0CAA0C;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,iBAAiB,GAAG,GAAG,GAAG,YAAY,CAAC;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,GAAG,iBAAiB,CAAC,CAAC;QAEtE,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,IAAI,SAAS,EAAE,CAAC;gBACd,GAAG,CAAC,WAAW,QAAQ,yBAAyB,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;QAED,uBAAuB;QACvB,IAAI,CAAC;YACH,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED,YAAY,GAAG,KAAK,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAI,EAAoB;IACnD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAEpC,0CAA0C;QAC1C,sEAAsE;QACtE,KAAK,YAAY,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,qCAAqC;QACrC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAC1E,OAAO,IAAI,CAAC;QACd,CAAC;QACD,uCAAuC;QACvC,MAAM,eAAe,GAAG,KAAyD,CAAC;QAClF,OAAO,eAAe,CAAC,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,UAAU,KAAK,GAAG,CAAC;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,QAAQ,GAAG,KAAgC,CAAC;IAElD,0DAA0D;IAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,OAA6C,CAAC;IACvE,MAAM,eAAe,GACnB,OAAO,EAAE,CAAC,aAAa,CAAC;QACxB,OAAO,EAAE,CAAC,aAAa,CAAC;QACvB,QAAQ,CAAC,UAA0C,CAAC;IAEvD,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,qCAAqC;IACrC,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,eAAe,GAAG,IAAI,CAAC;IAChC,CAAC;IAED,oCAAoC;IACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACpB,OAAO,OAAO,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,4BAA4B;IAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5C,OAAO,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3C,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,oDAAoD;IACpD,MAAM,gBAAgB,GAAG,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAChE,qCAAqC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,GAAG,gBAAgB,CAAC;IACvD,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,aAAqB,mBAAmB;IAExC,IAAI,SAA4B,CAAC;IAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAEtE,kCAAkC;YAClC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,SAAS,CAAC;YAClB,CAAC;YAED,gCAAgC;YAChC,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBACzB,0EAA0E;gBAC1E,MAAM,eAAe,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBACjD,MAAM,KAAK,GAAG,eAAe,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAC3D,MAAM,WAAW,GAAG,eAAe,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,qBAAqB,CAAC;gBACnF,GAAG,CACD,yBAAyB,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,KAAK;oBACzD,eAAe,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,WAAW,GAAG,CACxD,CAAC;gBACF,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,MAAM,IAAI,KAAK,CACb,6BAA6B,UAAU,GAAG,CAAC,cAAc,SAAS,EAAE,OAAO,IAAI,eAAe,EAAE,CACjG,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,EAAoB,EACpB,aAAqB,mBAAmB;IAExC,OAAO,aAAa,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,YAAY,GAAG,CAAC,CAAC;IACjB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACjB,YAAY,GAAG,KAAK,CAAC;IACrB,mBAAmB,GAAG,sBAAsB,CAAC;IAC7C,SAAS,GAAG,KAAK,CAAC;IAClB,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry for Dynamic MCP Tool Discovery
|
|
3
|
+
*
|
|
4
|
+
* Manages tool loading/unloading by tier and scope, enabling dynamic tool discovery
|
|
5
|
+
* and permission-based access control.
|
|
6
|
+
*
|
|
7
|
+
* @module services/tool-registry
|
|
8
|
+
*/
|
|
9
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
11
|
+
import type { ToolScope, ToolTier } from "../config/environment.js";
|
|
12
|
+
/**
|
|
13
|
+
* Re-export tier and scope types for convenience.
|
|
14
|
+
*/
|
|
15
|
+
export type { ToolTier, ToolScope };
|
|
16
|
+
/**
|
|
17
|
+
* MCP tool input schema (JSON Schema format).
|
|
18
|
+
*/
|
|
19
|
+
export interface ToolInputSchema {
|
|
20
|
+
type: "object";
|
|
21
|
+
properties: Record<string, unknown>;
|
|
22
|
+
required?: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Tool annotations for MCP clients.
|
|
26
|
+
*/
|
|
27
|
+
export interface ToolAnnotations {
|
|
28
|
+
title?: string;
|
|
29
|
+
readOnlyHint?: boolean;
|
|
30
|
+
destructiveHint?: boolean;
|
|
31
|
+
idempotentHint?: boolean;
|
|
32
|
+
openWorldHint?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* MCP tool definition returned to clients.
|
|
36
|
+
*/
|
|
37
|
+
export interface MCPToolDefinition {
|
|
38
|
+
name: string;
|
|
39
|
+
description: string;
|
|
40
|
+
inputSchema: ToolInputSchema;
|
|
41
|
+
annotations?: ToolAnnotations;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Tool response format from execute function.
|
|
45
|
+
* Re-exports SDK's CallToolResult for proper type compatibility.
|
|
46
|
+
*/
|
|
47
|
+
export type ToolResponse = CallToolResult;
|
|
48
|
+
/**
|
|
49
|
+
* Internal tool definition with metadata.
|
|
50
|
+
*/
|
|
51
|
+
export interface ToolDefinition {
|
|
52
|
+
/** Unique tool name (e.g., "send_email") */
|
|
53
|
+
name: string;
|
|
54
|
+
/** Human-readable description */
|
|
55
|
+
description: string;
|
|
56
|
+
/** JSON Schema for input validation */
|
|
57
|
+
inputSchema: ToolInputSchema;
|
|
58
|
+
/** Optional MCP annotations */
|
|
59
|
+
annotations?: ToolAnnotations;
|
|
60
|
+
/** Tool tier for loading priority */
|
|
61
|
+
tier: Exclude<ToolTier, "all">;
|
|
62
|
+
/** Required scopes for this tool */
|
|
63
|
+
scopes: ToolScope[];
|
|
64
|
+
/** Execute function for the tool */
|
|
65
|
+
execute: (args: unknown) => Promise<ToolResponse>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Registry statistics for debugging.
|
|
69
|
+
*/
|
|
70
|
+
export interface RegistryStats {
|
|
71
|
+
/** Total registered tools */
|
|
72
|
+
totalRegistered: number;
|
|
73
|
+
/** Currently enabled tools */
|
|
74
|
+
totalEnabled: number;
|
|
75
|
+
/** Tools by tier */
|
|
76
|
+
byTier: {
|
|
77
|
+
core: number;
|
|
78
|
+
secondary: number;
|
|
79
|
+
tertiary: number;
|
|
80
|
+
};
|
|
81
|
+
/** Enabled tools by tier */
|
|
82
|
+
enabledByTier: {
|
|
83
|
+
core: number;
|
|
84
|
+
secondary: number;
|
|
85
|
+
tertiary: number;
|
|
86
|
+
};
|
|
87
|
+
/** List of enabled tool names */
|
|
88
|
+
enabledTools: string[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Core tools - essential functionality (always available).
|
|
92
|
+
*/
|
|
93
|
+
export declare const CORE_TOOLS: string[];
|
|
94
|
+
/**
|
|
95
|
+
* Secondary tools - commonly used features.
|
|
96
|
+
*/
|
|
97
|
+
export declare const SECONDARY_TOOLS: string[];
|
|
98
|
+
/**
|
|
99
|
+
* Tertiary tools - advanced/admin features.
|
|
100
|
+
* NOTE: API key operations are EXCLUDED for security reasons.
|
|
101
|
+
*/
|
|
102
|
+
export declare const TERTIARY_TOOLS: string[];
|
|
103
|
+
/**
|
|
104
|
+
* Initialize the tool registry with an MCP server instance.
|
|
105
|
+
*
|
|
106
|
+
* @param server - MCP Server instance for notifications
|
|
107
|
+
* @param tools - Initial tools to register
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const server = new Server({ name: "resend-mcp" }, { capabilities: { tools: {} } });
|
|
112
|
+
* initializeRegistry(server, [sendEmailTool, listDomainsTool]);
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export declare function initializeRegistry(server: Server, tools?: ToolDefinition[]): void;
|
|
116
|
+
/**
|
|
117
|
+
* Register a tool in the registry.
|
|
118
|
+
*
|
|
119
|
+
* @param tool - Tool definition to register
|
|
120
|
+
*/
|
|
121
|
+
export declare function registerTool(tool: ToolDefinition): void;
|
|
122
|
+
/**
|
|
123
|
+
* Unregister a tool from the registry.
|
|
124
|
+
*
|
|
125
|
+
* @param name - Tool name to unregister
|
|
126
|
+
*/
|
|
127
|
+
export declare function unregisterTool(name: string): void;
|
|
128
|
+
/**
|
|
129
|
+
* Load all tools of a specific tier (and lower tiers).
|
|
130
|
+
*
|
|
131
|
+
* @param tier - Tier to load (includes all lower tiers)
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* loadTier("secondary"); // Loads core + secondary tools
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export declare function loadTier(tier: Exclude<ToolTier, "all">): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Unload all tools of a specific tier (keeps lower tiers).
|
|
141
|
+
*
|
|
142
|
+
* @param tier - Tier to unload
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* unloadTier("tertiary"); // Removes only tertiary tools
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare function unloadTier(tier: Exclude<ToolTier, "all">): Promise<void>;
|
|
150
|
+
/**
|
|
151
|
+
* Load tools by scope(s).
|
|
152
|
+
*
|
|
153
|
+
* @param scopes - Scopes to enable
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* loadByScope(["read", "write"]); // Enable tools with read or write scope
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
export declare function loadByScope(scopes: ToolScope[]): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Unload tools by scope(s).
|
|
163
|
+
*
|
|
164
|
+
* @param scopes - Scopes to disable
|
|
165
|
+
*/
|
|
166
|
+
export declare function unloadByScope(scopes: ToolScope[]): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* Get all currently enabled tools as MCP tool definitions.
|
|
169
|
+
*
|
|
170
|
+
* @returns Array of MCP tool definitions
|
|
171
|
+
*/
|
|
172
|
+
export declare function getEnabledTools(): MCPToolDefinition[];
|
|
173
|
+
/**
|
|
174
|
+
* Check if a tool is currently enabled.
|
|
175
|
+
*
|
|
176
|
+
* @param name - Tool name to check
|
|
177
|
+
* @returns True if tool is enabled
|
|
178
|
+
*/
|
|
179
|
+
export declare function isToolEnabled(name: string): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Get a tool definition by name.
|
|
182
|
+
*
|
|
183
|
+
* @param name - Tool name
|
|
184
|
+
* @returns Tool definition or undefined
|
|
185
|
+
*/
|
|
186
|
+
export declare function getTool(name: string): ToolDefinition | undefined;
|
|
187
|
+
/**
|
|
188
|
+
* Get a tool's execute function if the tool is enabled.
|
|
189
|
+
*
|
|
190
|
+
* @param name - Tool name
|
|
191
|
+
* @returns Execute function or undefined
|
|
192
|
+
*/
|
|
193
|
+
export declare function getToolExecutor(name: string): ((args: unknown) => Promise<ToolResponse>) | undefined;
|
|
194
|
+
/**
|
|
195
|
+
* Get registry statistics for debugging.
|
|
196
|
+
*
|
|
197
|
+
* @returns Registry statistics
|
|
198
|
+
*/
|
|
199
|
+
export declare function getRegistryStats(): RegistryStats;
|
|
200
|
+
/**
|
|
201
|
+
* Reset the registry to initial state.
|
|
202
|
+
* Useful for testing or reconfiguration.
|
|
203
|
+
*/
|
|
204
|
+
export declare function resetRegistry(): void;
|
|
205
|
+
/**
|
|
206
|
+
* Enable a specific tool by name.
|
|
207
|
+
*
|
|
208
|
+
* @param name - Tool name to enable
|
|
209
|
+
* @returns True if tool was enabled
|
|
210
|
+
*/
|
|
211
|
+
export declare function enableTool(name: string): Promise<boolean>;
|
|
212
|
+
/**
|
|
213
|
+
* Disable a specific tool by name.
|
|
214
|
+
*
|
|
215
|
+
* @param name - Tool name to disable
|
|
216
|
+
* @returns True if tool was disabled
|
|
217
|
+
*/
|
|
218
|
+
export declare function disableTool(name: string): Promise<boolean>;
|
|
219
|
+
//# sourceMappingURL=tool-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/services/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAKpE;;GAEG;AACH,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,eAAe,CAAC;IAC7B,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,WAAW,EAAE,eAAe,CAAC;IAC7B,+BAA+B;IAC/B,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qCAAqC;IACrC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/B,oCAAoC;IACpC,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,oCAAoC;IACpC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,4BAA4B;IAC5B,aAAa,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,iCAAiC;IACjC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAiCD;;GAEG;AACH,eAAO,MAAM,UAAU,UAMtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,UA8B3B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,UA4C1B,CAAC;AAMF;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,cAAc,EAAO,GAC3B,IAAI,CASN;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CASvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiBjD;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiC5E;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B9E;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBpE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBtE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,iBAAiB,EAAE,CAgBrD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,GACX,CAAC,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,SAAS,CAKxD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CA2BhD;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAe/D;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhE"}
|