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.
- package/README.md +114 -48
- package/dist/ajv-patch.js +34 -0
- package/dist/cache/CacheInvalidation.d.ts +3 -1
- package/dist/cache/CacheInvalidation.d.ts.map +1 -1
- package/dist/cache/CacheInvalidation.js +10 -4
- package/dist/cache/CacheInvalidation.js.map +1 -1
- package/dist/cache/CacheManager.d.ts +3 -2
- package/dist/cache/CacheManager.d.ts.map +1 -1
- package/dist/cache/CacheManager.js +11 -3
- package/dist/cache/CacheManager.js.map +1 -1
- package/dist/cache/HttpCacheWrapper.d.ts +7 -6
- package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
- package/dist/cache/HttpCacheWrapper.js +8 -5
- package/dist/cache/HttpCacheWrapper.js.map +1 -1
- package/dist/cache/__tests__/HttpCacheWrapper.test.js +6 -5
- package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -1
- package/dist/cache/index.d.ts +3 -3
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/client/CachedWordPressClient.d.ts +23 -9
- package/dist/client/CachedWordPressClient.d.ts.map +1 -1
- package/dist/client/CachedWordPressClient.js +4 -1
- package/dist/client/CachedWordPressClient.js.map +1 -1
- package/dist/client/MockWordPressClient.d.ts +2 -1
- package/dist/client/MockWordPressClient.d.ts.map +1 -1
- package/dist/client/MockWordPressClient.js +3 -1
- package/dist/client/MockWordPressClient.js.map +1 -1
- package/dist/client/api.d.ts +17 -13
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +135 -30
- package/dist/client/api.js.map +1 -1
- package/dist/client/auth.d.ts.map +1 -1
- package/dist/client/auth.js +2 -3
- package/dist/client/auth.js.map +1 -1
- package/dist/client/managers/AuthenticationManager.d.ts +55 -2
- package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
- package/dist/client/managers/AuthenticationManager.js +269 -71
- package/dist/client/managers/AuthenticationManager.js.map +1 -1
- package/dist/client/managers/BaseManager.d.ts +3 -3
- package/dist/client/managers/BaseManager.d.ts.map +1 -1
- package/dist/client/managers/BaseManager.js +11 -5
- package/dist/client/managers/BaseManager.js.map +1 -1
- package/dist/client/managers/RequestManager.d.ts +2 -2
- package/dist/client/managers/RequestManager.d.ts.map +1 -1
- package/dist/client/managers/RequestManager.js +25 -12
- package/dist/client/managers/RequestManager.js.map +1 -1
- package/dist/config/Config.d.ts +155 -0
- package/dist/config/Config.d.ts.map +1 -0
- package/dist/config/Config.js +215 -0
- package/dist/config/Config.js.map +1 -0
- package/dist/config/ConfigurationSchema.d.ts +21 -21
- package/dist/config/ConfigurationSchema.d.ts.map +1 -1
- package/dist/config/ConfigurationSchema.js +19 -2
- package/dist/config/ConfigurationSchema.js.map +1 -1
- package/dist/config/ServerConfiguration.d.ts +2 -1
- package/dist/config/ServerConfiguration.d.ts.map +1 -1
- package/dist/config/ServerConfiguration.js +50 -41
- package/dist/config/ServerConfiguration.js.map +1 -1
- package/dist/docs/DocumentationGenerator.d.ts +9 -8
- package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
- package/dist/docs/DocumentationGenerator.js +10 -7
- package/dist/docs/DocumentationGenerator.js.map +1 -1
- package/dist/docs/MarkdownFormatter.d.ts.map +1 -1
- package/dist/docs/MarkdownFormatter.js +3 -2
- package/dist/docs/MarkdownFormatter.js.map +1 -1
- package/dist/dxt-entry.cjs +81 -0
- package/dist/dxt-entry.js +15 -14
- package/dist/dxt-entry.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -21
- package/dist/index.js.map +1 -1
- package/dist/performance/MetricsCollector.d.ts +13 -7
- package/dist/performance/MetricsCollector.d.ts.map +1 -1
- package/dist/performance/MetricsCollector.js +69 -27
- package/dist/performance/MetricsCollector.js.map +1 -1
- package/dist/performance/PerformanceAnalytics.d.ts +8 -2
- package/dist/performance/PerformanceAnalytics.d.ts.map +1 -1
- package/dist/performance/PerformanceAnalytics.js +17 -47
- package/dist/performance/PerformanceAnalytics.js.map +1 -1
- package/dist/performance/PerformanceMonitor.d.ts +2 -1
- package/dist/performance/PerformanceMonitor.d.ts.map +1 -1
- package/dist/performance/PerformanceMonitor.js +12 -13
- package/dist/performance/PerformanceMonitor.js.map +1 -1
- package/dist/performance/index.d.ts +2 -2
- package/dist/performance/index.d.ts.map +1 -1
- package/dist/security/AISecurityScanner.d.ts +1 -0
- package/dist/security/AISecurityScanner.d.ts.map +1 -1
- package/dist/security/AISecurityScanner.js +22 -12
- package/dist/security/AISecurityScanner.js.map +1 -1
- package/dist/security/AutomatedRemediation.d.ts +4 -3
- package/dist/security/AutomatedRemediation.d.ts.map +1 -1
- package/dist/security/AutomatedRemediation.js +46 -15
- package/dist/security/AutomatedRemediation.js.map +1 -1
- package/dist/security/InputValidator.d.ts +13 -9
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +4 -2
- package/dist/security/InputValidator.js.map +1 -1
- package/dist/security/SecurityCIPipeline.d.ts +1 -1
- package/dist/security/SecurityCIPipeline.d.ts.map +1 -1
- package/dist/security/SecurityCIPipeline.js +38 -29
- package/dist/security/SecurityCIPipeline.js.map +1 -1
- package/dist/security/SecurityConfig.d.ts +3 -3
- package/dist/security/SecurityConfig.d.ts.map +1 -1
- package/dist/security/SecurityConfig.js +13 -9
- package/dist/security/SecurityConfig.js.map +1 -1
- package/dist/security/SecurityConfigManager.d.ts +2 -2
- package/dist/security/SecurityConfigManager.d.ts.map +1 -1
- package/dist/security/SecurityConfigManager.js +20 -15
- package/dist/security/SecurityConfigManager.js.map +1 -1
- package/dist/security/SecurityMonitoring.d.ts +2 -2
- package/dist/security/SecurityMonitoring.d.ts.map +1 -1
- package/dist/security/SecurityMonitoring.js +19 -17
- package/dist/security/SecurityMonitoring.js.map +1 -1
- package/dist/security/SecurityReviewer.d.ts.map +1 -1
- package/dist/security/SecurityReviewer.js +10 -7
- package/dist/security/SecurityReviewer.js.map +1 -1
- package/dist/security/index.d.ts +24 -23
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +52 -23
- package/dist/security/index.js.map +1 -1
- package/dist/server/ConnectionTester.d.ts +12 -4
- package/dist/server/ConnectionTester.d.ts.map +1 -1
- package/dist/server/ConnectionTester.js +96 -22
- package/dist/server/ConnectionTester.js.map +1 -1
- package/dist/server/ToolRegistry.d.ts +2 -2
- package/dist/server/ToolRegistry.d.ts.map +1 -1
- package/dist/server/ToolRegistry.js +10 -5
- package/dist/server/ToolRegistry.js.map +1 -1
- package/dist/tools/BaseToolManager.d.ts +47 -11
- package/dist/tools/BaseToolManager.d.ts.map +1 -1
- package/dist/tools/BaseToolManager.js +168 -29
- package/dist/tools/BaseToolManager.js.map +1 -1
- package/dist/tools/auth.d.ts +16 -10
- package/dist/tools/auth.d.ts.map +1 -1
- package/dist/tools/auth.js +3 -2
- package/dist/tools/auth.js.map +1 -1
- package/dist/tools/cache.d.ts +30 -30
- package/dist/tools/cache.d.ts.map +1 -1
- package/dist/tools/cache.js +1 -6
- package/dist/tools/cache.js.map +1 -1
- package/dist/tools/comments.d.ts +20 -20
- package/dist/tools/comments.d.ts.map +1 -1
- package/dist/tools/comments.js +16 -9
- package/dist/tools/comments.js.map +1 -1
- package/dist/tools/media.d.ts +18 -16
- package/dist/tools/media.d.ts.map +1 -1
- package/dist/tools/media.js +16 -15
- package/dist/tools/media.js.map +1 -1
- package/dist/tools/pages.d.ts +19 -17
- package/dist/tools/pages.d.ts.map +1 -1
- package/dist/tools/pages.js +16 -12
- package/dist/tools/pages.js.map +1 -1
- package/dist/tools/performance.d.ts +11 -1
- package/dist/tools/performance.d.ts.map +1 -1
- package/dist/tools/performance.js +67 -34
- package/dist/tools/performance.js.map +1 -1
- package/dist/tools/posts/PostHandlers.d.ts +46 -0
- package/dist/tools/posts/PostHandlers.d.ts.map +1 -0
- package/dist/tools/posts/PostHandlers.js +400 -0
- package/dist/tools/posts/PostHandlers.js.map +1 -0
- package/dist/tools/posts/PostToolDefinitions.d.ts +37 -0
- package/dist/tools/posts/PostToolDefinitions.d.ts.map +1 -0
- package/dist/tools/posts/PostToolDefinitions.js +236 -0
- package/dist/tools/posts/PostToolDefinitions.js.map +1 -0
- package/dist/tools/posts/index.d.ts +138 -0
- package/dist/tools/posts/index.d.ts.map +1 -0
- package/dist/tools/posts/index.js +163 -0
- package/dist/tools/posts/index.js.map +1 -0
- package/dist/tools/posts.d.ts +10 -246
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +11 -723
- package/dist/tools/posts.js.map +1 -1
- package/dist/tools/site.d.ts +19 -18
- package/dist/tools/site.d.ts.map +1 -1
- package/dist/tools/site.js +14 -10
- package/dist/tools/site.js.map +1 -1
- package/dist/tools/taxonomies.d.ts +23 -24
- package/dist/tools/taxonomies.d.ts.map +1 -1
- package/dist/tools/taxonomies.js +24 -18
- package/dist/tools/taxonomies.js.map +1 -1
- package/dist/tools/users.d.ts +20 -15
- package/dist/tools/users.d.ts.map +1 -1
- package/dist/tools/users.js +12 -8
- package/dist/tools/users.js.map +1 -1
- package/dist/types/client.d.ts +48 -41
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/client.js +30 -5
- package/dist/types/client.js.map +1 -1
- package/dist/types/enhanced.d.ts +237 -0
- package/dist/types/enhanced.d.ts.map +1 -0
- package/dist/types/enhanced.js +49 -0
- package/dist/types/enhanced.js.map +1 -0
- package/dist/types/index.d.ts +15 -12
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/mcp.d.ts +12 -12
- package/dist/types/mcp.d.ts.map +1 -1
- package/dist/types/requests.d.ts +322 -0
- package/dist/types/requests.d.ts.map +1 -0
- package/dist/types/requests.js +8 -0
- package/dist/types/requests.js.map +1 -0
- package/dist/types/tools.d.ts +506 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +8 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/types/wordpress.d.ts +43 -15
- package/dist/types/wordpress.d.ts.map +1 -1
- package/dist/types/wordpress.js +8 -1
- package/dist/types/wordpress.js.map +1 -1
- package/dist/utils/debug.d.ts +19 -11
- package/dist/utils/debug.d.ts.map +1 -1
- package/dist/utils/debug.js +46 -10
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/enhancedError.d.ts +8 -8
- package/dist/utils/enhancedError.d.ts.map +1 -1
- package/dist/utils/enhancedError.js.map +1 -1
- package/dist/utils/error.d.ts +2 -4
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js +42 -5
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/logger.d.ts +106 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +280 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/streaming.d.ts +9 -9
- package/dist/utils/streaming.d.ts.map +1 -1
- package/dist/utils/streaming.js +71 -52
- package/dist/utils/streaming.js.map +1 -1
- package/dist/utils/toolWrapper.d.ts +9 -7
- package/dist/utils/toolWrapper.d.ts.map +1 -1
- package/dist/utils/toolWrapper.js.map +1 -1
- package/dist/utils/validation/core.d.ts +21 -0
- package/dist/utils/validation/core.d.ts.map +1 -0
- package/dist/utils/validation/core.js +71 -0
- package/dist/utils/validation/core.js.map +1 -0
- package/dist/utils/validation/index.d.ts +25 -0
- package/dist/utils/validation/index.d.ts.map +1 -0
- package/dist/utils/validation/index.js +29 -0
- package/dist/utils/validation/index.js.map +1 -0
- package/dist/utils/validation/network.d.ts +19 -0
- package/dist/utils/validation/network.d.ts.map +1 -0
- package/dist/utils/validation/network.js +93 -0
- package/dist/utils/validation/network.js.map +1 -0
- package/dist/utils/validation/rateLimit.d.ts +21 -0
- package/dist/utils/validation/rateLimit.d.ts.map +1 -0
- package/dist/utils/validation/rateLimit.js +43 -0
- package/dist/utils/validation/rateLimit.js.map +1 -0
- package/dist/utils/validation/security.d.ts +29 -0
- package/dist/utils/validation/security.d.ts.map +1 -0
- package/dist/utils/validation/security.js +327 -0
- package/dist/utils/validation/security.js.map +1 -0
- package/dist/utils/validation/wordpress.d.ts +31 -0
- package/dist/utils/validation/wordpress.d.ts.map +1 -0
- package/dist/utils/validation/wordpress.js +146 -0
- package/dist/utils/validation/wordpress.js.map +1 -0
- package/dist/utils/validation.d.ts +13 -82
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +25 -343
- package/dist/utils/validation.js.map +1 -1
- package/docs/BADGE_UPDATES.md +132 -0
- package/docs/CI_CD_IMPROVEMENTS.md +191 -0
- package/docs/INCREMENTAL_COVERAGE.md +183 -0
- package/docs/api/README.md +3 -1
- package/docs/api/openapi.json +5 -1
- package/docs/api/summary.json +1 -1
- package/docs/api/tools/wp_create_post.md +12 -14
- package/docs/examples/claude-desktop-config.md +1 -1
- package/docs/examples/docker-production.md +100 -93
- package/docs/examples/multi-site-setup.md +5 -4
- package/docs/examples/single-site-setup.md +3 -4
- package/docs/examples/use-case-workflows.md +4 -5
- package/docs/integrations/claude-desktop.md +31 -31
- package/docs/integrations/cline.md +4 -4
- package/docs/integrations/vs-code.md +9 -8
- package/docs/user-guides/SMITHERY_SETUP.md +10 -10
- package/package.json +44 -25
- package/src/cache/CacheInvalidation.ts +12 -5
- package/src/cache/CacheManager.ts +18 -15
- package/src/cache/HttpCacheWrapper.ts +30 -59
- package/src/cache/__tests__/HttpCacheWrapper.test.ts +6 -5
- package/src/cache/index.ts +3 -14
- package/src/client/CachedWordPressClient.ts +32 -30
- package/src/client/MockWordPressClient.ts +4 -2
- package/src/client/api.ts +186 -64
- package/src/client/auth.ts +15 -40
- package/src/client/managers/AuthenticationManager.ts +337 -77
- package/src/client/managers/BaseManager.ts +18 -30
- package/src/client/managers/RequestManager.ts +39 -44
- package/src/config/Config.ts +308 -0
- package/src/config/ConfigurationSchema.ts +23 -2
- package/src/config/ServerConfiguration.ts +51 -47
- package/src/docs/DocumentationGenerator.ts +50 -39
- package/src/docs/MarkdownFormatter.ts +19 -29
- package/src/dxt-entry.cjs +26 -16
- package/src/dxt-entry.ts +17 -27
- package/src/index.ts +42 -28
- package/src/performance/MetricsCollector.ts +108 -86
- package/src/performance/PerformanceAnalytics.ts +69 -164
- package/src/performance/PerformanceMonitor.ts +32 -47
- package/src/performance/index.ts +2 -10
- package/src/security/AISecurityScanner.ts +22 -12
- package/src/security/AutomatedRemediation.ts +49 -18
- package/src/security/InputValidator.ts +9 -6
- package/src/security/SecurityCIPipeline.ts +53 -37
- package/src/security/SecurityConfig.ts +22 -22
- package/src/security/SecurityConfigManager.ts +23 -19
- package/src/security/SecurityMonitoring.ts +24 -21
- package/src/security/SecurityReviewer.ts +10 -7
- package/src/security/index.ts +64 -29
- package/src/server/ConnectionTester.ts +120 -31
- package/src/server/ToolRegistry.ts +31 -21
- package/src/tools/BaseToolManager.ts +286 -33
- package/src/tools/auth.ts +20 -8
- package/src/tools/cache.ts +5 -15
- package/src/tools/comments.ts +34 -48
- package/src/tools/media.ts +41 -53
- package/src/tools/pages.ts +32 -54
- package/src/tools/performance.ts +141 -176
- package/src/tools/posts/PostHandlers.ts +474 -0
- package/src/tools/posts/PostToolDefinitions.ts +250 -0
- package/src/tools/posts/index.ts +192 -0
- package/src/tools/posts.ts +24 -780
- package/src/tools/site.ts +34 -19
- package/src/tools/taxonomies.ts +41 -57
- package/src/tools/users.ts +28 -16
- package/src/types/client.ts +114 -138
- package/src/types/enhanced.ts +318 -0
- package/src/types/index.ts +51 -30
- package/src/types/mcp.ts +20 -42
- package/src/types/requests.ts +378 -0
- package/src/types/tools.ts +608 -0
- package/src/types/wordpress.ts +56 -34
- package/src/utils/debug.ts +77 -59
- package/src/utils/enhancedError.ts +8 -8
- package/src/utils/error.ts +53 -31
- package/src/utils/logger.ts +351 -0
- package/src/utils/streaming.ts +86 -68
- package/src/utils/toolWrapper.ts +10 -12
- package/src/utils/validation/core.ts +108 -0
- package/src/utils/validation/index.ts +36 -0
- package/src/utils/validation/network.ts +132 -0
- package/src/utils/validation/rateLimit.ts +54 -0
- package/src/utils/validation/security.ts +361 -0
- package/src/utils/validation/wordpress.ts +180 -0
- package/src/utils/validation.ts +47 -470
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress Posts Handler Implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements all handler methods for WordPress post management tools.
|
|
5
|
+
* This module contains the business logic for post operations including
|
|
6
|
+
* validation, API interaction, and response formatting.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { WordPressClient } from "../../client/api.js";
|
|
10
|
+
import { CreatePostRequest, PostQueryParams, UpdatePostRequest, WordPressPost } from "../../types/wordpress.js";
|
|
11
|
+
import { getErrorMessage } from "../../utils/error.js";
|
|
12
|
+
import { ErrorHandlers } from "../../utils/enhancedError.js";
|
|
13
|
+
import { validateId, validatePaginationParams, validatePostParams } from "../../utils/validation.js";
|
|
14
|
+
import { sanitizeHtml } from "../../utils/validation/security.js";
|
|
15
|
+
import { WordPressDataStreamer, StreamingUtils, StreamingResult } from "../../utils/streaming.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Handles listing WordPress posts with advanced filtering and pagination
|
|
19
|
+
*/
|
|
20
|
+
export async function handleListPosts(
|
|
21
|
+
client: WordPressClient,
|
|
22
|
+
params: PostQueryParams,
|
|
23
|
+
): Promise<WordPressPost[] | string> {
|
|
24
|
+
try {
|
|
25
|
+
// Enhanced input validation and sanitization
|
|
26
|
+
const paginationValidated = validatePaginationParams({
|
|
27
|
+
page: params.page,
|
|
28
|
+
per_page: params.per_page,
|
|
29
|
+
offset: params.offset,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const sanitizedParams = {
|
|
33
|
+
...params,
|
|
34
|
+
...paginationValidated,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Validate and sanitize search term
|
|
38
|
+
if (sanitizedParams.search) {
|
|
39
|
+
sanitizedParams.search = sanitizedParams.search.trim();
|
|
40
|
+
if (sanitizedParams.search.length === 0) {
|
|
41
|
+
delete sanitizedParams.search;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Validate category and tag IDs if provided
|
|
46
|
+
if (sanitizedParams.categories) {
|
|
47
|
+
sanitizedParams.categories = sanitizedParams.categories.map((id) => validateId(id, "category ID"));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (sanitizedParams.tags) {
|
|
51
|
+
sanitizedParams.tags = sanitizedParams.tags.map((id) => validateId(id, "tag ID"));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Validate status parameter
|
|
55
|
+
if (sanitizedParams.status) {
|
|
56
|
+
const validStatuses = ["publish", "future", "draft", "pending", "private"];
|
|
57
|
+
const statusesToCheck = Array.isArray(sanitizedParams.status) ? sanitizedParams.status : [sanitizedParams.status];
|
|
58
|
+
|
|
59
|
+
for (const statusToCheck of statusesToCheck) {
|
|
60
|
+
if (!validStatuses.includes(statusToCheck)) {
|
|
61
|
+
throw ErrorHandlers.validationError("status", statusToCheck, "one of: " + validStatuses.join(", "));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Performance optimization: set reasonable defaults
|
|
67
|
+
if (!sanitizedParams.per_page) {
|
|
68
|
+
sanitizedParams.per_page = 10; // Default to 10 posts for better performance
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const posts = await client.getPosts(sanitizedParams);
|
|
72
|
+
if (posts.length === 0) {
|
|
73
|
+
const searchInfo = sanitizedParams.search ? ` matching "${sanitizedParams.search}"` : "";
|
|
74
|
+
const statusInfo = sanitizedParams.status ? ` with status "${sanitizedParams.status}"` : "";
|
|
75
|
+
return `No posts found${searchInfo}${statusInfo}. Try adjusting your search criteria or check if posts exist.`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Use streaming for large result sets (>50 posts)
|
|
79
|
+
if (posts.length > 50) {
|
|
80
|
+
const streamResults: StreamingResult<unknown>[] = [];
|
|
81
|
+
|
|
82
|
+
for await (const result of WordPressDataStreamer.streamPosts(posts, {
|
|
83
|
+
includeAuthor: true,
|
|
84
|
+
includeCategories: true,
|
|
85
|
+
includeTags: true,
|
|
86
|
+
batchSize: 20,
|
|
87
|
+
})) {
|
|
88
|
+
streamResults.push(result);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return StreamingUtils.formatStreamingResponse(streamResults, "posts");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Add comprehensive site context information
|
|
95
|
+
const siteUrl = client.getSiteUrl ? client.getSiteUrl() : "Unknown site";
|
|
96
|
+
const totalPosts = posts.length;
|
|
97
|
+
const statusCounts = posts.reduce(
|
|
98
|
+
(acc, p) => {
|
|
99
|
+
acc[p.status] = (acc[p.status] || 0) + 1;
|
|
100
|
+
return acc;
|
|
101
|
+
},
|
|
102
|
+
{} as Record<string, number>,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Enhanced metadata
|
|
106
|
+
const metadata = [
|
|
107
|
+
`📊 **Posts Summary**: ${totalPosts} total`,
|
|
108
|
+
`📝 **Status Breakdown**: ${Object.entries(statusCounts)
|
|
109
|
+
.map(([status, count]) => `${status}: ${count}`)
|
|
110
|
+
.join(", ")}`,
|
|
111
|
+
`🌐 **Source**: ${siteUrl}`,
|
|
112
|
+
`📅 **Retrieved**: ${new Date().toLocaleString()}`,
|
|
113
|
+
...(params.search ? [`🔍 **Search Term**: "${params.search}"`] : []),
|
|
114
|
+
...(params.categories ? [`📁 **Categories**: ${params.categories.join(", ")}`] : []),
|
|
115
|
+
...(params.tags ? [`🏷️ **Tags**: ${params.tags.join(", ")}`] : []),
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
// Fetch additional metadata for enhanced responses
|
|
119
|
+
const authorIds = [...new Set(posts.map((p) => p.author).filter(Boolean))];
|
|
120
|
+
const categoryIds = [...new Set(posts.flatMap((p) => p.categories || []))];
|
|
121
|
+
const tagIds = [...new Set(posts.flatMap((p) => p.tags || []))];
|
|
122
|
+
|
|
123
|
+
// Fetch authors, categories, and tags in parallel for better performance
|
|
124
|
+
const [authors, categories, tags] = await Promise.all([
|
|
125
|
+
authorIds.length > 0
|
|
126
|
+
? Promise.all(
|
|
127
|
+
authorIds.map(async (id) => {
|
|
128
|
+
try {
|
|
129
|
+
const user = await client.getUser(id);
|
|
130
|
+
return { id, name: user.name || user.username || `User ${id}` };
|
|
131
|
+
} catch {
|
|
132
|
+
return { id, name: `User ${id}` };
|
|
133
|
+
}
|
|
134
|
+
}),
|
|
135
|
+
)
|
|
136
|
+
: [],
|
|
137
|
+
categoryIds.length > 0
|
|
138
|
+
? Promise.all(
|
|
139
|
+
categoryIds.map(async (id) => {
|
|
140
|
+
try {
|
|
141
|
+
const category = await client.getCategory(id);
|
|
142
|
+
return { id, name: category.name || `Category ${id}` };
|
|
143
|
+
} catch {
|
|
144
|
+
return { id, name: `Category ${id}` };
|
|
145
|
+
}
|
|
146
|
+
}),
|
|
147
|
+
)
|
|
148
|
+
: [],
|
|
149
|
+
tagIds.length > 0
|
|
150
|
+
? Promise.all(
|
|
151
|
+
tagIds.map(async (id) => {
|
|
152
|
+
try {
|
|
153
|
+
const tag = await client.getTag(id);
|
|
154
|
+
return { id, name: tag.name || `Tag ${id}` };
|
|
155
|
+
} catch {
|
|
156
|
+
return { id, name: `Tag ${id}` };
|
|
157
|
+
}
|
|
158
|
+
}),
|
|
159
|
+
)
|
|
160
|
+
: [],
|
|
161
|
+
]);
|
|
162
|
+
|
|
163
|
+
// Create lookup maps for performance
|
|
164
|
+
const authorMap = new Map(authors.map((a) => [a.id, a.name]));
|
|
165
|
+
const categoryMap = new Map(categories.map((c) => [c.id, c.name]));
|
|
166
|
+
const tagMap = new Map(tags.map((t) => [t.id, t.name]));
|
|
167
|
+
|
|
168
|
+
const content =
|
|
169
|
+
metadata.join("\n") +
|
|
170
|
+
"\n\n" +
|
|
171
|
+
posts
|
|
172
|
+
.map((p) => {
|
|
173
|
+
const date = new Date(p.date);
|
|
174
|
+
const formattedDate = date.toLocaleDateString("en-US", {
|
|
175
|
+
year: "numeric",
|
|
176
|
+
month: "short",
|
|
177
|
+
day: "numeric",
|
|
178
|
+
});
|
|
179
|
+
const excerpt = p.excerpt?.rendered ? sanitizeHtml(p.excerpt.rendered).substring(0, 80) + "..." : "";
|
|
180
|
+
|
|
181
|
+
// Enhanced metadata
|
|
182
|
+
const authorName = authorMap.get(p.author) || `User ${p.author}`;
|
|
183
|
+
const postCategories = (p.categories || []).map((id) => categoryMap.get(id) || `Category ${id}`);
|
|
184
|
+
const postTags = (p.tags || []).map((id) => tagMap.get(id) || `Tag ${id}`);
|
|
185
|
+
|
|
186
|
+
let postInfo = `- ID ${p.id}: **${p.title.rendered}** (${p.status})\n`;
|
|
187
|
+
postInfo += ` 👤 Author: ${authorName}\n`;
|
|
188
|
+
postInfo += ` 📅 Published: ${formattedDate}\n`;
|
|
189
|
+
if (postCategories.length > 0) {
|
|
190
|
+
postInfo += ` 📁 Categories: ${postCategories.join(", ")}\n`;
|
|
191
|
+
}
|
|
192
|
+
if (postTags.length > 0) {
|
|
193
|
+
postInfo += ` 🏷️ Tags: ${postTags.join(", ")}\n`;
|
|
194
|
+
}
|
|
195
|
+
if (excerpt) {
|
|
196
|
+
postInfo += ` 📝 Excerpt: ${excerpt}\n`;
|
|
197
|
+
}
|
|
198
|
+
postInfo += ` 🔗 Link: ${p.link}`;
|
|
199
|
+
|
|
200
|
+
return postInfo;
|
|
201
|
+
})
|
|
202
|
+
.join("\n\n");
|
|
203
|
+
|
|
204
|
+
// Add pagination guidance for large result sets
|
|
205
|
+
let finalContent = content;
|
|
206
|
+
if (posts.length >= (sanitizedParams.per_page || 10)) {
|
|
207
|
+
finalContent += `\n\n📄 **Pagination Tip**: Use \`per_page\` parameter to control results (max 100). Current: ${sanitizedParams.per_page || 10}`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return finalContent;
|
|
211
|
+
} catch (error) {
|
|
212
|
+
throw new Error(`Failed to list posts: ${getErrorMessage(error)}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Handles retrieving a single WordPress post by ID
|
|
218
|
+
*/
|
|
219
|
+
export async function handleGetPost(client: WordPressClient, params: { id: number }): Promise<WordPressPost | string> {
|
|
220
|
+
try {
|
|
221
|
+
const postId = validateId(params.id, "post ID");
|
|
222
|
+
const post = await client.getPost(postId);
|
|
223
|
+
|
|
224
|
+
// Get additional metadata for comprehensive response
|
|
225
|
+
const [author, categories, tags] = await Promise.all([
|
|
226
|
+
// Get author information
|
|
227
|
+
post.author
|
|
228
|
+
? client.getUser(post.author).catch(() => ({ name: `User ${post.author}`, username: `user${post.author}` }))
|
|
229
|
+
: null,
|
|
230
|
+
// Get categories
|
|
231
|
+
post.categories && post.categories.length > 0
|
|
232
|
+
? Promise.all(post.categories.map((id) => client.getCategory(id).catch(() => ({ id, name: `Category ${id}` }))))
|
|
233
|
+
: [],
|
|
234
|
+
// Get tags
|
|
235
|
+
post.tags && post.tags.length > 0
|
|
236
|
+
? Promise.all(post.tags.map((id) => client.getTag(id).catch(() => ({ id, name: `Tag ${id}` }))))
|
|
237
|
+
: [],
|
|
238
|
+
]);
|
|
239
|
+
|
|
240
|
+
// Format post content
|
|
241
|
+
const date = new Date(post.date);
|
|
242
|
+
const modifiedDate = new Date(post.modified);
|
|
243
|
+
const formattedDate = date.toLocaleDateString("en-US", {
|
|
244
|
+
year: "numeric",
|
|
245
|
+
month: "short",
|
|
246
|
+
day: "numeric",
|
|
247
|
+
hour: "2-digit",
|
|
248
|
+
minute: "2-digit",
|
|
249
|
+
});
|
|
250
|
+
const formattedModified = modifiedDate.toLocaleDateString("en-US", {
|
|
251
|
+
year: "numeric",
|
|
252
|
+
month: "short",
|
|
253
|
+
day: "numeric",
|
|
254
|
+
hour: "2-digit",
|
|
255
|
+
minute: "2-digit",
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const content = post.content?.rendered || "";
|
|
259
|
+
const excerpt = post.excerpt?.rendered ? sanitizeHtml(post.excerpt.rendered).trim() : "";
|
|
260
|
+
const wordCount = sanitizeHtml(content).split(/\s+/).filter(Boolean).length;
|
|
261
|
+
|
|
262
|
+
// Build comprehensive response
|
|
263
|
+
let response = `# ${post.title.rendered}\n\n`;
|
|
264
|
+
response += `**Post ID**: ${post.id}\n`;
|
|
265
|
+
response += `**Status**: ${post.status}\n`;
|
|
266
|
+
response += `**Author**: ${author?.name || author?.username || `User ${post.author}`}\n`;
|
|
267
|
+
response += `**Published**: ${formattedDate}\n`;
|
|
268
|
+
response += `**Modified**: ${formattedModified}\n`;
|
|
269
|
+
|
|
270
|
+
if (categories.length > 0) {
|
|
271
|
+
response += `**Categories**: ${categories.map((c) => c.name).join(", ")}\n`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (tags.length > 0) {
|
|
275
|
+
response += `**Tags**: ${tags.map((t) => t.name).join(", ")}\n`;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
response += `**Word Count**: ${wordCount}\n`;
|
|
279
|
+
response += `**Link**: ${post.link}\n`;
|
|
280
|
+
|
|
281
|
+
if (excerpt) {
|
|
282
|
+
response += `\n## Excerpt\n${excerpt}\n`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (content) {
|
|
286
|
+
response += `\n## Content\n${content}\n`;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Add management links and metadata
|
|
290
|
+
const siteUrl = client.getSiteUrl ? client.getSiteUrl() : "";
|
|
291
|
+
if (siteUrl) {
|
|
292
|
+
response += `\n## Management\n`;
|
|
293
|
+
response += `- **Edit**: ${siteUrl}/wp-admin/post.php?post=${post.id}&action=edit\n`;
|
|
294
|
+
response += `- **Preview**: ${siteUrl}/?p=${post.id}&preview=true\n`;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return response;
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
300
|
+
return `Post with ID ${params.id} not found. Please verify the ID and try again.`;
|
|
301
|
+
}
|
|
302
|
+
throw new Error(`Failed to get post: ${getErrorMessage(error)}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Handles creating a new WordPress post
|
|
308
|
+
*/
|
|
309
|
+
export async function handleCreatePost(
|
|
310
|
+
client: WordPressClient,
|
|
311
|
+
params: CreatePostRequest,
|
|
312
|
+
): Promise<WordPressPost | string> {
|
|
313
|
+
try {
|
|
314
|
+
validatePostParams(params);
|
|
315
|
+
const post = await client.createPost(params);
|
|
316
|
+
|
|
317
|
+
// Build success response with management links
|
|
318
|
+
let response = `✅ **Post Created Successfully**\n\n`;
|
|
319
|
+
response += `**Title**: ${post.title.rendered}\n`;
|
|
320
|
+
response += `**ID**: ${post.id}\n`;
|
|
321
|
+
response += `**Status**: ${post.status}\n`;
|
|
322
|
+
response += `**Link**: ${post.link}\n`;
|
|
323
|
+
|
|
324
|
+
// Add management links
|
|
325
|
+
const siteUrl = client.getSiteUrl ? client.getSiteUrl() : "";
|
|
326
|
+
if (siteUrl) {
|
|
327
|
+
response += `\n**Management**:\n`;
|
|
328
|
+
response += `- Edit: ${siteUrl}/wp-admin/post.php?post=${post.id}&action=edit\n`;
|
|
329
|
+
if (post.status === "publish") {
|
|
330
|
+
response += `- View: ${post.link}\n`;
|
|
331
|
+
} else {
|
|
332
|
+
response += `- Preview: ${siteUrl}/?p=${post.id}&preview=true\n`;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return response;
|
|
337
|
+
} catch (error) {
|
|
338
|
+
throw new Error(`Failed to create post: ${getErrorMessage(error)}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Handles updating an existing WordPress post
|
|
344
|
+
*/
|
|
345
|
+
export async function handleUpdatePost(
|
|
346
|
+
client: WordPressClient,
|
|
347
|
+
params: UpdatePostRequest & { id: number },
|
|
348
|
+
): Promise<WordPressPost | string> {
|
|
349
|
+
try {
|
|
350
|
+
const postId = validateId(params.id, "post ID");
|
|
351
|
+
|
|
352
|
+
// Get original post to show what changed
|
|
353
|
+
const originalPost = await client.getPost(postId);
|
|
354
|
+
|
|
355
|
+
const { id: _id, ...updateData } = params;
|
|
356
|
+
validatePostParams(updateData);
|
|
357
|
+
|
|
358
|
+
const updatedPost = await client.updatePost({ id: postId, ...updateData });
|
|
359
|
+
|
|
360
|
+
// Build change summary
|
|
361
|
+
let response = `✅ **Post Updated Successfully**\n\n`;
|
|
362
|
+
response += `**Title**: ${updatedPost.title.rendered}\n`;
|
|
363
|
+
response += `**ID**: ${updatedPost.id}\n`;
|
|
364
|
+
response += `**Status**: ${updatedPost.status}\n`;
|
|
365
|
+
response += `**Modified**: ${new Date(updatedPost.modified).toLocaleString()}\n`;
|
|
366
|
+
|
|
367
|
+
// Show what changed
|
|
368
|
+
const changes: string[] = [];
|
|
369
|
+
if (params.title && originalPost.title.rendered !== updatedPost.title.rendered) {
|
|
370
|
+
changes.push(`Title: "${originalPost.title.rendered}" → "${updatedPost.title.rendered}"`);
|
|
371
|
+
}
|
|
372
|
+
if (params.status && originalPost.status !== updatedPost.status) {
|
|
373
|
+
changes.push(`Status: "${originalPost.status}" → "${updatedPost.status}"`);
|
|
374
|
+
}
|
|
375
|
+
if (params.content && originalPost.content?.rendered !== updatedPost.content?.rendered) {
|
|
376
|
+
changes.push("Content updated");
|
|
377
|
+
}
|
|
378
|
+
if (params.excerpt && originalPost.excerpt?.rendered !== updatedPost.excerpt?.rendered) {
|
|
379
|
+
changes.push("Excerpt updated");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (changes.length > 0) {
|
|
383
|
+
response += `\n**Changes Made**:\n${changes.map((c) => `- ${c}`).join("\n")}\n`;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
response += `\n**Link**: ${updatedPost.link}`;
|
|
387
|
+
|
|
388
|
+
return response;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
391
|
+
return `Post with ID ${params.id} not found. Please verify the ID and try again.`;
|
|
392
|
+
}
|
|
393
|
+
throw new Error(`Failed to update post: ${getErrorMessage(error)}`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Handles deleting a WordPress post
|
|
399
|
+
*/
|
|
400
|
+
export async function handleDeletePost(
|
|
401
|
+
client: WordPressClient,
|
|
402
|
+
params: { id: number; force?: boolean },
|
|
403
|
+
): Promise<{ deleted: boolean; previous?: WordPressPost } | string> {
|
|
404
|
+
try {
|
|
405
|
+
const postId = validateId(params.id, "post ID");
|
|
406
|
+
const result = await client.deletePost(postId, params.force);
|
|
407
|
+
|
|
408
|
+
if (result.deleted) {
|
|
409
|
+
const action = params.force ? "permanently deleted" : "moved to trash";
|
|
410
|
+
let response = `✅ **Post ${action} successfully**\n\n`;
|
|
411
|
+
|
|
412
|
+
if (result.previous) {
|
|
413
|
+
response += `**Title**: ${result.previous.title.rendered}\n`;
|
|
414
|
+
response += `**ID**: ${result.previous.id}\n`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (!params.force) {
|
|
418
|
+
response += `\n**Note**: Post moved to trash. Use \`force=true\` to permanently delete.`;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return response;
|
|
422
|
+
} else {
|
|
423
|
+
return `Failed to delete post with ID ${params.id}. It may not exist or you may not have permission.`;
|
|
424
|
+
}
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
427
|
+
return `Post with ID ${params.id} not found. Please verify the ID and try again.`;
|
|
428
|
+
}
|
|
429
|
+
throw new Error(`Failed to delete post: ${getErrorMessage(error)}`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Handles retrieving post revisions
|
|
435
|
+
*/
|
|
436
|
+
export async function handleGetPostRevisions(
|
|
437
|
+
client: WordPressClient,
|
|
438
|
+
params: { id: number },
|
|
439
|
+
): Promise<WordPressPost[] | string> {
|
|
440
|
+
try {
|
|
441
|
+
const postId = validateId(params.id, "post ID");
|
|
442
|
+
const revisions = await client.getPostRevisions(postId);
|
|
443
|
+
|
|
444
|
+
if (revisions.length === 0) {
|
|
445
|
+
return `No revisions found for post ${params.id}. This may be because revisions are disabled or the post has no revision history.`;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
let response = `📚 **Post Revisions** (${revisions.length} total)\n\n`;
|
|
449
|
+
|
|
450
|
+
revisions.forEach((revision, index) => {
|
|
451
|
+
const date = new Date(revision.date);
|
|
452
|
+
const formattedDate = date.toLocaleDateString("en-US", {
|
|
453
|
+
year: "numeric",
|
|
454
|
+
month: "short",
|
|
455
|
+
day: "numeric",
|
|
456
|
+
hour: "2-digit",
|
|
457
|
+
minute: "2-digit",
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
response += `**Revision ${index + 1}**\n`;
|
|
461
|
+
response += `- ID: ${revision.id}\n`;
|
|
462
|
+
response += `- Date: ${formattedDate}\n`;
|
|
463
|
+
response += `- Title: ${revision.title.rendered}\n`;
|
|
464
|
+
if (index < revisions.length - 1) response += "\n";
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
return response;
|
|
468
|
+
} catch (error) {
|
|
469
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
470
|
+
return `Post with ID ${params.id} not found. Please verify the ID and try again.`;
|
|
471
|
+
}
|
|
472
|
+
throw new Error(`Failed to get post revisions: ${getErrorMessage(error)}`);
|
|
473
|
+
}
|
|
474
|
+
}
|