@mainwp/mcp 1.0.0-beta.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 +674 -0
- package/README.md +1034 -0
- package/dist/abilities.d.ts +144 -0
- package/dist/abilities.d.ts.map +1 -0
- package/dist/abilities.js +529 -0
- package/dist/abilities.js.map +1 -0
- package/dist/config.d.ts +135 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +405 -0
- package/dist/config.js.map +1 -0
- package/dist/confirmation-responses.d.ts +44 -0
- package/dist/confirmation-responses.d.ts.map +1 -0
- package/dist/confirmation-responses.js +120 -0
- package/dist/confirmation-responses.js.map +1 -0
- package/dist/errors.d.ts +118 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +206 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +506 -0
- package/dist/index.js.map +1 -0
- package/dist/logging.d.ts +34 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +74 -0
- package/dist/logging.js.map +1 -0
- package/dist/naming.d.ts +23 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +37 -0
- package/dist/naming.js.map +1 -0
- package/dist/prompts.d.ts +22 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +414 -0
- package/dist/prompts.js.map +1 -0
- package/dist/retry.d.ts +77 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +206 -0
- package/dist/retry.js.map +1 -0
- package/dist/security.d.ts +41 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +154 -0
- package/dist/security.js.map +1 -0
- package/dist/tools.d.ts +82 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +861 -0
- package/dist/tools.js.map +1 -0
- package/package.json +73 -0
- package/settings.example.json +30 -0
- package/settings.schema.json +129 -0
package/dist/retry.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Logic for Transient Errors
|
|
3
|
+
*
|
|
4
|
+
* Provides exponential backoff with jitter for handling transient network
|
|
5
|
+
* failures and server errors (HTTP 5xx, 429, network errors).
|
|
6
|
+
*
|
|
7
|
+
* Key features:
|
|
8
|
+
* - Only retries transient errors (5xx, 429, network errors)
|
|
9
|
+
* - Permanent errors (4xx except 429) fail immediately
|
|
10
|
+
* - Timeout budget ensures total time never exceeds requestTimeout
|
|
11
|
+
* - Exponential backoff with jitter prevents thundering herd
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Extract HTTP status code from an error.
|
|
15
|
+
* Handles various error formats including fetch errors and custom error objects.
|
|
16
|
+
*/
|
|
17
|
+
function extractStatusCode(error) {
|
|
18
|
+
// Handle error objects with status property
|
|
19
|
+
if (error && typeof error === 'object') {
|
|
20
|
+
const errorObj = error;
|
|
21
|
+
// Direct status property (e.g., Response object or custom error)
|
|
22
|
+
if (typeof errorObj.status === 'number') {
|
|
23
|
+
return errorObj.status;
|
|
24
|
+
}
|
|
25
|
+
// Status in cause (chained errors)
|
|
26
|
+
if (errorObj.cause && typeof errorObj.cause === 'object') {
|
|
27
|
+
const cause = errorObj.cause;
|
|
28
|
+
if (typeof cause.status === 'number') {
|
|
29
|
+
return cause.status;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Extract from error message patterns
|
|
34
|
+
if (error instanceof Error) {
|
|
35
|
+
const message = error.message;
|
|
36
|
+
// Match patterns like "Failed to fetch: 503" or "HTTP 503"
|
|
37
|
+
const statusMatch = message.match(/\b([45]\d{2})\b/);
|
|
38
|
+
if (statusMatch) {
|
|
39
|
+
return parseInt(statusMatch[1], 10);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Extract error code from an error (e.g., ECONNRESET, ETIMEDOUT)
|
|
46
|
+
*/
|
|
47
|
+
function extractErrorCode(error) {
|
|
48
|
+
if (error && typeof error === 'object') {
|
|
49
|
+
const errorObj = error;
|
|
50
|
+
// Direct code property (Node.js errors)
|
|
51
|
+
if (typeof errorObj.code === 'string') {
|
|
52
|
+
return errorObj.code;
|
|
53
|
+
}
|
|
54
|
+
// Code in cause (chained errors)
|
|
55
|
+
if (errorObj.cause && typeof errorObj.cause === 'object') {
|
|
56
|
+
const cause = errorObj.cause;
|
|
57
|
+
if (typeof cause.code === 'string') {
|
|
58
|
+
return cause.code;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Extract from error message
|
|
63
|
+
if (error instanceof Error) {
|
|
64
|
+
const message = error.message.toUpperCase();
|
|
65
|
+
// Common network error codes
|
|
66
|
+
const networkCodes = ['ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'];
|
|
67
|
+
for (const code of networkCodes) {
|
|
68
|
+
if (message.includes(code)) {
|
|
69
|
+
return code;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Determine if an error is retryable (transient).
|
|
77
|
+
*
|
|
78
|
+
* Retryable errors:
|
|
79
|
+
* - HTTP 5xx (server errors)
|
|
80
|
+
* - HTTP 429 (rate limited)
|
|
81
|
+
* - Network errors: ECONNRESET, ECONNREFUSED, ETIMEDOUT, ENOTFOUND
|
|
82
|
+
*
|
|
83
|
+
* Non-retryable errors:
|
|
84
|
+
* - HTTP 4xx (except 429): client errors, auth failures, validation errors
|
|
85
|
+
* - AbortError: user cancellation
|
|
86
|
+
* - Any other errors (treat as permanent)
|
|
87
|
+
*/
|
|
88
|
+
export function isRetryableError(error) {
|
|
89
|
+
// AbortError is never retryable (user cancellation)
|
|
90
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// Check for HTTP status codes
|
|
94
|
+
const statusCode = extractStatusCode(error);
|
|
95
|
+
if (statusCode !== null) {
|
|
96
|
+
// 5xx server errors are retryable
|
|
97
|
+
if (statusCode >= 500 && statusCode <= 599) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
// 429 rate limited is retryable
|
|
101
|
+
if (statusCode === 429) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
// 4xx client errors (except 429) are NOT retryable
|
|
105
|
+
if (statusCode >= 400 && statusCode <= 499) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Check for network error codes
|
|
110
|
+
const errorCode = extractErrorCode(error);
|
|
111
|
+
if (errorCode !== null) {
|
|
112
|
+
const retryableCodes = ['ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'];
|
|
113
|
+
if (retryableCodes.includes(errorCode)) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Unknown errors are NOT retried (conservative approach)
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Calculate exponential backoff delay with jitter.
|
|
122
|
+
*
|
|
123
|
+
* Formula: min(maxDelay, baseDelay * 2^attempt + random(0, baseDelay))
|
|
124
|
+
*
|
|
125
|
+
* @param attempt - 0-indexed attempt number (0 for first retry, 1 for second, etc.)
|
|
126
|
+
* @param baseDelay - Base delay in milliseconds
|
|
127
|
+
* @param maxDelay - Maximum delay in milliseconds
|
|
128
|
+
* @returns Delay in milliseconds
|
|
129
|
+
*/
|
|
130
|
+
export function calculateBackoff(attempt, baseDelay, maxDelay) {
|
|
131
|
+
// Exponential: baseDelay * 2^attempt
|
|
132
|
+
const exponentialDelay = baseDelay * Math.pow(2, attempt);
|
|
133
|
+
// Jitter: random value between 0 and baseDelay
|
|
134
|
+
const jitter = Math.random() * baseDelay;
|
|
135
|
+
// Total delay with jitter
|
|
136
|
+
const totalDelay = exponentialDelay + jitter;
|
|
137
|
+
// Cap at maxDelay
|
|
138
|
+
return Math.min(totalDelay, maxDelay);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Execute an operation with retry logic.
|
|
142
|
+
*
|
|
143
|
+
* @param operation - The async operation to execute
|
|
144
|
+
* @param options - Retry configuration
|
|
145
|
+
* @returns The result of the operation
|
|
146
|
+
* @throws The last error if all retries are exhausted or a non-retryable error occurs
|
|
147
|
+
*/
|
|
148
|
+
export async function withRetry(operation, options) {
|
|
149
|
+
const { maxRetries, baseDelay, maxDelay, timeoutBudget, logger } = options;
|
|
150
|
+
const startTime = Date.now();
|
|
151
|
+
let lastError = null;
|
|
152
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
153
|
+
// Calculate remaining budget before each attempt
|
|
154
|
+
const elapsed = Date.now() - startTime;
|
|
155
|
+
const remainingBudget = timeoutBudget - elapsed;
|
|
156
|
+
// Check if budget is already exhausted before attempting
|
|
157
|
+
if (remainingBudget <= 0) {
|
|
158
|
+
const budgetError = new Error(`Retry timeout budget exhausted: ${Math.round(elapsed)}ms elapsed, budget was ${timeoutBudget}ms`);
|
|
159
|
+
if (lastError) {
|
|
160
|
+
budgetError.cause = lastError;
|
|
161
|
+
}
|
|
162
|
+
throw budgetError;
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
// Pass context with remaining budget so operation can enforce timeout
|
|
166
|
+
return await operation({ remainingBudget, attempt });
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
170
|
+
// Check if error is retryable
|
|
171
|
+
if (!isRetryableError(error)) {
|
|
172
|
+
throw lastError;
|
|
173
|
+
}
|
|
174
|
+
// Check if this was the last attempt
|
|
175
|
+
if (attempt >= maxRetries - 1) {
|
|
176
|
+
throw lastError;
|
|
177
|
+
}
|
|
178
|
+
// Calculate backoff delay
|
|
179
|
+
const backoffDelay = calculateBackoff(attempt, baseDelay, maxDelay);
|
|
180
|
+
// Re-calculate remaining budget after operation completed
|
|
181
|
+
const elapsedAfterOp = Date.now() - startTime;
|
|
182
|
+
const remainingBudgetAfterOp = timeoutBudget - elapsedAfterOp;
|
|
183
|
+
if (backoffDelay > remainingBudgetAfterOp) {
|
|
184
|
+
// Don't wait for a retry that would exceed the budget
|
|
185
|
+
const budgetError = new Error(`Retry timeout budget exceeded: would need ${Math.round(backoffDelay)}ms but only ${Math.round(remainingBudgetAfterOp)}ms remaining`);
|
|
186
|
+
// Preserve the original error as the cause
|
|
187
|
+
budgetError.cause = lastError;
|
|
188
|
+
throw budgetError;
|
|
189
|
+
}
|
|
190
|
+
// Log the retry attempt
|
|
191
|
+
if (logger) {
|
|
192
|
+
logger.warning('Retrying request after transient error', {
|
|
193
|
+
attempt: attempt + 1,
|
|
194
|
+
delay: Math.round(backoffDelay),
|
|
195
|
+
error: lastError.message,
|
|
196
|
+
remainingBudget: Math.round(remainingBudgetAfterOp),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// Wait before retrying
|
|
200
|
+
await new Promise(resolve => setTimeout(resolve, backoffDelay));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Should never reach here, but TypeScript doesn't know that
|
|
204
|
+
throw lastError || new Error('Retry exhausted with no error captured');
|
|
205
|
+
}
|
|
206
|
+
//# 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,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared security functions for input validation, error sanitization,
|
|
5
|
+
* and rate limiting.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validate input arguments before forwarding to the API.
|
|
9
|
+
* Prevents malicious payloads and enforces reasonable limits.
|
|
10
|
+
* Recurses into nested objects and arrays to enforce string length and ID range checks.
|
|
11
|
+
* Throws McpError with INVALID_PARAMS code on validation failure.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateInput(args: Record<string, unknown>, depth?: number): void;
|
|
14
|
+
/**
|
|
15
|
+
* Sanitize error messages before returning to clients.
|
|
16
|
+
* Removes potentially sensitive information like file paths, credentials, and stack traces.
|
|
17
|
+
*/
|
|
18
|
+
export declare function sanitizeError(message: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Token bucket rate limiter to prevent API abuse.
|
|
21
|
+
* Throttles requests to a configurable rate per minute.
|
|
22
|
+
*/
|
|
23
|
+
export declare class RateLimiter {
|
|
24
|
+
private tokens;
|
|
25
|
+
private lastRefill;
|
|
26
|
+
private readonly maxTokens;
|
|
27
|
+
private readonly refillRate;
|
|
28
|
+
constructor(requestsPerMinute: number);
|
|
29
|
+
/**
|
|
30
|
+
* Acquire a token, waiting if necessary.
|
|
31
|
+
* Returns immediately if rate limiting is disabled (maxTokens = 0).
|
|
32
|
+
* @param signal - Optional AbortSignal to cancel the wait
|
|
33
|
+
*/
|
|
34
|
+
acquire(signal?: AbortSignal): Promise<void>;
|
|
35
|
+
private refill;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if a value is a valid positive integer ID
|
|
39
|
+
*/
|
|
40
|
+
export declare function isValidId(value: unknown): boolean;
|
|
41
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,SAAI,GAAG,IAAI,CAwD5E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAiCrD;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,iBAAiB,EAAE,MAAM;IAOrC;;;;OAIG;IACG,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BlD,OAAO,CAAC,MAAM;CAMf;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASjD"}
|
package/dist/security.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared security functions for input validation, error sanitization,
|
|
5
|
+
* and rate limiting.
|
|
6
|
+
*/
|
|
7
|
+
import { McpErrorFactory } from './errors.js';
|
|
8
|
+
// Input validation limits
|
|
9
|
+
const MAX_STRING_LENGTH = 10000;
|
|
10
|
+
const MAX_ARRAY_ELEMENTS = 1000;
|
|
11
|
+
const MAX_OBJECT_DEPTH = 5;
|
|
12
|
+
/**
|
|
13
|
+
* Validate input arguments before forwarding to the API.
|
|
14
|
+
* Prevents malicious payloads and enforces reasonable limits.
|
|
15
|
+
* Recurses into nested objects and arrays to enforce string length and ID range checks.
|
|
16
|
+
* Throws McpError with INVALID_PARAMS code on validation failure.
|
|
17
|
+
*/
|
|
18
|
+
export function validateInput(args, depth = 0) {
|
|
19
|
+
if (depth > MAX_OBJECT_DEPTH) {
|
|
20
|
+
throw McpErrorFactory.invalidParams(`Input exceeds maximum nesting depth (${MAX_OBJECT_DEPTH})`, { maxDepth: MAX_OBJECT_DEPTH });
|
|
21
|
+
}
|
|
22
|
+
for (const [key, value] of Object.entries(args)) {
|
|
23
|
+
// String length check
|
|
24
|
+
if (typeof value === 'string' && value.length > MAX_STRING_LENGTH) {
|
|
25
|
+
throw McpErrorFactory.invalidParams(`Parameter "${key}" exceeds maximum length (${MAX_STRING_LENGTH} characters)`, { parameter: key, maxLength: MAX_STRING_LENGTH });
|
|
26
|
+
}
|
|
27
|
+
// ID fields: accept number or numeric string, must be positive integer
|
|
28
|
+
if (key.endsWith('_id')) {
|
|
29
|
+
const numValue = typeof value === 'string' ? parseInt(value, 10) : value;
|
|
30
|
+
if (typeof numValue === 'number') {
|
|
31
|
+
if (!Number.isInteger(numValue) || numValue < 1 || numValue > Number.MAX_SAFE_INTEGER) {
|
|
32
|
+
throw McpErrorFactory.invalidParams(`Parameter "${key}" must be a positive integer`, {
|
|
33
|
+
parameter: key,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Array validation
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
if (value.length > MAX_ARRAY_ELEMENTS) {
|
|
41
|
+
throw McpErrorFactory.invalidParams(`Parameter "${key}" has too many elements (max ${MAX_ARRAY_ELEMENTS})`, { parameter: key, maxElements: MAX_ARRAY_ELEMENTS, actualElements: value.length });
|
|
42
|
+
}
|
|
43
|
+
// Validate array elements (strings and nested objects)
|
|
44
|
+
for (const item of value) {
|
|
45
|
+
if (typeof item === 'string' && item.length > MAX_STRING_LENGTH) {
|
|
46
|
+
throw McpErrorFactory.invalidParams(`Element in "${key}" exceeds maximum length (${MAX_STRING_LENGTH} characters)`, { parameter: key, maxLength: MAX_STRING_LENGTH });
|
|
47
|
+
}
|
|
48
|
+
if (typeof item === 'object' && item !== null && !Array.isArray(item)) {
|
|
49
|
+
validateInput(item, depth + 1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Nested object: recurse to validate contents (string lengths, ID ranges, depth)
|
|
54
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
55
|
+
validateInput(value, depth + 1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Sanitize error messages before returning to clients.
|
|
61
|
+
* Removes potentially sensitive information like file paths, credentials, and stack traces.
|
|
62
|
+
*/
|
|
63
|
+
export function sanitizeError(message) {
|
|
64
|
+
return (message
|
|
65
|
+
// Remove absolute file paths (Unix: /home/..., /var/..., macOS: /Users/...)
|
|
66
|
+
.replace(/\/(Users|home|var|tmp|etc|usr|opt)\/[\w\-./]+/gi, '[path]')
|
|
67
|
+
// Remove Windows paths
|
|
68
|
+
.replace(/[A-Z]:\\[\w\-\\./]+/gi, '[path]')
|
|
69
|
+
// Remove credentials in URLs (user:pass@host)
|
|
70
|
+
.replace(/(https?:\/\/)[^:]+:[^@]+@/g, '$1[redacted]@')
|
|
71
|
+
// Remove Bearer tokens (Authorization: Bearer xxx)
|
|
72
|
+
.replace(/Bearer\s+[\w\-._~+/]+=*/gi, 'Bearer [redacted]')
|
|
73
|
+
// Remove potential tokens/keys in key=value patterns (handles quoted values with spaces)
|
|
74
|
+
// Matches: TOKEN=xxx, _TOKEN=xxx, MAINWP_TOKEN=xxx, password: "xxx", etc.
|
|
75
|
+
.replace(/\b(\w*(?:token|password|secret|key|auth|credential))[=:]\s*"[^"]*"/gi, '$1=[redacted]')
|
|
76
|
+
.replace(/\b(\w*(?:token|password|secret|key|auth|credential))[=:]\s*'[^']*'/gi, '$1=[redacted]')
|
|
77
|
+
.replace(/\b(\w*(?:token|password|secret|key|auth|credential))[=:]\s*[\w\-._~+/]+=*/gi, '$1=[redacted]')
|
|
78
|
+
// Remove stack traces (at Function.name (file:line:col))
|
|
79
|
+
.replace(/\s+at\s+.+\(.+:\d+:\d+\)/g, '')
|
|
80
|
+
// Remove Node.js internal paths
|
|
81
|
+
.replace(/\(node:[\w]+:\d+:\d+\)/g, '')
|
|
82
|
+
// Truncate to reasonable length
|
|
83
|
+
.slice(0, 500)
|
|
84
|
+
.trim());
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Token bucket rate limiter to prevent API abuse.
|
|
88
|
+
* Throttles requests to a configurable rate per minute.
|
|
89
|
+
*/
|
|
90
|
+
export class RateLimiter {
|
|
91
|
+
tokens;
|
|
92
|
+
lastRefill;
|
|
93
|
+
maxTokens;
|
|
94
|
+
refillRate; // tokens per ms
|
|
95
|
+
constructor(requestsPerMinute) {
|
|
96
|
+
this.maxTokens = requestsPerMinute;
|
|
97
|
+
this.tokens = requestsPerMinute;
|
|
98
|
+
this.refillRate = requestsPerMinute / 60000;
|
|
99
|
+
this.lastRefill = Date.now();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Acquire a token, waiting if necessary.
|
|
103
|
+
* Returns immediately if rate limiting is disabled (maxTokens = 0).
|
|
104
|
+
* @param signal - Optional AbortSignal to cancel the wait
|
|
105
|
+
*/
|
|
106
|
+
async acquire(signal) {
|
|
107
|
+
if (this.maxTokens === 0)
|
|
108
|
+
return; // Disabled
|
|
109
|
+
this.refill();
|
|
110
|
+
if (this.tokens < 1) {
|
|
111
|
+
if (signal?.aborted) {
|
|
112
|
+
throw new Error('Rate limiter acquire aborted');
|
|
113
|
+
}
|
|
114
|
+
const waitTime = Math.ceil((1 - this.tokens) / this.refillRate);
|
|
115
|
+
await new Promise((resolve, reject) => {
|
|
116
|
+
const timer = setTimeout(() => {
|
|
117
|
+
cleanup();
|
|
118
|
+
resolve();
|
|
119
|
+
}, waitTime);
|
|
120
|
+
const onAbort = () => {
|
|
121
|
+
clearTimeout(timer);
|
|
122
|
+
cleanup();
|
|
123
|
+
reject(new Error('Rate limiter acquire aborted'));
|
|
124
|
+
};
|
|
125
|
+
const cleanup = () => {
|
|
126
|
+
signal?.removeEventListener('abort', onAbort);
|
|
127
|
+
};
|
|
128
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
129
|
+
});
|
|
130
|
+
this.refill();
|
|
131
|
+
}
|
|
132
|
+
this.tokens -= 1;
|
|
133
|
+
}
|
|
134
|
+
refill() {
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
const elapsed = now - this.lastRefill;
|
|
137
|
+
this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
|
|
138
|
+
this.lastRefill = now;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if a value is a valid positive integer ID
|
|
143
|
+
*/
|
|
144
|
+
export function isValidId(value) {
|
|
145
|
+
if (typeof value === 'number') {
|
|
146
|
+
return Number.isInteger(value) && value >= 1 && value <= Number.MAX_SAFE_INTEGER;
|
|
147
|
+
}
|
|
148
|
+
if (typeof value === 'string') {
|
|
149
|
+
const num = parseInt(value, 10);
|
|
150
|
+
return !isNaN(num) && num >= 1 && num <= Number.MAX_SAFE_INTEGER;
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool Conversion
|
|
3
|
+
*
|
|
4
|
+
* Converts MainWP Abilities to MCP Tool definitions and handles
|
|
5
|
+
* tool execution by forwarding to the Abilities API.
|
|
6
|
+
*/
|
|
7
|
+
import { Tool, TextContent } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { AbilityAnnotations } from './abilities.js';
|
|
9
|
+
import { Config, SchemaVerbosity } from './config.js';
|
|
10
|
+
import { Logger } from './logging.js';
|
|
11
|
+
/**
|
|
12
|
+
* Check whether an error represents an idempotent no-op (already in desired state).
|
|
13
|
+
* Only matches 4xx HTTP errors with a recognized no-op error code.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export declare function isNoOpError(error: unknown): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Get the current cumulative session data usage in bytes and the configured limit.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getSessionDataUsage(config: Config): {
|
|
21
|
+
used: number;
|
|
22
|
+
limit: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Reset the cumulative session data counter to zero.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resetSessionData(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Clear pending previews (for testing only).
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export declare function clearPendingPreviews(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Options for tool execution
|
|
35
|
+
*/
|
|
36
|
+
export interface ExecuteToolOptions {
|
|
37
|
+
/** AbortSignal for cancellation support */
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generate contextual LLM instruction text from ability metadata.
|
|
42
|
+
*
|
|
43
|
+
* Produces safety guidance that tells the AI how to use a tool correctly:
|
|
44
|
+
* preview-first workflows, dry-run suggestions, or read-only assurance.
|
|
45
|
+
* API-provided instructions are prepended (they take priority).
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare function generateInstructions(meta: AbilityAnnotations | undefined, hasDryRun: boolean, hasConfirm: boolean): string;
|
|
49
|
+
/**
|
|
50
|
+
* Build safety tag string for tool descriptions.
|
|
51
|
+
*
|
|
52
|
+
* Standard mode: verbose tags like `[DESTRUCTIVE, Requires two-step confirmation]`
|
|
53
|
+
* Compact mode: short tags like `[destructive, confirm]`
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildSafetyTags(meta: AbilityAnnotations | undefined, hasDryRun: boolean, hasConfirm: boolean, verbosity: SchemaVerbosity): string;
|
|
57
|
+
/**
|
|
58
|
+
* Clear the cached tool list (for testing).
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export declare function clearToolsCache(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Fetch all MainWP abilities and convert them to MCP tools
|
|
64
|
+
*
|
|
65
|
+
* Applies optional filtering based on config:
|
|
66
|
+
* - allowedTools: If set, only include tools in this list
|
|
67
|
+
* - blockedTools: If set, exclude tools in this list
|
|
68
|
+
*
|
|
69
|
+
* Caches the converted tool list by abilities array reference and config
|
|
70
|
+
* fingerprint. fetchAbilities() returns the same cached array while valid,
|
|
71
|
+
* so reference equality is a reliable cache key.
|
|
72
|
+
*
|
|
73
|
+
* @param config - Server configuration
|
|
74
|
+
* @param logger - Optional structured logger for filtering/verbosity messages
|
|
75
|
+
*/
|
|
76
|
+
export declare function getTools(config: Config, logger?: Logger): Promise<Tool[]>;
|
|
77
|
+
export { abilityNameToToolName, toolNameToAbilityName } from './naming.js';
|
|
78
|
+
/**
|
|
79
|
+
* Execute an MCP tool call by forwarding to the corresponding ability
|
|
80
|
+
*/
|
|
81
|
+
export declare function executeTool(config: Config, toolName: string, args: Record<string, unknown>, logger: Logger, options?: ExecuteToolOptions): Promise<TextContent[]>;
|
|
82
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAEL,kBAAkB,EAInB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,eAAe,EAAc,MAAM,aAAa,CAAC;AAGlE,OAAO,EAAE,MAAM,EAAiB,MAAM,cAAc,CAAC;AAsErD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMnD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAEnF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C;AA6DD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAmKD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,kBAAkB,GAAG,SAAS,EACpC,SAAS,EAAE,OAAO,EAClB,UAAU,EAAE,OAAO,GAClB,MAAM,CAyBR;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,kBAAkB,GAAG,SAAS,EACpC,SAAS,EAAE,OAAO,EAClB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,eAAe,GACzB,MAAM,CAqBR;AA6GD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAmD/E;AAGD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAE3E;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,WAAW,EAAE,CAAC,CAwYxB"}
|