mcp-wordpress 1.1.2
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 +21 -0
- package/README.md +568 -0
- package/bin/mcp-wordpress.js +12 -0
- package/bin/setup.js +302 -0
- package/bin/status.js +359 -0
- package/dist/client/WordPressClient.d.ts +81 -0
- package/dist/client/WordPressClient.d.ts.map +1 -0
- package/dist/client/WordPressClient.js +354 -0
- package/dist/client/WordPressClient.js.map +1 -0
- package/dist/client/api.d.ts +140 -0
- package/dist/client/api.d.ts.map +1 -0
- package/dist/client/api.js +727 -0
- package/dist/client/api.js.map +1 -0
- package/dist/client/auth.d.ts +121 -0
- package/dist/client/auth.d.ts.map +1 -0
- package/dist/client/auth.js +430 -0
- package/dist/client/auth.js.map +1 -0
- package/dist/client/managers/AuthenticationManager.d.ts +39 -0
- package/dist/client/managers/AuthenticationManager.d.ts.map +1 -0
- package/dist/client/managers/AuthenticationManager.js +159 -0
- package/dist/client/managers/AuthenticationManager.js.map +1 -0
- package/dist/client/managers/BaseManager.d.ts +22 -0
- package/dist/client/managers/BaseManager.d.ts.map +1 -0
- package/dist/client/managers/BaseManager.js +47 -0
- package/dist/client/managers/BaseManager.js.map +1 -0
- package/dist/client/managers/RequestManager.d.ts +45 -0
- package/dist/client/managers/RequestManager.d.ts.map +1 -0
- package/dist/client/managers/RequestManager.js +161 -0
- package/dist/client/managers/RequestManager.js.map +1 -0
- package/dist/client/managers/index.d.ts +8 -0
- package/dist/client/managers/index.d.ts.map +1 -0
- package/dist/client/managers/index.js +8 -0
- package/dist/client/managers/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +264 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +7 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/auth.d.ts +44 -0
- package/dist/tools/auth.d.ts.map +1 -0
- package/dist/tools/auth.js +126 -0
- package/dist/tools/auth.js.map +1 -0
- package/dist/tools/base.d.ts +37 -0
- package/dist/tools/base.d.ts.map +1 -0
- package/dist/tools/base.js +60 -0
- package/dist/tools/base.js.map +1 -0
- package/dist/tools/comments.d.ts +33 -0
- package/dist/tools/comments.d.ts.map +1 -0
- package/dist/tools/comments.js +228 -0
- package/dist/tools/comments.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/media.d.ts +29 -0
- package/dist/tools/media.d.ts.map +1 -0
- package/dist/tools/media.js +208 -0
- package/dist/tools/media.js.map +1 -0
- package/dist/tools/pages.d.ts +30 -0
- package/dist/tools/pages.d.ts.map +1 -0
- package/dist/tools/pages.js +211 -0
- package/dist/tools/pages.js.map +1 -0
- package/dist/tools/posts.d.ts +30 -0
- package/dist/tools/posts.d.ts.map +1 -0
- package/dist/tools/posts.js +240 -0
- package/dist/tools/posts.js.map +1 -0
- package/dist/tools/site.d.ts +31 -0
- package/dist/tools/site.d.ts.map +1 -0
- package/dist/tools/site.js +192 -0
- package/dist/tools/site.js.map +1 -0
- package/dist/tools/taxonomies.d.ts +37 -0
- package/dist/tools/taxonomies.d.ts.map +1 -0
- package/dist/tools/taxonomies.js +280 -0
- package/dist/tools/taxonomies.js.map +1 -0
- package/dist/tools/users.d.ts +28 -0
- package/dist/tools/users.d.ts.map +1 -0
- package/dist/tools/users.js +201 -0
- package/dist/tools/users.js.map +1 -0
- package/dist/types/client.d.ts +215 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/client.js +72 -0
- package/dist/types/client.js.map +1 -0
- package/dist/types/index.d.ts +157 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mcp.d.ts +178 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +7 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/types/wordpress.d.ts +443 -0
- package/dist/types/wordpress.d.ts.map +1 -0
- package/dist/types/wordpress.js +7 -0
- package/dist/types/wordpress.js.map +1 -0
- package/dist/utils/debug.d.ts +63 -0
- package/dist/utils/debug.d.ts.map +1 -0
- package/dist/utils/debug.js +195 -0
- package/dist/utils/debug.js.map +1 -0
- package/dist/utils/error.d.ts +19 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +71 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/toolWrapper.d.ts +36 -0
- package/dist/utils/toolWrapper.d.ts.map +1 -0
- package/dist/utils/toolWrapper.js +90 -0
- package/dist/utils/toolWrapper.js.map +1 -0
- package/package.json +115 -0
- package/src/client/api.ts +1043 -0
- package/src/client/auth.ts +527 -0
- package/src/client/managers/AuthenticationManager.ts +190 -0
- package/src/client/managers/BaseManager.ts +73 -0
- package/src/client/managers/RequestManager.ts +214 -0
- package/src/client/managers/index.ts +8 -0
- package/src/index.ts +337 -0
- package/src/server.ts +7 -0
- package/src/tools/auth.ts +153 -0
- package/src/tools/comments.ts +263 -0
- package/src/tools/index.ts +8 -0
- package/src/tools/media.ts +240 -0
- package/src/tools/pages.ts +246 -0
- package/src/tools/posts.ts +277 -0
- package/src/tools/site.ts +227 -0
- package/src/tools/taxonomies.ts +322 -0
- package/src/tools/users.ts +233 -0
- package/src/types/client.ts +304 -0
- package/src/types/index.ts +207 -0
- package/src/types/mcp.ts +247 -0
- package/src/types/wordpress.ts +491 -0
- package/src/utils/debug.ts +258 -0
- package/src/utils/error.ts +88 -0
- package/src/utils/toolWrapper.ts +105 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { WordPressClient } from "../client/api.js";
|
|
2
|
+
import { AuthMethod } from "../types/client.js";
|
|
3
|
+
import { getErrorMessage } from "../utils/error.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Provides authentication-related tools for WordPress sites.
|
|
7
|
+
* This class encapsulates tool definitions and their corresponding handlers.
|
|
8
|
+
*/
|
|
9
|
+
export class AuthTools {
|
|
10
|
+
/**
|
|
11
|
+
* Retrieves the list of authentication tools.
|
|
12
|
+
* @returns An array of MCPTool definitions.
|
|
13
|
+
*/
|
|
14
|
+
public getTools(): any[] {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
name: "wp_test_auth",
|
|
18
|
+
description:
|
|
19
|
+
"Tests the authentication and connectivity for a configured WordPress site.",
|
|
20
|
+
parameters: [], // The 'site' parameter is added dynamically by the server
|
|
21
|
+
handler: this.handleTestAuth.bind(this),
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "wp_get_auth_status",
|
|
25
|
+
description:
|
|
26
|
+
"Gets the current authentication status for a configured WordPress site.",
|
|
27
|
+
parameters: [],
|
|
28
|
+
handler: this.handleGetAuthStatus.bind(this),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "wp_switch_auth_method",
|
|
32
|
+
description:
|
|
33
|
+
"Switches the authentication method for a site for the current session.",
|
|
34
|
+
parameters: [
|
|
35
|
+
{
|
|
36
|
+
name: "method",
|
|
37
|
+
type: "string",
|
|
38
|
+
required: true,
|
|
39
|
+
description: "The new authentication method to use.",
|
|
40
|
+
enum: ["app-password", "jwt", "basic", "api-key", "cookie"],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "username",
|
|
44
|
+
type: "string",
|
|
45
|
+
description:
|
|
46
|
+
"The username for 'app-password' or 'basic' authentication.",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "password",
|
|
50
|
+
type: "string",
|
|
51
|
+
description:
|
|
52
|
+
"The Application Password for 'app-password' or password for 'basic' auth.",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "jwt_token",
|
|
56
|
+
type: "string",
|
|
57
|
+
description: "The token for 'jwt' authentication.",
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
handler: this.handleSwitchAuthMethod.bind(this),
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Handles the 'wp_test_auth' tool request.
|
|
67
|
+
* It tests the connection and fetches user details upon success.
|
|
68
|
+
* @param client - The WordPressClient instance for the target site.
|
|
69
|
+
* @param params - The parameters for the tool request.
|
|
70
|
+
* @returns A promise that resolves to an MCPToolResponse.
|
|
71
|
+
*/
|
|
72
|
+
public async handleTestAuth(
|
|
73
|
+
client: WordPressClient,
|
|
74
|
+
params: any,
|
|
75
|
+
): Promise<any> {
|
|
76
|
+
try {
|
|
77
|
+
await client.ping();
|
|
78
|
+
const user = await client.getCurrentUser();
|
|
79
|
+
const siteConfig = client.config;
|
|
80
|
+
|
|
81
|
+
const content =
|
|
82
|
+
`✅ **Authentication successful!**\n\n` +
|
|
83
|
+
`**Site:** ${siteConfig.baseUrl}\n` +
|
|
84
|
+
`**Method:** ${siteConfig.auth.method}\n` +
|
|
85
|
+
`**User:** ${user.name} (@${user.slug})\n` +
|
|
86
|
+
`**Roles:** ${user.roles?.join(", ") || "N/A"}\n\n` +
|
|
87
|
+
`Your WordPress connection is working properly.`;
|
|
88
|
+
|
|
89
|
+
return content;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new Error(`Authentication test failed: ${getErrorMessage(error)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Handles the 'wp_get_auth_status' tool request.
|
|
97
|
+
* Reports whether the client is currently authenticated.
|
|
98
|
+
* @param client - The WordPressClient instance for the target site.
|
|
99
|
+
* @param params - The parameters for the tool request.
|
|
100
|
+
* @returns A promise that resolves to an MCPToolResponse.
|
|
101
|
+
*/
|
|
102
|
+
public async handleGetAuthStatus(
|
|
103
|
+
client: WordPressClient,
|
|
104
|
+
params: any,
|
|
105
|
+
): Promise<any> {
|
|
106
|
+
try {
|
|
107
|
+
const isAuthenticated = client.isAuthenticated;
|
|
108
|
+
const config = client.config;
|
|
109
|
+
let content =
|
|
110
|
+
`**Authentication Status for ${config.baseUrl}**\n\n` +
|
|
111
|
+
`**Authenticated:** ${isAuthenticated ? "✅ Yes" : "❌ No"}\n` +
|
|
112
|
+
`**Method:** ${config.auth.method}\n`;
|
|
113
|
+
|
|
114
|
+
if (isAuthenticated) {
|
|
115
|
+
const user = await client.getCurrentUser();
|
|
116
|
+
content += `**User:** ${user.name} (@${user.slug})\n`;
|
|
117
|
+
} else {
|
|
118
|
+
content += `**Status:** Not connected. Use 'wp_test_auth' to connect and verify credentials.`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return content;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
throw new Error(`Failed to get auth status: ${getErrorMessage(error)}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Handles the 'wp_switch_auth_method' tool request.
|
|
129
|
+
* Updates the client's authentication configuration in memory for the session.
|
|
130
|
+
* @param client - The WordPressClient instance for the target site.
|
|
131
|
+
* @param params - The parameters for the tool request, including the new auth details.
|
|
132
|
+
* @returns A promise that resolves to an MCPToolResponse.
|
|
133
|
+
*/
|
|
134
|
+
public async handleSwitchAuthMethod(
|
|
135
|
+
client: WordPressClient,
|
|
136
|
+
params: {
|
|
137
|
+
method: AuthMethod;
|
|
138
|
+
username?: string;
|
|
139
|
+
password?: string;
|
|
140
|
+
jwt_token?: string;
|
|
141
|
+
},
|
|
142
|
+
): Promise<any> {
|
|
143
|
+
try {
|
|
144
|
+
// This functionality is not currently supported as the client
|
|
145
|
+
// doesn't have an updateAuthConfig method
|
|
146
|
+
throw new Error("Dynamic authentication method switching is not currently supported. Please update your configuration file and restart the server.");
|
|
147
|
+
} catch (error) {
|
|
148
|
+
throw new Error(`Failed to switch auth method: ${getErrorMessage(error)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export default AuthTools;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { WordPressClient } from "../client/api.js";
|
|
2
|
+
import {
|
|
3
|
+
CommentQueryParams,
|
|
4
|
+
CreateCommentRequest,
|
|
5
|
+
UpdateCommentRequest,
|
|
6
|
+
} from "../types/wordpress.js";
|
|
7
|
+
import { getErrorMessage } from "../utils/error.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Provides tools for managing comments on a WordPress site.
|
|
11
|
+
* This class encapsulates tool definitions and their corresponding handlers.
|
|
12
|
+
*/
|
|
13
|
+
export class CommentTools {
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves the list of comment management tools.
|
|
16
|
+
* @returns An array of MCPTool definitions.
|
|
17
|
+
*/
|
|
18
|
+
public getTools(): any[] {
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
name: "wp_list_comments",
|
|
22
|
+
description: "Lists comments from a WordPress site, with filters.",
|
|
23
|
+
parameters: [
|
|
24
|
+
{
|
|
25
|
+
name: "post",
|
|
26
|
+
type: "number",
|
|
27
|
+
description:
|
|
28
|
+
"Limit results to comments assigned to a specific post ID.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "status",
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Filter by comment status.",
|
|
34
|
+
enum: ["hold", "approve", "spam", "trash"],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
handler: this.handleListComments.bind(this),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "wp_get_comment",
|
|
41
|
+
description: "Retrieves a single comment by its ID.",
|
|
42
|
+
parameters: [
|
|
43
|
+
{
|
|
44
|
+
name: "id",
|
|
45
|
+
type: "number",
|
|
46
|
+
required: true,
|
|
47
|
+
description: "The unique identifier for the comment.",
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
handler: this.handleGetComment.bind(this),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "wp_create_comment",
|
|
54
|
+
description: "Creates a new comment on a post.",
|
|
55
|
+
parameters: [
|
|
56
|
+
{
|
|
57
|
+
name: "post",
|
|
58
|
+
type: "number",
|
|
59
|
+
required: true,
|
|
60
|
+
description: "The ID of the post to comment on.",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "content",
|
|
64
|
+
type: "string",
|
|
65
|
+
required: true,
|
|
66
|
+
description: "The content of the comment.",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "author_name",
|
|
70
|
+
type: "string",
|
|
71
|
+
description: "The name of the comment author.",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "author_email",
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "The email of the comment author.",
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
handler: this.handleCreateComment.bind(this),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "wp_update_comment",
|
|
83
|
+
description: "Updates an existing comment.",
|
|
84
|
+
parameters: [
|
|
85
|
+
{
|
|
86
|
+
name: "id",
|
|
87
|
+
type: "number",
|
|
88
|
+
required: true,
|
|
89
|
+
description: "The ID of the comment to update.",
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "content",
|
|
93
|
+
type: "string",
|
|
94
|
+
description: "The updated content for the comment.",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "status",
|
|
98
|
+
type: "string",
|
|
99
|
+
description: "The new status for the comment.",
|
|
100
|
+
enum: ["hold", "approve", "spam", "trash"],
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
handler: this.handleUpdateComment.bind(this),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "wp_delete_comment",
|
|
107
|
+
description: "Deletes a comment.",
|
|
108
|
+
parameters: [
|
|
109
|
+
{
|
|
110
|
+
name: "id",
|
|
111
|
+
type: "number",
|
|
112
|
+
required: true,
|
|
113
|
+
description: "The ID of the comment to delete.",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "force",
|
|
117
|
+
type: "boolean",
|
|
118
|
+
description:
|
|
119
|
+
"If true, the comment will be permanently deleted. Defaults to false (moved to trash).",
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
handler: this.handleDeleteComment.bind(this),
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "wp_approve_comment",
|
|
126
|
+
description: "Approves a pending comment.",
|
|
127
|
+
parameters: [
|
|
128
|
+
{
|
|
129
|
+
name: "id",
|
|
130
|
+
type: "number",
|
|
131
|
+
required: true,
|
|
132
|
+
description: "The ID of the comment to approve.",
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
handler: this.handleApproveComment.bind(this),
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "wp_spam_comment",
|
|
139
|
+
description: "Marks a comment as spam.",
|
|
140
|
+
parameters: [
|
|
141
|
+
{
|
|
142
|
+
name: "id",
|
|
143
|
+
type: "number",
|
|
144
|
+
required: true,
|
|
145
|
+
description: "The ID of the comment to mark as spam.",
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
handler: this.handleSpamComment.bind(this),
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public async handleListComments(
|
|
154
|
+
client: WordPressClient,
|
|
155
|
+
params: CommentQueryParams,
|
|
156
|
+
): Promise<any> {
|
|
157
|
+
try {
|
|
158
|
+
const comments = await client.getComments(params);
|
|
159
|
+
if (comments.length === 0) {
|
|
160
|
+
return "No comments found matching the criteria.";
|
|
161
|
+
}
|
|
162
|
+
const content =
|
|
163
|
+
`Found ${comments.length} comments:\n\n` +
|
|
164
|
+
comments
|
|
165
|
+
.map(
|
|
166
|
+
(c) =>
|
|
167
|
+
`- ID ${c.id}: By **${c.author_name}** on Post ${c.post} (${c.status})\n > ${c.content.rendered.substring(0, 100)}...`,
|
|
168
|
+
)
|
|
169
|
+
.join("\n");
|
|
170
|
+
return content;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
throw new Error(`Failed to list comments: ${getErrorMessage(error)}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public async handleGetComment(
|
|
177
|
+
client: WordPressClient,
|
|
178
|
+
params: { id: number },
|
|
179
|
+
): Promise<any> {
|
|
180
|
+
try {
|
|
181
|
+
const comment = await client.getComment(params.id);
|
|
182
|
+
const content =
|
|
183
|
+
`**Comment Details (ID: ${comment.id})**\n\n` +
|
|
184
|
+
`- **Author:** ${comment.author_name}\n` +
|
|
185
|
+
`- **Post ID:** ${comment.post}\n` +
|
|
186
|
+
`- **Date:** ${new Date(comment.date).toLocaleString()}\n` +
|
|
187
|
+
`- **Status:** ${comment.status}\n` +
|
|
188
|
+
`- **Content:** ${comment.content.rendered}`;
|
|
189
|
+
return content;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
throw new Error(`Failed to get comment: ${getErrorMessage(error)}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public async handleCreateComment(
|
|
196
|
+
client: WordPressClient,
|
|
197
|
+
params: CreateCommentRequest,
|
|
198
|
+
): Promise<any> {
|
|
199
|
+
try {
|
|
200
|
+
const comment = await client.createComment(params);
|
|
201
|
+
return `✅ Comment created successfully with ID: ${comment.id}`;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
throw new Error(`Failed to create comment: ${getErrorMessage(error)}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public async handleUpdateComment(
|
|
208
|
+
client: WordPressClient,
|
|
209
|
+
params: UpdateCommentRequest & { id: number },
|
|
210
|
+
): Promise<any> {
|
|
211
|
+
try {
|
|
212
|
+
const comment = await client.updateComment(params);
|
|
213
|
+
return `✅ Comment ${comment.id} updated successfully. New status: ${comment.status}.`;
|
|
214
|
+
} catch (error) {
|
|
215
|
+
throw new Error(`Failed to update comment: ${getErrorMessage(error)}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public async handleDeleteComment(
|
|
220
|
+
client: WordPressClient,
|
|
221
|
+
params: { id: number; force?: boolean },
|
|
222
|
+
): Promise<any> {
|
|
223
|
+
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}.`;
|
|
227
|
+
} catch (error) {
|
|
228
|
+
throw new Error(`Failed to delete comment: ${getErrorMessage(error)}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public async handleApproveComment(
|
|
233
|
+
client: WordPressClient,
|
|
234
|
+
params: { id: number },
|
|
235
|
+
): Promise<any> {
|
|
236
|
+
try {
|
|
237
|
+
const comment = await client.updateComment({
|
|
238
|
+
id: params.id,
|
|
239
|
+
status: "approved",
|
|
240
|
+
});
|
|
241
|
+
return `✅ Comment ${comment.id} has been approved.`;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
throw new Error(`Failed to approve comment: ${getErrorMessage(error)}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
public async handleSpamComment(
|
|
248
|
+
client: WordPressClient,
|
|
249
|
+
params: { id: number },
|
|
250
|
+
): Promise<any> {
|
|
251
|
+
try {
|
|
252
|
+
const comment = await client.updateComment({
|
|
253
|
+
id: params.id,
|
|
254
|
+
status: "spam",
|
|
255
|
+
});
|
|
256
|
+
return `✅ Comment ${comment.id} has been marked as spam.`;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
throw new Error(`Failed to mark comment as spam: ${getErrorMessage(error)}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export default CommentTools;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default as AuthTools } from './auth.js';
|
|
2
|
+
export { default as CommentTools } from './comments.js';
|
|
3
|
+
export { default as MediaTools } from './media.js';
|
|
4
|
+
export { default as PageTools } from './pages.js';
|
|
5
|
+
export { default as PostTools } from './posts.js';
|
|
6
|
+
export { default as SiteTools } from './site.js';
|
|
7
|
+
export { default as TaxonomyTools } from './taxonomies.js';
|
|
8
|
+
export { default as UserTools } from './users.js';
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { WordPressClient } from "../client/api.js";
|
|
4
|
+
import {
|
|
5
|
+
MediaQueryParams,
|
|
6
|
+
UpdateMediaRequest,
|
|
7
|
+
UploadMediaRequest,
|
|
8
|
+
WordPressMedia,
|
|
9
|
+
} from "../types/wordpress.js";
|
|
10
|
+
import { getErrorMessage } from "../utils/error.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Provides tools for managing media on a WordPress site.
|
|
14
|
+
* This class encapsulates tool definitions and their corresponding handlers.
|
|
15
|
+
*/
|
|
16
|
+
export class MediaTools {
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves the list of media management tools.
|
|
19
|
+
* @returns An array of MCPTool definitions.
|
|
20
|
+
*/
|
|
21
|
+
public getTools(): any[] {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
name: "wp_list_media",
|
|
25
|
+
description: "Lists media items from a WordPress site, with filters.",
|
|
26
|
+
parameters: [
|
|
27
|
+
{
|
|
28
|
+
name: "per_page",
|
|
29
|
+
type: "number",
|
|
30
|
+
description: "Number of items to return per page (max 100).",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "search",
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Limit results to those matching a search term.",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "media_type",
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Limit results to a specific media type.",
|
|
41
|
+
enum: ["image", "video", "audio", "application"],
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
handler: this.handleListMedia.bind(this),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "wp_get_media",
|
|
48
|
+
description: "Retrieves a single media item by its ID.",
|
|
49
|
+
parameters: [
|
|
50
|
+
{
|
|
51
|
+
name: "id",
|
|
52
|
+
type: "number",
|
|
53
|
+
required: true,
|
|
54
|
+
description: "The unique identifier for the media item.",
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
handler: this.handleGetMedia.bind(this),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "wp_upload_media",
|
|
61
|
+
description: "Uploads a file to the WordPress media library.",
|
|
62
|
+
parameters: [
|
|
63
|
+
{
|
|
64
|
+
name: "file_path",
|
|
65
|
+
type: "string",
|
|
66
|
+
required: true,
|
|
67
|
+
description: "The local, absolute path to the file to upload.",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "title",
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "The title for the media item.",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "alt_text",
|
|
76
|
+
type: "string",
|
|
77
|
+
description:
|
|
78
|
+
"Alternative text for the media item (for accessibility).",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "caption",
|
|
82
|
+
type: "string",
|
|
83
|
+
description: "The caption for the media item.",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "description",
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "The description for the media item.",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "post",
|
|
92
|
+
type: "number",
|
|
93
|
+
description: "The ID of a post to attach this media to.",
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
handler: this.handleUploadMedia.bind(this),
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "wp_update_media",
|
|
100
|
+
description: "Updates the metadata of an existing media item.",
|
|
101
|
+
parameters: [
|
|
102
|
+
{
|
|
103
|
+
name: "id",
|
|
104
|
+
type: "number",
|
|
105
|
+
required: true,
|
|
106
|
+
description: "The ID of the media item to update.",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "title",
|
|
110
|
+
type: "string",
|
|
111
|
+
description: "The new title for the media item.",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "alt_text",
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "The new alternative text.",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: "caption",
|
|
120
|
+
type: "string",
|
|
121
|
+
description: "The new caption.",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "description",
|
|
125
|
+
type: "string",
|
|
126
|
+
description: "The new description.",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
handler: this.handleUpdateMedia.bind(this),
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: "wp_delete_media",
|
|
133
|
+
description: "Deletes a media item.",
|
|
134
|
+
parameters: [
|
|
135
|
+
{
|
|
136
|
+
name: "id",
|
|
137
|
+
type: "number",
|
|
138
|
+
required: true,
|
|
139
|
+
description: "The ID of the media item to delete.",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "force",
|
|
143
|
+
type: "boolean",
|
|
144
|
+
description:
|
|
145
|
+
"If true, permanently delete. If false, move to trash. Defaults to false.",
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
handler: this.handleDeleteMedia.bind(this),
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public async handleListMedia(
|
|
154
|
+
client: WordPressClient,
|
|
155
|
+
params: MediaQueryParams,
|
|
156
|
+
): Promise<any> {
|
|
157
|
+
try {
|
|
158
|
+
const media = await client.getMedia(params);
|
|
159
|
+
if (media.length === 0) {
|
|
160
|
+
return "No media items found matching the criteria.";
|
|
161
|
+
}
|
|
162
|
+
const content =
|
|
163
|
+
`Found ${media.length} media items:\n\n` +
|
|
164
|
+
media
|
|
165
|
+
.map(
|
|
166
|
+
(m) =>
|
|
167
|
+
`- ID ${m.id}: **${m.title.rendered}** (${m.mime_type})\n Link: ${m.source_url}`,
|
|
168
|
+
)
|
|
169
|
+
.join("\n");
|
|
170
|
+
return content;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
throw new Error(`Failed to list media: ${getErrorMessage(error)}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public async handleGetMedia(
|
|
177
|
+
client: WordPressClient,
|
|
178
|
+
params: { id: number },
|
|
179
|
+
): Promise<any> {
|
|
180
|
+
try {
|
|
181
|
+
const media = await client.getMediaItem(params.id);
|
|
182
|
+
const content =
|
|
183
|
+
`**Media Details (ID: ${media.id})**\n\n` +
|
|
184
|
+
`- **Title:** ${media.title.rendered}\n` +
|
|
185
|
+
`- **URL:** ${media.source_url}\n` +
|
|
186
|
+
`- **Type:** ${media.media_type} (${media.mime_type})\n` +
|
|
187
|
+
`- **Date:** ${new Date(media.date).toLocaleString()}\n` +
|
|
188
|
+
(media.alt_text ? `- **Alt Text:** ${media.alt_text}\n` : "") +
|
|
189
|
+
(media.caption.rendered
|
|
190
|
+
? `- **Caption:** ${media.caption.rendered}\n`
|
|
191
|
+
: "");
|
|
192
|
+
return content;
|
|
193
|
+
} catch (error) {
|
|
194
|
+
throw new Error(`Failed to get media item: ${getErrorMessage(error)}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public async handleUploadMedia(
|
|
199
|
+
client: WordPressClient,
|
|
200
|
+
params: UploadMediaRequest & { file_path: string },
|
|
201
|
+
): Promise<any> {
|
|
202
|
+
try {
|
|
203
|
+
if (!fs.existsSync(params.file_path)) {
|
|
204
|
+
throw new Error(`File not found at path: ${params.file_path}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const media = await client.uploadMedia(params);
|
|
208
|
+
return `✅ Media uploaded successfully!\n- ID: ${media.id}\n- Title: ${media.title.rendered}\n- URL: ${media.source_url}`;
|
|
209
|
+
} catch (error) {
|
|
210
|
+
throw new Error(`Failed to upload media: ${getErrorMessage(error)}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public async handleUpdateMedia(
|
|
215
|
+
client: WordPressClient,
|
|
216
|
+
params: UpdateMediaRequest & { id: number },
|
|
217
|
+
): Promise<any> {
|
|
218
|
+
try {
|
|
219
|
+
const media = await client.updateMedia(params);
|
|
220
|
+
return `✅ Media ${media.id} updated successfully.`;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
throw new Error(`Failed to update media: ${getErrorMessage(error)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public async handleDeleteMedia(
|
|
227
|
+
client: WordPressClient,
|
|
228
|
+
params: { id: number; force?: boolean },
|
|
229
|
+
): Promise<any> {
|
|
230
|
+
try {
|
|
231
|
+
await client.deleteMedia(params.id, params.force);
|
|
232
|
+
const action = params.force ? "permanently deleted" : "moved to trash";
|
|
233
|
+
return `✅ Media item ${params.id} has been ${action}.`;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
throw new Error(`Failed to delete media: ${getErrorMessage(error)}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export default MediaTools;
|