mcp-wordpress 2.4.2 → 2.5.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.
Files changed (348) hide show
  1. package/README.md +114 -48
  2. package/dist/ajv-patch.js +34 -0
  3. package/dist/cache/CacheInvalidation.d.ts +3 -1
  4. package/dist/cache/CacheInvalidation.d.ts.map +1 -1
  5. package/dist/cache/CacheInvalidation.js +10 -4
  6. package/dist/cache/CacheInvalidation.js.map +1 -1
  7. package/dist/cache/CacheManager.d.ts +3 -2
  8. package/dist/cache/CacheManager.d.ts.map +1 -1
  9. package/dist/cache/CacheManager.js +11 -3
  10. package/dist/cache/CacheManager.js.map +1 -1
  11. package/dist/cache/HttpCacheWrapper.d.ts +7 -6
  12. package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
  13. package/dist/cache/HttpCacheWrapper.js +8 -5
  14. package/dist/cache/HttpCacheWrapper.js.map +1 -1
  15. package/dist/cache/__tests__/HttpCacheWrapper.test.js +6 -5
  16. package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -1
  17. package/dist/cache/index.d.ts +3 -3
  18. package/dist/cache/index.d.ts.map +1 -1
  19. package/dist/cache/index.js +1 -1
  20. package/dist/cache/index.js.map +1 -1
  21. package/dist/client/CachedWordPressClient.d.ts +23 -9
  22. package/dist/client/CachedWordPressClient.d.ts.map +1 -1
  23. package/dist/client/CachedWordPressClient.js +4 -1
  24. package/dist/client/CachedWordPressClient.js.map +1 -1
  25. package/dist/client/MockWordPressClient.d.ts +2 -1
  26. package/dist/client/MockWordPressClient.d.ts.map +1 -1
  27. package/dist/client/MockWordPressClient.js +3 -1
  28. package/dist/client/MockWordPressClient.js.map +1 -1
  29. package/dist/client/api.d.ts +17 -13
  30. package/dist/client/api.d.ts.map +1 -1
  31. package/dist/client/api.js +135 -30
  32. package/dist/client/api.js.map +1 -1
  33. package/dist/client/auth.d.ts.map +1 -1
  34. package/dist/client/auth.js +2 -3
  35. package/dist/client/auth.js.map +1 -1
  36. package/dist/client/managers/AuthenticationManager.d.ts +55 -2
  37. package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
  38. package/dist/client/managers/AuthenticationManager.js +269 -71
  39. package/dist/client/managers/AuthenticationManager.js.map +1 -1
  40. package/dist/client/managers/BaseManager.d.ts +3 -3
  41. package/dist/client/managers/BaseManager.d.ts.map +1 -1
  42. package/dist/client/managers/BaseManager.js +11 -5
  43. package/dist/client/managers/BaseManager.js.map +1 -1
  44. package/dist/client/managers/RequestManager.d.ts +2 -2
  45. package/dist/client/managers/RequestManager.d.ts.map +1 -1
  46. package/dist/client/managers/RequestManager.js +25 -12
  47. package/dist/client/managers/RequestManager.js.map +1 -1
  48. package/dist/config/Config.d.ts +155 -0
  49. package/dist/config/Config.d.ts.map +1 -0
  50. package/dist/config/Config.js +215 -0
  51. package/dist/config/Config.js.map +1 -0
  52. package/dist/config/ConfigurationSchema.d.ts +21 -21
  53. package/dist/config/ConfigurationSchema.d.ts.map +1 -1
  54. package/dist/config/ConfigurationSchema.js +19 -2
  55. package/dist/config/ConfigurationSchema.js.map +1 -1
  56. package/dist/config/ServerConfiguration.d.ts +2 -1
  57. package/dist/config/ServerConfiguration.d.ts.map +1 -1
  58. package/dist/config/ServerConfiguration.js +50 -41
  59. package/dist/config/ServerConfiguration.js.map +1 -1
  60. package/dist/docs/DocumentationGenerator.d.ts +9 -8
  61. package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
  62. package/dist/docs/DocumentationGenerator.js +10 -7
  63. package/dist/docs/DocumentationGenerator.js.map +1 -1
  64. package/dist/docs/MarkdownFormatter.d.ts.map +1 -1
  65. package/dist/docs/MarkdownFormatter.js +3 -2
  66. package/dist/docs/MarkdownFormatter.js.map +1 -1
  67. package/dist/dxt-entry.cjs +81 -0
  68. package/dist/dxt-entry.js +15 -14
  69. package/dist/dxt-entry.js.map +1 -1
  70. package/dist/index.d.ts +3 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +37 -21
  73. package/dist/index.js.map +1 -1
  74. package/dist/performance/MetricsCollector.d.ts +13 -7
  75. package/dist/performance/MetricsCollector.d.ts.map +1 -1
  76. package/dist/performance/MetricsCollector.js +69 -27
  77. package/dist/performance/MetricsCollector.js.map +1 -1
  78. package/dist/performance/PerformanceAnalytics.d.ts +8 -2
  79. package/dist/performance/PerformanceAnalytics.d.ts.map +1 -1
  80. package/dist/performance/PerformanceAnalytics.js +17 -47
  81. package/dist/performance/PerformanceAnalytics.js.map +1 -1
  82. package/dist/performance/PerformanceMonitor.d.ts +2 -1
  83. package/dist/performance/PerformanceMonitor.d.ts.map +1 -1
  84. package/dist/performance/PerformanceMonitor.js +12 -13
  85. package/dist/performance/PerformanceMonitor.js.map +1 -1
  86. package/dist/performance/index.d.ts +2 -2
  87. package/dist/performance/index.d.ts.map +1 -1
  88. package/dist/security/AISecurityScanner.d.ts +1 -0
  89. package/dist/security/AISecurityScanner.d.ts.map +1 -1
  90. package/dist/security/AISecurityScanner.js +22 -12
  91. package/dist/security/AISecurityScanner.js.map +1 -1
  92. package/dist/security/AutomatedRemediation.d.ts +4 -3
  93. package/dist/security/AutomatedRemediation.d.ts.map +1 -1
  94. package/dist/security/AutomatedRemediation.js +46 -15
  95. package/dist/security/AutomatedRemediation.js.map +1 -1
  96. package/dist/security/InputValidator.d.ts +13 -9
  97. package/dist/security/InputValidator.d.ts.map +1 -1
  98. package/dist/security/InputValidator.js +4 -2
  99. package/dist/security/InputValidator.js.map +1 -1
  100. package/dist/security/SecurityCIPipeline.d.ts +1 -1
  101. package/dist/security/SecurityCIPipeline.d.ts.map +1 -1
  102. package/dist/security/SecurityCIPipeline.js +38 -29
  103. package/dist/security/SecurityCIPipeline.js.map +1 -1
  104. package/dist/security/SecurityConfig.d.ts +3 -3
  105. package/dist/security/SecurityConfig.d.ts.map +1 -1
  106. package/dist/security/SecurityConfig.js +13 -9
  107. package/dist/security/SecurityConfig.js.map +1 -1
  108. package/dist/security/SecurityConfigManager.d.ts +2 -2
  109. package/dist/security/SecurityConfigManager.d.ts.map +1 -1
  110. package/dist/security/SecurityConfigManager.js +20 -15
  111. package/dist/security/SecurityConfigManager.js.map +1 -1
  112. package/dist/security/SecurityMonitoring.d.ts +2 -2
  113. package/dist/security/SecurityMonitoring.d.ts.map +1 -1
  114. package/dist/security/SecurityMonitoring.js +19 -17
  115. package/dist/security/SecurityMonitoring.js.map +1 -1
  116. package/dist/security/SecurityReviewer.d.ts.map +1 -1
  117. package/dist/security/SecurityReviewer.js +10 -7
  118. package/dist/security/SecurityReviewer.js.map +1 -1
  119. package/dist/security/index.d.ts +24 -23
  120. package/dist/security/index.d.ts.map +1 -1
  121. package/dist/security/index.js +52 -23
  122. package/dist/security/index.js.map +1 -1
  123. package/dist/server/ConnectionTester.d.ts +12 -4
  124. package/dist/server/ConnectionTester.d.ts.map +1 -1
  125. package/dist/server/ConnectionTester.js +96 -22
  126. package/dist/server/ConnectionTester.js.map +1 -1
  127. package/dist/server/ToolRegistry.d.ts +2 -2
  128. package/dist/server/ToolRegistry.d.ts.map +1 -1
  129. package/dist/server/ToolRegistry.js +10 -5
  130. package/dist/server/ToolRegistry.js.map +1 -1
  131. package/dist/tools/BaseToolManager.d.ts +47 -11
  132. package/dist/tools/BaseToolManager.d.ts.map +1 -1
  133. package/dist/tools/BaseToolManager.js +168 -29
  134. package/dist/tools/BaseToolManager.js.map +1 -1
  135. package/dist/tools/auth.d.ts +16 -10
  136. package/dist/tools/auth.d.ts.map +1 -1
  137. package/dist/tools/auth.js +3 -2
  138. package/dist/tools/auth.js.map +1 -1
  139. package/dist/tools/cache.d.ts +30 -30
  140. package/dist/tools/cache.d.ts.map +1 -1
  141. package/dist/tools/cache.js +1 -6
  142. package/dist/tools/cache.js.map +1 -1
  143. package/dist/tools/comments.d.ts +20 -20
  144. package/dist/tools/comments.d.ts.map +1 -1
  145. package/dist/tools/comments.js +16 -9
  146. package/dist/tools/comments.js.map +1 -1
  147. package/dist/tools/media.d.ts +18 -16
  148. package/dist/tools/media.d.ts.map +1 -1
  149. package/dist/tools/media.js +16 -15
  150. package/dist/tools/media.js.map +1 -1
  151. package/dist/tools/pages.d.ts +19 -17
  152. package/dist/tools/pages.d.ts.map +1 -1
  153. package/dist/tools/pages.js +16 -12
  154. package/dist/tools/pages.js.map +1 -1
  155. package/dist/tools/performance.d.ts +11 -1
  156. package/dist/tools/performance.d.ts.map +1 -1
  157. package/dist/tools/performance.js +67 -34
  158. package/dist/tools/performance.js.map +1 -1
  159. package/dist/tools/posts/PostHandlers.d.ts +46 -0
  160. package/dist/tools/posts/PostHandlers.d.ts.map +1 -0
  161. package/dist/tools/posts/PostHandlers.js +400 -0
  162. package/dist/tools/posts/PostHandlers.js.map +1 -0
  163. package/dist/tools/posts/PostToolDefinitions.d.ts +37 -0
  164. package/dist/tools/posts/PostToolDefinitions.d.ts.map +1 -0
  165. package/dist/tools/posts/PostToolDefinitions.js +236 -0
  166. package/dist/tools/posts/PostToolDefinitions.js.map +1 -0
  167. package/dist/tools/posts/index.d.ts +138 -0
  168. package/dist/tools/posts/index.d.ts.map +1 -0
  169. package/dist/tools/posts/index.js +163 -0
  170. package/dist/tools/posts/index.js.map +1 -0
  171. package/dist/tools/posts.d.ts +10 -246
  172. package/dist/tools/posts.d.ts.map +1 -1
  173. package/dist/tools/posts.js +11 -723
  174. package/dist/tools/posts.js.map +1 -1
  175. package/dist/tools/site.d.ts +19 -18
  176. package/dist/tools/site.d.ts.map +1 -1
  177. package/dist/tools/site.js +14 -10
  178. package/dist/tools/site.js.map +1 -1
  179. package/dist/tools/taxonomies.d.ts +23 -24
  180. package/dist/tools/taxonomies.d.ts.map +1 -1
  181. package/dist/tools/taxonomies.js +24 -18
  182. package/dist/tools/taxonomies.js.map +1 -1
  183. package/dist/tools/users.d.ts +20 -15
  184. package/dist/tools/users.d.ts.map +1 -1
  185. package/dist/tools/users.js +12 -8
  186. package/dist/tools/users.js.map +1 -1
  187. package/dist/types/client.d.ts +48 -41
  188. package/dist/types/client.d.ts.map +1 -1
  189. package/dist/types/client.js +30 -5
  190. package/dist/types/client.js.map +1 -1
  191. package/dist/types/enhanced.d.ts +237 -0
  192. package/dist/types/enhanced.d.ts.map +1 -0
  193. package/dist/types/enhanced.js +49 -0
  194. package/dist/types/enhanced.js.map +1 -0
  195. package/dist/types/index.d.ts +15 -12
  196. package/dist/types/index.d.ts.map +1 -1
  197. package/dist/types/index.js +2 -0
  198. package/dist/types/index.js.map +1 -1
  199. package/dist/types/mcp.d.ts +12 -12
  200. package/dist/types/mcp.d.ts.map +1 -1
  201. package/dist/types/requests.d.ts +322 -0
  202. package/dist/types/requests.d.ts.map +1 -0
  203. package/dist/types/requests.js +8 -0
  204. package/dist/types/requests.js.map +1 -0
  205. package/dist/types/tools.d.ts +506 -0
  206. package/dist/types/tools.d.ts.map +1 -0
  207. package/dist/types/tools.js +8 -0
  208. package/dist/types/tools.js.map +1 -0
  209. package/dist/types/wordpress.d.ts +43 -15
  210. package/dist/types/wordpress.d.ts.map +1 -1
  211. package/dist/types/wordpress.js +8 -1
  212. package/dist/types/wordpress.js.map +1 -1
  213. package/dist/utils/debug.d.ts +19 -11
  214. package/dist/utils/debug.d.ts.map +1 -1
  215. package/dist/utils/debug.js +46 -10
  216. package/dist/utils/debug.js.map +1 -1
  217. package/dist/utils/enhancedError.d.ts +8 -8
  218. package/dist/utils/enhancedError.d.ts.map +1 -1
  219. package/dist/utils/enhancedError.js.map +1 -1
  220. package/dist/utils/error.d.ts +2 -4
  221. package/dist/utils/error.d.ts.map +1 -1
  222. package/dist/utils/error.js +42 -5
  223. package/dist/utils/error.js.map +1 -1
  224. package/dist/utils/logger.d.ts +106 -0
  225. package/dist/utils/logger.d.ts.map +1 -0
  226. package/dist/utils/logger.js +280 -0
  227. package/dist/utils/logger.js.map +1 -0
  228. package/dist/utils/streaming.d.ts +9 -9
  229. package/dist/utils/streaming.d.ts.map +1 -1
  230. package/dist/utils/streaming.js +71 -52
  231. package/dist/utils/streaming.js.map +1 -1
  232. package/dist/utils/toolWrapper.d.ts +9 -7
  233. package/dist/utils/toolWrapper.d.ts.map +1 -1
  234. package/dist/utils/toolWrapper.js.map +1 -1
  235. package/dist/utils/validation/core.d.ts +21 -0
  236. package/dist/utils/validation/core.d.ts.map +1 -0
  237. package/dist/utils/validation/core.js +71 -0
  238. package/dist/utils/validation/core.js.map +1 -0
  239. package/dist/utils/validation/index.d.ts +25 -0
  240. package/dist/utils/validation/index.d.ts.map +1 -0
  241. package/dist/utils/validation/index.js +29 -0
  242. package/dist/utils/validation/index.js.map +1 -0
  243. package/dist/utils/validation/network.d.ts +19 -0
  244. package/dist/utils/validation/network.d.ts.map +1 -0
  245. package/dist/utils/validation/network.js +93 -0
  246. package/dist/utils/validation/network.js.map +1 -0
  247. package/dist/utils/validation/rateLimit.d.ts +21 -0
  248. package/dist/utils/validation/rateLimit.d.ts.map +1 -0
  249. package/dist/utils/validation/rateLimit.js +43 -0
  250. package/dist/utils/validation/rateLimit.js.map +1 -0
  251. package/dist/utils/validation/security.d.ts +29 -0
  252. package/dist/utils/validation/security.d.ts.map +1 -0
  253. package/dist/utils/validation/security.js +327 -0
  254. package/dist/utils/validation/security.js.map +1 -0
  255. package/dist/utils/validation/wordpress.d.ts +31 -0
  256. package/dist/utils/validation/wordpress.d.ts.map +1 -0
  257. package/dist/utils/validation/wordpress.js +146 -0
  258. package/dist/utils/validation/wordpress.js.map +1 -0
  259. package/dist/utils/validation.d.ts +13 -82
  260. package/dist/utils/validation.d.ts.map +1 -1
  261. package/dist/utils/validation.js +25 -343
  262. package/dist/utils/validation.js.map +1 -1
  263. package/docs/BADGE_UPDATES.md +132 -0
  264. package/docs/CI_CD_IMPROVEMENTS.md +191 -0
  265. package/docs/INCREMENTAL_COVERAGE.md +183 -0
  266. package/docs/api/README.md +3 -1
  267. package/docs/api/openapi.json +5 -1
  268. package/docs/api/summary.json +1 -1
  269. package/docs/api/tools/wp_create_post.md +12 -14
  270. package/docs/examples/claude-desktop-config.md +1 -1
  271. package/docs/examples/docker-production.md +100 -93
  272. package/docs/examples/multi-site-setup.md +5 -4
  273. package/docs/examples/single-site-setup.md +3 -4
  274. package/docs/examples/use-case-workflows.md +4 -5
  275. package/docs/integrations/claude-desktop.md +31 -31
  276. package/docs/integrations/cline.md +4 -4
  277. package/docs/integrations/vs-code.md +9 -8
  278. package/docs/user-guides/SMITHERY_SETUP.md +10 -10
  279. package/package.json +44 -25
  280. package/src/cache/CacheInvalidation.ts +12 -5
  281. package/src/cache/CacheManager.ts +18 -15
  282. package/src/cache/HttpCacheWrapper.ts +30 -59
  283. package/src/cache/__tests__/HttpCacheWrapper.test.ts +6 -5
  284. package/src/cache/index.ts +3 -14
  285. package/src/client/CachedWordPressClient.ts +32 -30
  286. package/src/client/MockWordPressClient.ts +4 -2
  287. package/src/client/api.ts +186 -64
  288. package/src/client/auth.ts +15 -40
  289. package/src/client/managers/AuthenticationManager.ts +337 -77
  290. package/src/client/managers/BaseManager.ts +18 -30
  291. package/src/client/managers/RequestManager.ts +39 -44
  292. package/src/config/Config.ts +308 -0
  293. package/src/config/ConfigurationSchema.ts +23 -2
  294. package/src/config/ServerConfiguration.ts +51 -47
  295. package/src/docs/DocumentationGenerator.ts +50 -39
  296. package/src/docs/MarkdownFormatter.ts +19 -29
  297. package/src/dxt-entry.cjs +26 -16
  298. package/src/dxt-entry.ts +17 -27
  299. package/src/index.ts +42 -28
  300. package/src/performance/MetricsCollector.ts +108 -86
  301. package/src/performance/PerformanceAnalytics.ts +69 -164
  302. package/src/performance/PerformanceMonitor.ts +32 -47
  303. package/src/performance/index.ts +2 -10
  304. package/src/security/AISecurityScanner.ts +22 -12
  305. package/src/security/AutomatedRemediation.ts +49 -18
  306. package/src/security/InputValidator.ts +9 -6
  307. package/src/security/SecurityCIPipeline.ts +53 -37
  308. package/src/security/SecurityConfig.ts +22 -22
  309. package/src/security/SecurityConfigManager.ts +23 -19
  310. package/src/security/SecurityMonitoring.ts +24 -21
  311. package/src/security/SecurityReviewer.ts +10 -7
  312. package/src/security/index.ts +64 -29
  313. package/src/server/ConnectionTester.ts +120 -31
  314. package/src/server/ToolRegistry.ts +31 -21
  315. package/src/tools/BaseToolManager.ts +286 -33
  316. package/src/tools/auth.ts +20 -8
  317. package/src/tools/cache.ts +5 -15
  318. package/src/tools/comments.ts +34 -48
  319. package/src/tools/media.ts +41 -53
  320. package/src/tools/pages.ts +32 -54
  321. package/src/tools/performance.ts +141 -176
  322. package/src/tools/posts/PostHandlers.ts +474 -0
  323. package/src/tools/posts/PostToolDefinitions.ts +250 -0
  324. package/src/tools/posts/index.ts +192 -0
  325. package/src/tools/posts.ts +24 -780
  326. package/src/tools/site.ts +34 -19
  327. package/src/tools/taxonomies.ts +41 -57
  328. package/src/tools/users.ts +28 -16
  329. package/src/types/client.ts +114 -138
  330. package/src/types/enhanced.ts +318 -0
  331. package/src/types/index.ts +51 -30
  332. package/src/types/mcp.ts +20 -42
  333. package/src/types/requests.ts +378 -0
  334. package/src/types/tools.ts +608 -0
  335. package/src/types/wordpress.ts +56 -34
  336. package/src/utils/debug.ts +77 -59
  337. package/src/utils/enhancedError.ts +8 -8
  338. package/src/utils/error.ts +53 -31
  339. package/src/utils/logger.ts +351 -0
  340. package/src/utils/streaming.ts +86 -68
  341. package/src/utils/toolWrapper.ts +10 -12
  342. package/src/utils/validation/core.ts +108 -0
  343. package/src/utils/validation/index.ts +36 -0
  344. package/src/utils/validation/network.ts +132 -0
  345. package/src/utils/validation/rateLimit.ts +54 -0
  346. package/src/utils/validation/security.ts +361 -0
  347. package/src/utils/validation/wordpress.ts +180 -0
  348. package/src/utils/validation.ts +47 -470
@@ -1,66 +1,319 @@
1
1
  /**
2
- * Base utility class for tool managers to reduce code duplication
2
+ * Base utility class for tool managers with enhanced type safety
3
3
  */
4
4
 
5
5
  import { getErrorMessage } from "../utils/error.js";
6
+ import { WordPressId, createWordPressId, DeepReadonly, Result, createSuccess, createError } from "../types/enhanced.js";
7
+
8
+ interface EnhancedError extends Error {
9
+ originalError?: unknown;
10
+ operation?: string;
11
+ context?: Record<string, unknown> | undefined;
12
+ timestamp?: Date;
13
+ }
14
+
15
+ export interface ParameterValidationRule<T = unknown> {
16
+ readonly key: string;
17
+ readonly required: boolean;
18
+ readonly type?: string;
19
+ readonly validator?: (value: unknown) => value is T;
20
+ readonly transformer?: (value: unknown) => T;
21
+ readonly errorMessage?: string;
22
+ }
23
+
24
+ export interface CacheKeyOptions {
25
+ readonly namespace?: string;
26
+ readonly includeTimestamp?: boolean;
27
+ readonly customHasher?: (params: Record<string, unknown>) => string;
28
+ }
6
29
 
7
30
  export class BaseToolUtils {
8
31
  /**
9
- * Validate required parameters
32
+ * Validate required parameters with enhanced type safety
33
+ */
34
+ static validateParams<T extends Record<string, unknown>>(
35
+ params: unknown,
36
+ rules: readonly ParameterValidationRule[]
37
+ ): Result<T, Error> {
38
+ if (!params || typeof params !== 'object' || Array.isArray(params)) {
39
+ return createError(new ValidationError('Parameters must be a non-null object', 'params', params));
40
+ }
41
+
42
+ const typedParams = params as Record<string, unknown>;
43
+ const errors: Error[] = [];
44
+
45
+ for (const rule of rules) {
46
+ const value = typedParams[rule.key];
47
+ const exists = rule.key in typedParams;
48
+
49
+ // Check required fields
50
+ if (rule.required && (!exists || value === undefined || value === null)) {
51
+ errors.push(new ValidationError(
52
+ rule.errorMessage || `Missing required parameter: ${rule.key}`,
53
+ rule.key,
54
+ value
55
+ ));
56
+ continue;
57
+ }
58
+
59
+ // Skip optional fields that don't exist
60
+ if (!rule.required && !exists) {
61
+ continue;
62
+ }
63
+
64
+ // Type validation
65
+ if (rule.type && typeof value !== rule.type) {
66
+ errors.push(new ValidationError(
67
+ `Parameter ${rule.key} must be of type ${rule.type}, got ${typeof value}`,
68
+ rule.key,
69
+ value
70
+ ));
71
+ continue;
72
+ }
73
+
74
+ // Custom validation
75
+ if (rule.validator && !rule.validator(value)) {
76
+ errors.push(new ValidationError(
77
+ rule.errorMessage || `Parameter ${rule.key} failed validation`,
78
+ rule.key,
79
+ value
80
+ ));
81
+ continue;
82
+ }
83
+
84
+ // Transform value if transformer provided
85
+ if (rule.transformer) {
86
+ try {
87
+ typedParams[rule.key] = rule.transformer(value);
88
+ } catch (error) {
89
+ errors.push(new ValidationError(
90
+ `Failed to transform parameter ${rule.key}: ${getErrorMessage(error)}`,
91
+ rule.key,
92
+ value
93
+ ));
94
+ }
95
+ }
96
+ }
97
+
98
+ if (errors.length > 0) {
99
+ return createError(errors[0]); // Return first error for simplicity
100
+ }
101
+
102
+ return createSuccess(typedParams as T);
103
+ }
104
+
105
+ /**
106
+ * Validate ID parameter with WordPress ID branding
10
107
  */
11
- static validateParams(params: Record<string, any>, required: string[]): void {
12
- for (const field of required) {
13
- if (
14
- !(field in params) ||
15
- params[field] === undefined ||
16
- params[field] === null
17
- ) {
18
- throw new Error(`Missing required parameter: ${field}`);
108
+ static validateId(id: unknown, name = "id"): Result<WordPressId, Error> {
109
+ try {
110
+ const numId = Number(id);
111
+ if (!Number.isInteger(numId) || numId <= 0) {
112
+ return createError(new ValidationError(
113
+ `Invalid ${name}: must be a positive integer`,
114
+ name,
115
+ id
116
+ ));
19
117
  }
118
+ return createSuccess(createWordPressId(numId));
119
+ } catch (error) {
120
+ return createError(new ValidationError(
121
+ `Invalid ${name}: ${getErrorMessage(error)}`,
122
+ name,
123
+ id
124
+ ));
20
125
  }
21
126
  }
22
127
 
23
128
  /**
24
- * Validate ID parameter
129
+ * Validate multiple IDs at once
25
130
  */
26
- static validateId(id: unknown, name = "id"): number {
27
- const numId = Number(id);
28
- if (!Number.isInteger(numId) || numId <= 0) {
29
- throw new Error(`Invalid ${name}: must be a positive integer`);
131
+ static validateIds(ids: unknown[], name = "ids"): Result<readonly WordPressId[], Error> {
132
+ const validatedIds: WordPressId[] = [];
133
+
134
+ for (let i = 0; i < ids.length; i++) {
135
+ const result = this.validateId(ids[i], `${name}[${i}]`);
136
+ if (!result.success) {
137
+ return result;
138
+ }
139
+ validatedIds.push(result.data);
30
140
  }
31
- return numId;
141
+
142
+ return createSuccess(validatedIds as readonly WordPressId[]);
32
143
  }
33
144
 
34
145
  /**
35
- * Handle errors consistently across all tools
146
+ * Handle errors consistently with enhanced error context
36
147
  */
37
- static handleError(error: unknown, operation: string): string {
148
+ static handleError(error: unknown, operation: string, context?: Record<string, unknown> | undefined): Error {
38
149
  const errorMessage = getErrorMessage(error);
39
- return `Error in ${operation}: ${errorMessage}`;
150
+ const enhancedMessage = `Error in ${operation}: ${errorMessage}`;
151
+
152
+ const enhancedError = new Error(enhancedMessage) as EnhancedError;
153
+ enhancedError.originalError = error;
154
+ enhancedError.operation = operation;
155
+ enhancedError.context = context;
156
+ enhancedError.timestamp = new Date();
157
+
158
+ return enhancedError;
40
159
  }
41
160
 
42
161
  /**
43
- * Cache key generation helper
162
+ * Generate cache keys with enhanced options
44
163
  */
45
164
  static generateCacheKey(
46
- operation: string,
47
- params: Record<string, unknown>,
165
+ operation: string,
166
+ params: DeepReadonly<Record<string, unknown>>,
167
+ options: CacheKeyOptions = {}
48
168
  ): string {
169
+ const {
170
+ namespace = 'wp',
171
+ includeTimestamp = false,
172
+ customHasher
173
+ } = options;
174
+
49
175
  const site = params.site || "default";
50
- const paramStr = Object.entries(params)
51
- .filter(([key]) => key !== "site")
52
- .sort(([a], [b]) => a.localeCompare(b))
53
- .map(([key, value]) => `${key}:${value}`)
54
- .join("|");
55
- return `${site}:${operation}:${paramStr}`;
176
+
177
+ let paramStr: string;
178
+ if (customHasher) {
179
+ paramStr = customHasher(params as Record<string, unknown>);
180
+ } else {
181
+ paramStr = Object.entries(params)
182
+ .filter(([key]) => key !== "site")
183
+ .sort(([a], [b]) => a.localeCompare(b))
184
+ .map(([key, value]) => `${key}:${JSON.stringify(value)}`)
185
+ .join("|");
186
+ }
187
+
188
+ let cacheKey = `${namespace}:${site}:${operation}:${paramStr}`;
189
+
190
+ if (includeTimestamp) {
191
+ const timestamp = Math.floor(Date.now() / 1000);
192
+ cacheKey += `:${timestamp}`;
193
+ }
194
+
195
+ return cacheKey;
56
196
  }
57
197
 
58
198
  /**
59
- * Format consistent response messages
199
+ * Format consistent success response messages
60
200
  */
61
- static formatSuccessMessage(operation: string, details?: string): string {
62
- return details
63
- ? `${operation}: ${details}`
64
- : `${operation} completed successfully`;
201
+ static formatSuccessMessage(operation: string, details?: string, count?: number): string {
202
+ let message = operation;
203
+
204
+ if (count !== undefined) {
205
+ message += ` (${count} ${count === 1 ? 'item' : 'items'})`;
206
+ }
207
+
208
+ if (details) {
209
+ message += `: ${details}`;
210
+ } else {
211
+ message += " completed successfully";
212
+ }
213
+
214
+ return message;
215
+ }
216
+
217
+ /**
218
+ * Validate string parameters with enhanced checks
219
+ */
220
+ static validateString(
221
+ value: unknown,
222
+ name: string,
223
+ options: {
224
+ readonly required?: boolean;
225
+ readonly minLength?: number;
226
+ readonly maxLength?: number;
227
+ readonly pattern?: RegExp;
228
+ readonly allowEmpty?: boolean;
229
+ } = {}
230
+ ): Result<string, Error> {
231
+ const { required = true, minLength, maxLength, pattern, allowEmpty = false } = options;
232
+
233
+ if (value === undefined || value === null) {
234
+ if (required) {
235
+ return createError(new ValidationError(`${name} is required`, name, value));
236
+ }
237
+ return createSuccess('');
238
+ }
239
+
240
+ if (typeof value !== 'string') {
241
+ return createError(new ValidationError(`${name} must be a string`, name, value));
242
+ }
243
+
244
+ if (!allowEmpty && value.trim().length === 0) {
245
+ return createError(new ValidationError(`${name} cannot be empty`, name, value));
246
+ }
247
+
248
+ if (minLength !== undefined && value.length < minLength) {
249
+ return createError(new ValidationError(
250
+ `${name} must be at least ${minLength} characters long`,
251
+ name,
252
+ value
253
+ ));
254
+ }
255
+
256
+ if (maxLength !== undefined && value.length > maxLength) {
257
+ return createError(new ValidationError(
258
+ `${name} must be no more than ${maxLength} characters long`,
259
+ name,
260
+ value
261
+ ));
262
+ }
263
+
264
+ if (pattern && !pattern.test(value)) {
265
+ return createError(new ValidationError(
266
+ `${name} does not match required pattern`,
267
+ name,
268
+ value
269
+ ));
270
+ }
271
+
272
+ return createSuccess(value);
273
+ }
274
+
275
+ /**
276
+ * Type-safe parameter extraction
277
+ */
278
+ static extractParam<T>(
279
+ params: DeepReadonly<Record<string, unknown>>,
280
+ key: string,
281
+ defaultValue?: T
282
+ ): T | undefined {
283
+ const value = params[key];
284
+ return value !== undefined ? value as T : defaultValue;
285
+ }
286
+
287
+ /**
288
+ * Safe array extraction with type validation
289
+ */
290
+ static extractArray<T>(
291
+ params: DeepReadonly<Record<string, unknown>>,
292
+ key: string,
293
+ itemValidator?: (item: unknown) => item is T
294
+ ): readonly T[] {
295
+ const value = params[key];
296
+
297
+ if (!Array.isArray(value)) {
298
+ return [];
299
+ }
300
+
301
+ if (itemValidator) {
302
+ return value.filter(itemValidator);
303
+ }
304
+
305
+ return value as readonly T[];
306
+ }
307
+ }
308
+
309
+ // Custom ValidationError class for enhanced error handling
310
+ class ValidationError extends Error {
311
+ constructor(
312
+ message: string,
313
+ public readonly field: string,
314
+ public readonly value: unknown
315
+ ) {
316
+ super(message);
317
+ this.name = 'ValidationError';
65
318
  }
66
319
  }
package/src/tools/auth.ts CHANGED
@@ -11,7 +11,12 @@ export class AuthTools {
11
11
  * Retrieves the list of authentication tools.
12
12
  * @returns An array of MCPTool definitions.
13
13
  */
14
- public getTools(): any[] {
14
+ public getTools(): Array<{
15
+ name: string;
16
+ description: string;
17
+ parameters?: Array<{ name: string; type?: string; description?: string; required?: boolean; enum?: string[]; items?: unknown }>;
18
+ handler: (client: WordPressClient, params: Record<string, unknown>) => Promise<unknown>;
19
+ }> {
15
20
  return [
16
21
  {
17
22
  name: "wp_test_auth",
@@ -71,7 +76,10 @@ export class AuthTools {
71
76
  * @param params - The parameters for the tool request.
72
77
  * @returns A promise that resolves to an MCPToolResponse.
73
78
  */
74
- public async handleTestAuth(client: WordPressClient, params: any): Promise<any> {
79
+ public async handleTestAuth(
80
+ client: WordPressClient,
81
+ params: Record<string, unknown>,
82
+ ): Promise<Record<string, unknown>> {
75
83
  try {
76
84
  await client.ping();
77
85
  const user = await client.getCurrentUser();
@@ -85,7 +93,7 @@ export class AuthTools {
85
93
  `**Roles:** ${user.roles?.join(", ") || "N/A"}\n\n` +
86
94
  "Your WordPress connection is working properly.";
87
95
 
88
- return content;
96
+ return { content };
89
97
  } catch (error) {
90
98
  throw new Error(`Authentication test failed: ${getErrorMessage(error)}`);
91
99
  }
@@ -98,7 +106,10 @@ export class AuthTools {
98
106
  * @param params - The parameters for the tool request.
99
107
  * @returns A promise that resolves to an MCPToolResponse.
100
108
  */
101
- public async handleGetAuthStatus(client: WordPressClient, params: any): Promise<any> {
109
+ public async handleGetAuthStatus(
110
+ client: WordPressClient,
111
+ params: Record<string, unknown>,
112
+ ): Promise<Record<string, unknown>> {
102
113
  try {
103
114
  const isAuthenticated = client.isAuthenticated;
104
115
  const config = client.config;
@@ -114,7 +125,7 @@ export class AuthTools {
114
125
  content += "**Status:** Not connected. Use 'wp_test_auth' to connect and verify credentials.";
115
126
  }
116
127
 
117
- return content;
128
+ return { content };
118
129
  } catch (error) {
119
130
  throw new Error(`Failed to get auth status: ${getErrorMessage(error)}`);
120
131
  }
@@ -129,13 +140,14 @@ export class AuthTools {
129
140
  */
130
141
  public async handleSwitchAuthMethod(
131
142
  client: WordPressClient,
132
- params: {
143
+ params: Record<string, unknown>,
144
+ ): Promise<unknown> {
145
+ const { method: _method, username: _username, password: _password, jwt_token: _jwt_token } = params as {
133
146
  method: AuthMethod;
134
147
  username?: string;
135
148
  password?: string;
136
149
  jwt_token?: string;
137
- },
138
- ): Promise<any> {
150
+ };
139
151
  try {
140
152
  // This functionality is not currently supported as the client
141
153
  // doesn't have an updateAuthConfig method
@@ -43,8 +43,7 @@ export class CacheTools {
43
43
  {
44
44
  name: "pattern",
45
45
  type: "string",
46
- description:
47
- 'Optional pattern to clear specific cache entries (e.g., "posts", "categories").',
46
+ description: 'Optional pattern to clear specific cache entries (e.g., "posts", "categories").',
48
47
  },
49
48
  ],
50
49
  handler: this.handleClearCache.bind(this),
@@ -86,8 +85,7 @@ export class CacheTools {
86
85
  if (!(client instanceof CachedWordPressClient)) {
87
86
  return {
88
87
  caching_enabled: false,
89
- message:
90
- "Caching is disabled for this site. Set DISABLE_CACHE=false to enable caching.",
88
+ message: "Caching is disabled for this site. Set DISABLE_CACHE=false to enable caching.",
91
89
  };
92
90
  }
93
91
 
@@ -168,12 +166,7 @@ export class CacheTools {
168
166
  success: true,
169
167
  message: "Cache warmed with essential WordPress data.",
170
168
  cache_entries_after_warming: stats.cache.totalSize,
171
- warmed_data: [
172
- "Current user information",
173
- "Categories",
174
- "Tags",
175
- "Site settings",
176
- ],
169
+ warmed_data: ["Current user information", "Categories", "Tags", "Site settings"],
177
170
  };
178
171
  });
179
172
  }
@@ -189,8 +182,7 @@ export class CacheTools {
189
182
  return {
190
183
  caching_enabled: false,
191
184
  message: "Caching is disabled for this site.",
192
- how_to_enable:
193
- "Remove DISABLE_CACHE=true from environment variables or set it to false.",
185
+ how_to_enable: "Remove DISABLE_CACHE=true from environment variables or set it to false.",
194
186
  };
195
187
  }
196
188
 
@@ -251,9 +243,7 @@ export class CacheTools {
251
243
 
252
244
  const client = this.clients.get(siteId);
253
245
  if (!client) {
254
- throw new Error(
255
- `Site "${siteId}" not found. Available sites: ${Array.from(this.clients.keys()).join(", ")}`,
256
- );
246
+ throw new Error(`Site "${siteId}" not found. Available sites: ${Array.from(this.clients.keys()).join(", ")}`);
257
247
  }
258
248
 
259
249
  return client;
@@ -1,9 +1,5 @@
1
1
  import { WordPressClient } from "../client/api.js";
2
- import {
3
- CommentQueryParams,
4
- CreateCommentRequest,
5
- UpdateCommentRequest,
6
- } from "../types/wordpress.js";
2
+ import { CommentQueryParams, CreateCommentRequest, UpdateCommentRequest } from "../types/wordpress.js";
7
3
  import { getErrorMessage } from "../utils/error.js";
8
4
 
9
5
  /**
@@ -15,7 +11,12 @@ export class CommentTools {
15
11
  * Retrieves the list of comment management tools.
16
12
  * @returns An array of MCPTool definitions.
17
13
  */
18
- public getTools(): any[] {
14
+ public getTools(): Array<{
15
+ name: string;
16
+ description: string;
17
+ parameters?: Array<{ name: string; type?: string; description?: string; required?: boolean; enum?: string[]; items?: unknown }>;
18
+ handler: (client: WordPressClient, params: Record<string, unknown>) => Promise<unknown>;
19
+ }> {
19
20
  return [
20
21
  {
21
22
  name: "wp_list_comments",
@@ -24,8 +25,7 @@ export class CommentTools {
24
25
  {
25
26
  name: "post",
26
27
  type: "number",
27
- description:
28
- "Limit results to comments assigned to a specific post ID.",
28
+ description: "Limit results to comments assigned to a specific post ID.",
29
29
  },
30
30
  {
31
31
  name: "status",
@@ -115,8 +115,7 @@ export class CommentTools {
115
115
  {
116
116
  name: "force",
117
117
  type: "boolean",
118
- description:
119
- "If true, the comment will be permanently deleted. Defaults to false (moved to trash).",
118
+ description: "If true, the comment will be permanently deleted. Defaults to false (moved to trash).",
120
119
  },
121
120
  ],
122
121
  handler: this.handleDeleteComment.bind(this),
@@ -150,12 +149,10 @@ export class CommentTools {
150
149
  ];
151
150
  }
152
151
 
153
- public async handleListComments(
154
- client: WordPressClient,
155
- params: CommentQueryParams,
156
- ): Promise<any> {
152
+ public async handleListComments(client: WordPressClient, params: Record<string, unknown>): Promise<unknown> {
153
+ const queryParams = params as CommentQueryParams;
157
154
  try {
158
- const comments = await client.getComments(params);
155
+ const comments = await client.getComments(queryParams);
159
156
  if (comments.length === 0) {
160
157
  return "No comments found matching the criteria.";
161
158
  }
@@ -173,12 +170,10 @@ export class CommentTools {
173
170
  }
174
171
  }
175
172
 
176
- public async handleGetComment(
177
- client: WordPressClient,
178
- params: { id: number },
179
- ): Promise<any> {
173
+ public async handleGetComment(client: WordPressClient, params: Record<string, unknown>): Promise<unknown> {
180
174
  try {
181
- const comment = await client.getComment(params.id);
175
+ const { id } = params as { id: number };
176
+ const comment = await client.getComment(id);
182
177
  const content =
183
178
  `**Comment Details (ID: ${comment.id})**\n\n` +
184
179
  `- **Author:** ${comment.author_name}\n` +
@@ -192,12 +187,10 @@ export class CommentTools {
192
187
  }
193
188
  }
194
189
 
195
- public async handleCreateComment(
196
- client: WordPressClient,
197
- params: CreateCommentRequest,
198
- ): Promise<any> {
190
+ public async handleCreateComment(client: WordPressClient, params: Record<string, unknown>): Promise<unknown> {
191
+ const createParams = params as unknown as CreateCommentRequest;
199
192
  try {
200
- const comment = await client.createComment(params);
193
+ const comment = await client.createComment(createParams);
201
194
  return `✅ Comment created successfully with ID: ${comment.id}`;
202
195
  } catch (error) {
203
196
  throw new Error(`Failed to create comment: ${getErrorMessage(error)}`);
@@ -206,36 +199,33 @@ export class CommentTools {
206
199
 
207
200
  public async handleUpdateComment(
208
201
  client: WordPressClient,
209
- params: UpdateCommentRequest & { id: number },
210
- ): Promise<any> {
202
+ params: Record<string, unknown>,
203
+ ): Promise<unknown> {
211
204
  try {
212
- const comment = await client.updateComment(params);
205
+ const updateParams = params as unknown as UpdateCommentRequest & { id: number };
206
+ const comment = await client.updateComment(updateParams);
213
207
  return `✅ Comment ${comment.id} updated successfully. New status: ${comment.status}.`;
214
208
  } catch (error) {
215
209
  throw new Error(`Failed to update comment: ${getErrorMessage(error)}`);
216
210
  }
217
211
  }
218
212
 
219
- public async handleDeleteComment(
220
- client: WordPressClient,
221
- params: { id: number; force?: boolean },
222
- ): Promise<any> {
213
+ public async handleDeleteComment(client: WordPressClient, params: Record<string, unknown>): Promise<unknown> {
214
+ const { id, force } = params as { id: number; force?: boolean };
223
215
  try {
224
- await client.deleteComment(params.id, params.force);
225
- const action = params.force ? "permanently deleted" : "moved to trash";
226
- return `✅ Comment ${params.id} has been ${action}.`;
216
+ await client.deleteComment(id, force);
217
+ const action = force ? "permanently deleted" : "moved to trash";
218
+ return `✅ Comment ${id} has been ${action}`;
227
219
  } catch (error) {
228
220
  throw new Error(`Failed to delete comment: ${getErrorMessage(error)}`);
229
221
  }
230
222
  }
231
223
 
232
- public async handleApproveComment(
233
- client: WordPressClient,
234
- params: { id: number },
235
- ): Promise<any> {
224
+ public async handleApproveComment(client: WordPressClient, params: Record<string, unknown>): Promise<unknown> {
225
+ const { id } = params as { id: number };
236
226
  try {
237
227
  const comment = await client.updateComment({
238
- id: params.id,
228
+ id,
239
229
  status: "approved",
240
230
  });
241
231
  return `✅ Comment ${comment.id} has been approved.`;
@@ -244,20 +234,16 @@ export class CommentTools {
244
234
  }
245
235
  }
246
236
 
247
- public async handleSpamComment(
248
- client: WordPressClient,
249
- params: { id: number },
250
- ): Promise<any> {
237
+ public async handleSpamComment(client: WordPressClient, params: Record<string, unknown>): Promise<unknown> {
238
+ const { id } = params as { id: number };
251
239
  try {
252
240
  const comment = await client.updateComment({
253
- id: params.id,
241
+ id,
254
242
  status: "spam",
255
243
  });
256
244
  return `✅ Comment ${comment.id} has been marked as spam.`;
257
245
  } catch (error) {
258
- throw new Error(
259
- `Failed to mark comment as spam: ${getErrorMessage(error)}`,
260
- );
246
+ throw new Error(`Failed to mark comment as spam: ${getErrorMessage(error)}`);
261
247
  }
262
248
  }
263
249
  }