mcp-wordpress 1.5.2 → 2.0.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 (190) hide show
  1. package/README.md +332 -61
  2. package/dist/cache/CacheInvalidation.d.ts.map +1 -1
  3. package/dist/cache/CacheInvalidation.js +4 -4
  4. package/dist/cache/CacheInvalidation.js.map +1 -1
  5. package/dist/client/MockWordPressClient.d.ts +55 -0
  6. package/dist/client/MockWordPressClient.d.ts.map +1 -0
  7. package/dist/client/MockWordPressClient.js +369 -0
  8. package/dist/client/MockWordPressClient.js.map +1 -0
  9. package/dist/client/api.d.ts +1 -0
  10. package/dist/client/api.d.ts.map +1 -1
  11. package/dist/client/api.js +26 -60
  12. package/dist/client/api.js.map +1 -1
  13. package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
  14. package/dist/client/managers/AuthenticationManager.js +4 -3
  15. package/dist/client/managers/AuthenticationManager.js.map +1 -1
  16. package/dist/config/ConfigurationSchema.d.ts +3 -3
  17. package/dist/config/ConfigurationSchema.d.ts.map +1 -1
  18. package/dist/config/ConfigurationSchema.js +7 -24
  19. package/dist/config/ConfigurationSchema.js.map +1 -1
  20. package/dist/config/ServerConfiguration.d.ts +8 -0
  21. package/dist/config/ServerConfiguration.d.ts.map +1 -1
  22. package/dist/config/ServerConfiguration.js +80 -31
  23. package/dist/config/ServerConfiguration.js.map +1 -1
  24. package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
  25. package/dist/docs/DocumentationGenerator.js +5 -7
  26. package/dist/docs/DocumentationGenerator.js.map +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +33 -29
  29. package/dist/index.js.map +1 -1
  30. package/dist/security/InputValidator.d.ts.map +1 -1
  31. package/dist/security/InputValidator.js +3 -11
  32. package/dist/security/InputValidator.js.map +1 -1
  33. package/dist/server/ToolRegistry.d.ts +4 -0
  34. package/dist/server/ToolRegistry.d.ts.map +1 -1
  35. package/dist/server/ToolRegistry.js +71 -8
  36. package/dist/server/ToolRegistry.js.map +1 -1
  37. package/dist/tools/auth.d.ts.map +1 -1
  38. package/dist/tools/auth.js +8 -3
  39. package/dist/tools/auth.js.map +1 -1
  40. package/dist/tools/posts.d.ts.map +1 -1
  41. package/dist/tools/posts.js +287 -20
  42. package/dist/tools/posts.js.map +1 -1
  43. package/dist/tools/site.d.ts.map +1 -1
  44. package/dist/tools/site.js +47 -9
  45. package/dist/tools/site.js.map +1 -1
  46. package/dist/tools/users.d.ts.map +1 -1
  47. package/dist/tools/users.js +113 -10
  48. package/dist/tools/users.js.map +1 -1
  49. package/dist/utils/enhancedError.d.ts +61 -0
  50. package/dist/utils/enhancedError.d.ts.map +1 -0
  51. package/dist/utils/enhancedError.js +221 -0
  52. package/dist/utils/enhancedError.js.map +1 -0
  53. package/dist/utils/streaming.d.ts +104 -0
  54. package/dist/utils/streaming.d.ts.map +1 -0
  55. package/dist/utils/streaming.js +312 -0
  56. package/dist/utils/streaming.js.map +1 -0
  57. package/dist/utils/validation.d.ts +19 -3
  58. package/dist/utils/validation.d.ts.map +1 -1
  59. package/dist/utils/validation.js +174 -24
  60. package/dist/utils/validation.js.map +1 -1
  61. package/docs/ARCHITECTURE.md +850 -0
  62. package/docs/CACHING.md +20 -17
  63. package/docs/CONFIGURATION.md +660 -0
  64. package/docs/DOCKER.md +61 -60
  65. package/docs/EVALUATION.md +397 -0
  66. package/docs/INSTALLATION.md +423 -0
  67. package/docs/PERFORMANCE_MONITORING.md +17 -15
  68. package/docs/SECURITY.md +621 -0
  69. package/docs/SECURITY_TESTING.md +22 -26
  70. package/docs/TEST_SITE_SETUP.md +136 -0
  71. package/docs/TROUBLESHOOTING.md +578 -0
  72. package/docs/api/README.md +76 -91
  73. package/docs/api/categories/auth.md +0 -2
  74. package/docs/api/categories/cache.md +0 -2
  75. package/docs/api/categories/comment.md +0 -2
  76. package/docs/api/categories/media.md +0 -2
  77. package/docs/api/categories/page.md +0 -2
  78. package/docs/api/categories/performance.md +0 -2
  79. package/docs/api/categories/post.md +0 -2
  80. package/docs/api/categories/site.md +0 -2
  81. package/docs/api/categories/taxonomy.md +0 -2
  82. package/docs/api/categories/user.md +0 -2
  83. package/docs/api/summary.json +1 -1
  84. package/docs/api/tools/wp_approve_comment.md +11 -3
  85. package/docs/api/tools/wp_cache_clear.md +14 -5
  86. package/docs/api/tools/wp_cache_info.md +14 -5
  87. package/docs/api/tools/wp_cache_stats.md +14 -5
  88. package/docs/api/tools/wp_cache_warm.md +14 -5
  89. package/docs/api/tools/wp_create_application_password.md +11 -3
  90. package/docs/api/tools/wp_create_category.md +11 -3
  91. package/docs/api/tools/wp_create_comment.md +14 -5
  92. package/docs/api/tools/wp_create_page.md +13 -5
  93. package/docs/api/tools/wp_create_post.md +14 -7
  94. package/docs/api/tools/wp_create_tag.md +11 -3
  95. package/docs/api/tools/wp_create_user.md +13 -5
  96. package/docs/api/tools/wp_delete_application_password.md +11 -3
  97. package/docs/api/tools/wp_delete_category.md +11 -3
  98. package/docs/api/tools/wp_delete_comment.md +11 -3
  99. package/docs/api/tools/wp_delete_media.md +10 -3
  100. package/docs/api/tools/wp_delete_page.md +10 -3
  101. package/docs/api/tools/wp_delete_post.md +11 -5
  102. package/docs/api/tools/wp_delete_tag.md +11 -3
  103. package/docs/api/tools/wp_delete_user.md +10 -3
  104. package/docs/api/tools/wp_get_application_passwords.md +11 -3
  105. package/docs/api/tools/wp_get_auth_status.md +11 -3
  106. package/docs/api/tools/wp_get_category.md +11 -3
  107. package/docs/api/tools/wp_get_comment.md +11 -3
  108. package/docs/api/tools/wp_get_current_user.md +11 -3
  109. package/docs/api/tools/wp_get_media.md +11 -3
  110. package/docs/api/tools/wp_get_page.md +11 -3
  111. package/docs/api/tools/wp_get_page_revisions.md +11 -3
  112. package/docs/api/tools/wp_get_post.md +12 -5
  113. package/docs/api/tools/wp_get_post_revisions.md +11 -3
  114. package/docs/api/tools/wp_get_site_settings.md +10 -3
  115. package/docs/api/tools/wp_get_tag.md +11 -3
  116. package/docs/api/tools/wp_get_user.md +11 -3
  117. package/docs/api/tools/wp_list_categories.md +11 -3
  118. package/docs/api/tools/wp_list_comments.md +11 -3
  119. package/docs/api/tools/wp_list_media.md +14 -5
  120. package/docs/api/tools/wp_list_pages.md +14 -5
  121. package/docs/api/tools/wp_list_posts.md +15 -7
  122. package/docs/api/tools/wp_list_tags.md +11 -3
  123. package/docs/api/tools/wp_list_users.md +11 -3
  124. package/docs/api/tools/wp_performance_alerts.md +17 -7
  125. package/docs/api/tools/wp_performance_benchmark.md +17 -7
  126. package/docs/api/tools/wp_performance_export.md +17 -7
  127. package/docs/api/tools/wp_performance_history.md +17 -7
  128. package/docs/api/tools/wp_performance_optimize.md +17 -7
  129. package/docs/api/tools/wp_performance_stats.md +17 -7
  130. package/docs/api/tools/wp_search_site.md +11 -3
  131. package/docs/api/tools/wp_spam_comment.md +11 -3
  132. package/docs/api/tools/wp_switch_auth_method.md +14 -5
  133. package/docs/api/tools/wp_test_auth.md +11 -3
  134. package/docs/api/tools/wp_update_category.md +11 -3
  135. package/docs/api/tools/wp_update_comment.md +14 -5
  136. package/docs/api/tools/wp_update_media.md +14 -5
  137. package/docs/api/tools/wp_update_page.md +13 -5
  138. package/docs/api/tools/wp_update_post.md +14 -7
  139. package/docs/api/tools/wp_update_site_settings.md +14 -5
  140. package/docs/api/tools/wp_update_tag.md +11 -3
  141. package/docs/api/tools/wp_update_user.md +13 -5
  142. package/docs/api/tools/wp_upload_media.md +13 -5
  143. package/docs/api/types/WordPressPost.md +2 -0
  144. package/docs/code-improvements.md +40 -0
  145. package/docs/contract-testing.md +1 -1
  146. package/docs/developer/API_REFERENCE.md +19 -59
  147. package/docs/developer/ARCHITECTURE.md +8 -11
  148. package/docs/developer/BUILD_SYSTEM.md +2 -2
  149. package/docs/developer/CONTRIBUTING.md +3 -5
  150. package/docs/developer/GITHUB_ACTIONS_SETUP.md +2 -2
  151. package/docs/developer/MIGRATION_GUIDE.md +5 -6
  152. package/docs/developer/README.md +2 -1
  153. package/docs/developer/REFACTORING.md +9 -15
  154. package/docs/developer/RELEASE_PROCESS.md +4 -3
  155. package/docs/developer/TESTING.md +2 -2
  156. package/docs/examples/claude-desktop-config.md +8 -0
  157. package/docs/integrations/claude-desktop.md +426 -0
  158. package/docs/integrations/cline.md +537 -0
  159. package/docs/integrations/vs-code.md +515 -0
  160. package/docs/releases/COMMUNITY_ANNOUNCEMENT_v1.1.2.md +30 -23
  161. package/docs/releases/RELEASE_NOTES_v1.1.2.md +7 -6
  162. package/docs/testing-configurations.md +11 -0
  163. package/docs/user-guides/DOCKER_NPM_DTX_SETUP.md +3 -2
  164. package/docs/user-guides/DOCKER_SETUP.md +3 -2
  165. package/docs/user-guides/DTX_SETUP.md +6 -5
  166. package/docs/user-guides/DXT_INSTALLATION.md +4 -4
  167. package/docs/user-guides/NPM_SETUP.md +4 -2
  168. package/docs/user-guides/NPX_SETUP.md +4 -2
  169. package/docs/user-guides/SMITHERY_SETUP.md +402 -0
  170. package/docs/wordpress-rest-api-authentication-troubleshooting.md +45 -42
  171. package/package.json +12 -2
  172. package/src/cache/CacheInvalidation.ts +7 -18
  173. package/src/client/MockWordPressClient.ts +398 -0
  174. package/src/client/api.ts +77 -237
  175. package/src/client/managers/AuthenticationManager.ts +19 -56
  176. package/src/config/ConfigurationSchema.ts +14 -45
  177. package/src/config/ServerConfiguration.ts +98 -71
  178. package/src/docs/DocumentationGenerator.ts +39 -123
  179. package/src/dxt-entry.cjs +4 -1
  180. package/src/index.ts +35 -54
  181. package/src/security/InputValidator.ts +15 -57
  182. package/src/server/ToolRegistry.ts +88 -17
  183. package/src/tools/auth.ts +15 -22
  184. package/src/tools/posts.ts +347 -64
  185. package/src/tools/site.ts +69 -46
  186. package/src/tools/users.ts +142 -44
  187. package/src/utils/enhancedError.ts +248 -0
  188. package/src/utils/streaming.ts +428 -0
  189. package/src/utils/validation.ts +253 -92
  190. package/dist/mcp-wordpress-1.5.2.tgz +0 -0
@@ -16,8 +16,7 @@ export class AuthenticationManager extends BaseManager {
16
16
  * Get authentication from environment variables
17
17
  */
18
18
  static getAuthFromEnv(): AuthConfig {
19
- const method: AuthMethod =
20
- (process.env.WORDPRESS_AUTH_METHOD as AuthMethod) || "app-password";
19
+ const method: AuthMethod = (process.env.WORDPRESS_AUTH_METHOD as AuthMethod) || "app-password";
21
20
 
22
21
  switch (method) {
23
22
  case "app-password":
@@ -31,10 +30,7 @@ export class AuthenticationManager extends BaseManager {
31
30
  return {
32
31
  method: "jwt",
33
32
  username: process.env.WORDPRESS_USERNAME || "",
34
- password:
35
- process.env.WORDPRESS_JWT_PASSWORD ||
36
- process.env.WORDPRESS_PASSWORD ||
37
- "",
33
+ password: process.env.WORDPRESS_JWT_PASSWORD || process.env.WORDPRESS_PASSWORD || "",
38
34
  secret: process.env.WORDPRESS_JWT_SECRET || "",
39
35
  };
40
36
 
@@ -52,10 +48,7 @@ export class AuthenticationManager extends BaseManager {
52
48
  };
53
49
 
54
50
  default:
55
- throw new AuthenticationError(
56
- `Unsupported authentication method: ${method}`,
57
- method,
58
- );
51
+ throw new AuthenticationError(`Unsupported authentication method: ${method}`, method);
59
52
  }
60
53
  }
61
54
 
@@ -65,18 +58,17 @@ export class AuthenticationManager extends BaseManager {
65
58
  async getAuthHeaders(): Promise<Record<string, string>> {
66
59
  const auth = this.config.auth;
67
60
 
61
+ if (!auth) {
62
+ throw new AuthenticationError("Authentication configuration is required", "app-password");
63
+ }
64
+
68
65
  switch (auth.method) {
69
66
  case "app-password":
70
67
  if (!auth.username || !auth.appPassword) {
71
- throw new AuthenticationError(
72
- "Username and app password are required",
73
- auth.method,
74
- );
68
+ throw new AuthenticationError("Username and app password are required", auth.method);
75
69
  }
76
70
 
77
- const credentials = Buffer.from(
78
- `${auth.username}:${auth.appPassword}`,
79
- ).toString("base64");
71
+ const credentials = Buffer.from(`${auth.username}:${auth.appPassword}`).toString("base64");
80
72
  return { Authorization: `Basic ${credentials}` };
81
73
 
82
74
  case "jwt":
@@ -87,15 +79,10 @@ export class AuthenticationManager extends BaseManager {
87
79
 
88
80
  case "basic":
89
81
  if (!auth.username || !auth.password) {
90
- throw new AuthenticationError(
91
- "Username and password are required",
92
- auth.method,
93
- );
82
+ throw new AuthenticationError("Username and password are required", auth.method);
94
83
  }
95
84
 
96
- const basicCredentials = Buffer.from(
97
- `${auth.username}:${auth.password}`,
98
- ).toString("base64");
85
+ const basicCredentials = Buffer.from(`${auth.username}:${auth.password}`).toString("base64");
99
86
  return { Authorization: `Basic ${basicCredentials}` };
100
87
 
101
88
  case "api-key":
@@ -105,10 +92,7 @@ export class AuthenticationManager extends BaseManager {
105
92
  return { "X-API-Key": auth.apiKey };
106
93
 
107
94
  default:
108
- throw new AuthenticationError(
109
- `Unsupported authentication method: ${auth.method}`,
110
- auth.method,
111
- );
95
+ throw new AuthenticationError(`Unsupported authentication method: ${auth.method}`, auth.method);
112
96
  }
113
97
  }
114
98
 
@@ -119,19 +103,13 @@ export class AuthenticationManager extends BaseManager {
119
103
  const auth = this.config.auth;
120
104
 
121
105
  if (auth.method !== "jwt" || !auth.username || !auth.password) {
122
- throw new AuthenticationError(
123
- "JWT authentication requires username and password",
124
- "jwt",
125
- );
106
+ throw new AuthenticationError("JWT authentication requires username and password", "jwt");
126
107
  }
127
108
 
128
109
  try {
129
110
  // This would need the RequestManager instance to make the request
130
111
  // For now, we'll throw an error indicating this needs to be implemented
131
- throw new AuthenticationError(
132
- "JWT authentication requires RequestManager integration",
133
- "jwt",
134
- );
112
+ throw new AuthenticationError("JWT authentication requires RequestManager integration", "jwt");
135
113
  } catch (error) {
136
114
  this.handleError(error, "JWT authentication");
137
115
  }
@@ -180,10 +158,7 @@ export class AuthenticationManager extends BaseManager {
180
158
  const auth = this.config.auth;
181
159
 
182
160
  if (!auth.method) {
183
- throw new AuthenticationError(
184
- "Authentication method is required",
185
- "app-password",
186
- );
161
+ throw new AuthenticationError("Authentication method is required", "app-password");
187
162
  }
188
163
 
189
164
  switch (auth.method) {
@@ -198,36 +173,24 @@ export class AuthenticationManager extends BaseManager {
198
173
 
199
174
  case "jwt":
200
175
  if (!auth.username || !auth.password || !auth.secret) {
201
- throw new AuthenticationError(
202
- "JWT authentication requires username, password, and secret",
203
- "jwt",
204
- );
176
+ throw new AuthenticationError("JWT authentication requires username, password, and secret", "jwt");
205
177
  }
206
178
  break;
207
179
 
208
180
  case "basic":
209
181
  if (!auth.username || !auth.password) {
210
- throw new AuthenticationError(
211
- "Basic authentication requires username and password",
212
- "basic",
213
- );
182
+ throw new AuthenticationError("Basic authentication requires username and password", "basic");
214
183
  }
215
184
  break;
216
185
 
217
186
  case "api-key":
218
187
  if (!auth.apiKey) {
219
- throw new AuthenticationError(
220
- "API key authentication requires apiKey",
221
- "api-key",
222
- );
188
+ throw new AuthenticationError("API key authentication requires apiKey", "api-key");
223
189
  }
224
190
  break;
225
191
 
226
192
  default:
227
- throw new AuthenticationError(
228
- `Unsupported authentication method: ${auth.method}`,
229
- auth.method,
230
- );
193
+ throw new AuthenticationError(`Unsupported authentication method: ${auth.method}`, auth.method);
231
194
  }
232
195
  }
233
196
  }
@@ -3,13 +3,7 @@ import { z } from "zod";
3
3
  /**
4
4
  * Zod schema for WordPress authentication methods
5
5
  */
6
- const AuthMethodSchema = z.enum([
7
- "app-password",
8
- "jwt",
9
- "basic",
10
- "api-key",
11
- "cookie",
12
- ] as const);
6
+ const AuthMethodSchema = z.enum(["app-password", "jwt", "basic", "api-key", "cookie"] as const);
13
7
 
14
8
  /**
15
9
  * Zod schema for URL validation
@@ -51,14 +45,8 @@ const SiteSchema = z.object({
51
45
  .string()
52
46
  .min(1, "Site ID is required")
53
47
  .max(50, "Site ID must be 50 characters or less")
54
- .regex(
55
- /^[a-zA-Z0-9_-]+$/,
56
- "Site ID can only contain letters, numbers, underscores, and hyphens",
57
- ),
58
- name: z
59
- .string()
60
- .min(1, "Site name is required")
61
- .max(100, "Site name must be 100 characters or less"),
48
+ .regex(/^[a-zA-Z0-9_-]+$/, "Site ID can only contain letters, numbers, underscores, and hyphens"),
49
+ name: z.string().min(1, "Site name is required").max(100, "Site name must be 100 characters or less"),
62
50
  config: SiteConfigSchema,
63
51
  });
64
52
 
@@ -96,7 +84,7 @@ const EnvironmentConfigSchema = z.object({
96
84
  WORDPRESS_APP_PASSWORD: SiteConfigSchema.shape.WORDPRESS_APP_PASSWORD,
97
85
  WORDPRESS_AUTH_METHOD: AuthMethodSchema.optional().default("app-password"),
98
86
  // Optional environment variables
99
- NODE_ENV: z.enum(["development", "production", "test"]).optional(),
87
+ NODE_ENV: z.enum(["development", "production", "test", "dxt", "ci"]).optional(),
100
88
  DEBUG: z.string().optional(),
101
89
  DISABLE_CACHE: z.string().optional(),
102
90
  LOG_LEVEL: z.enum(["error", "warn", "info", "debug"]).optional(),
@@ -109,8 +97,7 @@ const McpConfigSchema = z
109
97
  .object({
110
98
  wordpressSiteUrl: UrlSchema.optional(),
111
99
  wordpressUsername: SiteConfigSchema.shape.WORDPRESS_USERNAME.optional(),
112
- wordpressAppPassword:
113
- SiteConfigSchema.shape.WORDPRESS_APP_PASSWORD.optional(),
100
+ wordpressAppPassword: SiteConfigSchema.shape.WORDPRESS_APP_PASSWORD.optional(),
114
101
  wordpressAuthMethod: AuthMethodSchema.optional(),
115
102
  })
116
103
  .optional();
@@ -136,12 +123,8 @@ export class ConfigurationValidator {
136
123
  return MultiSiteConfigSchema.parse(config);
137
124
  } catch (error) {
138
125
  if (error instanceof z.ZodError) {
139
- const messages = error.errors
140
- .map((err) => `${err.path.join(".")}: ${err.message}`)
141
- .join("; ");
142
- throw new Error(
143
- `Multi-site configuration validation failed: ${messages}`,
144
- );
126
+ const messages = error.errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
127
+ throw new Error(`Multi-site configuration validation failed: ${messages}`);
145
128
  }
146
129
  throw error;
147
130
  }
@@ -150,19 +133,13 @@ export class ConfigurationValidator {
150
133
  /**
151
134
  * Validate environment configuration for single-site mode
152
135
  */
153
- static validateEnvironmentConfig(
154
- env: Record<string, string | undefined>,
155
- ): EnvironmentConfigType {
136
+ static validateEnvironmentConfig(env: Record<string, string | undefined>): EnvironmentConfigType {
156
137
  try {
157
138
  return EnvironmentConfigSchema.parse(env);
158
139
  } catch (error) {
159
140
  if (error instanceof z.ZodError) {
160
- const messages = error.errors
161
- .map((err) => `${err.path.join(".")}: ${err.message}`)
162
- .join("; ");
163
- throw new Error(
164
- `Environment configuration validation failed: ${messages}`,
165
- );
141
+ const messages = error.errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
142
+ throw new Error(`Environment configuration validation failed: ${messages}`);
166
143
  }
167
144
  throw error;
168
145
  }
@@ -176,9 +153,7 @@ export class ConfigurationValidator {
176
153
  return McpConfigSchema.parse(config);
177
154
  } catch (error) {
178
155
  if (error instanceof z.ZodError) {
179
- const messages = error.errors
180
- .map((err) => `${err.path.join(".")}: ${err.message}`)
181
- .join("; ");
156
+ const messages = error.errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
182
157
  throw new Error(`MCP configuration validation failed: ${messages}`);
183
158
  }
184
159
  throw error;
@@ -193,9 +168,7 @@ export class ConfigurationValidator {
193
168
  return SiteSchema.parse(config);
194
169
  } catch (error) {
195
170
  if (error instanceof z.ZodError) {
196
- const messages = error.errors
197
- .map((err) => `${err.path.join(".")}: ${err.message}`)
198
- .join("; ");
171
+ const messages = error.errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
199
172
  throw new Error(`Site configuration validation failed: ${messages}`);
200
173
  }
201
174
  throw error;
@@ -213,9 +186,7 @@ export class ConfigurationValidator {
213
186
  /**
214
187
  * Check if environment configuration is valid without throwing
215
188
  */
216
- static isValidEnvironmentConfig(
217
- env: Record<string, string | undefined>,
218
- ): boolean {
189
+ static isValidEnvironmentConfig(env: Record<string, string | undefined>): boolean {
219
190
  const result = EnvironmentConfigSchema.safeParse(env);
220
191
  return result.success;
221
192
  }
@@ -228,9 +199,7 @@ export class ConfigurationValidator {
228
199
  if (result.success) {
229
200
  return [];
230
201
  }
231
- return result.error.errors.map(
232
- (err) => `${err.path.join(".")}: ${err.message}`,
233
- );
202
+ return result.error.errors.map((err) => `${err.path.join(".")}: ${err.message}`);
234
203
  }
235
204
  }
236
205
 
@@ -4,6 +4,7 @@ import * as path from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  import { WordPressClient } from "../client/api.js";
6
6
  import { CachedWordPressClient } from "../client/CachedWordPressClient.js";
7
+ import { MockWordPressClient } from "../client/MockWordPressClient.js";
7
8
  import { WordPressClientConfig } from "../types/client.js";
8
9
  import { getErrorMessage } from "../utils/error.js";
9
10
  import {
@@ -34,13 +35,14 @@ export class ServerConfiguration {
34
35
  // Load environment variables
35
36
  dotenv.config({ path: this.envPath });
36
37
 
37
- // Debug output for DXT troubleshooting
38
- console.error("DEBUG: ServerConfiguration initialized");
39
- console.error(`DEBUG: Root directory: ${this.rootDir}`);
40
- console.error(`DEBUG: Environment file path: ${this.envPath}`);
41
- console.error(
42
- `DEBUG: Environment file exists: ${fs.existsSync(this.envPath)}`,
43
- );
38
+ // Debug output for DXT troubleshooting (reduced in DXT mode)
39
+ const isDXTMode = process.env.NODE_ENV === "dxt";
40
+ if (!isDXTMode) {
41
+ console.error("DEBUG: ServerConfiguration initialized");
42
+ console.error(`DEBUG: Root directory: ${this.rootDir}`);
43
+ console.error(`DEBUG: Environment file path: ${this.envPath}`);
44
+ console.error(`DEBUG: Environment file exists: ${fs.existsSync(this.envPath)}`);
45
+ }
44
46
  }
45
47
 
46
48
  /**
@@ -65,9 +67,7 @@ export class ServerConfiguration {
65
67
 
66
68
  if (fs.existsSync(configPath)) {
67
69
  if (process.env.NODE_ENV !== "test") {
68
- console.error(
69
- "INFO: Found mcp-wordpress.config.json, loading multi-site configuration.",
70
- );
70
+ console.error("INFO: Found mcp-wordpress.config.json, loading multi-site configuration.");
71
71
  }
72
72
  return this.loadMultiSiteConfig(configPath);
73
73
  } else {
@@ -116,21 +116,69 @@ export class ServerConfiguration {
116
116
  validConfigs.push(site);
117
117
 
118
118
  if (process.env.NODE_ENV !== "test") {
119
- console.error(
120
- `INFO: Initialized client for site: ${site.name} (ID: ${site.id})`,
121
- );
119
+ console.error(`INFO: Initialized client for site: ${site.name} (ID: ${site.id})`);
122
120
  }
123
121
  }
124
122
 
125
123
  return { clients, configs: validConfigs };
126
124
  } catch (error) {
127
- console.error(
128
- `FATAL: Error reading or parsing mcp-wordpress.config.json: ${getErrorMessage(error)}`,
129
- );
125
+ console.error(`FATAL: Error reading or parsing mcp-wordpress.config.json: ${getErrorMessage(error)}`);
130
126
  process.exit(1);
131
127
  }
132
128
  }
133
129
 
130
+ /**
131
+ * Check if we're in CI environment
132
+ */
133
+ private isCIEnvironment(): boolean {
134
+ return (
135
+ process.env.CI === "true" ||
136
+ process.env.NODE_ENV === "ci" ||
137
+ process.env.NODE_ENV === "test" ||
138
+ process.env.GITHUB_ACTIONS === "true" ||
139
+ process.env.TRAVIS === "true" ||
140
+ process.env.CIRCLECI === "true"
141
+ );
142
+ }
143
+
144
+ /**
145
+ * Create mock configuration for CI environments
146
+ */
147
+ private createMockConfiguration(): {
148
+ clients: Map<string, WordPressClient>;
149
+ configs: SiteConfig[];
150
+ } {
151
+ const mockConfig = {
152
+ WORDPRESS_SITE_URL: "https://demo.wordpress.com",
153
+ WORDPRESS_USERNAME: "ci-user",
154
+ WORDPRESS_APP_PASSWORD: "ci-mock-password",
155
+ WORDPRESS_AUTH_METHOD: "app-password" as const,
156
+ };
157
+
158
+ const clientConfig: WordPressClientConfig = {
159
+ baseUrl: mockConfig.WORDPRESS_SITE_URL,
160
+ auth: {
161
+ method: mockConfig.WORDPRESS_AUTH_METHOD,
162
+ username: mockConfig.WORDPRESS_USERNAME,
163
+ appPassword: mockConfig.WORDPRESS_APP_PASSWORD,
164
+ },
165
+ };
166
+
167
+ // Create mock client that won't actually connect to WordPress
168
+ const client = new MockWordPressClient(clientConfig);
169
+ const clients = new Map<string, WordPressClient>();
170
+ clients.set("default", client);
171
+
172
+ const siteConfig: SiteConfig = {
173
+ id: "default",
174
+ name: "Demo Site (CI Mode)",
175
+ config: mockConfig,
176
+ };
177
+
178
+ console.error("INFO: Using mock configuration for CI environment.");
179
+ return { clients, configs: [siteConfig] };
180
+ }
181
+
134
182
  /**
135
183
  * Load single-site configuration from environment variables
136
184
  */
@@ -139,66 +187,49 @@ export class ServerConfiguration {
139
187
  configs: SiteConfig[];
140
188
  } {
141
189
  try {
142
- // Debug output for DXT troubleshooting
143
- console.error("DEBUG: loadSingleSiteFromEnv called");
144
- console.error(`DEBUG: mcpConfig provided: ${mcpConfig ? "YES" : "NO"}`);
145
- console.error("DEBUG: Current environment variables:");
146
- console.error(
147
- ` WORDPRESS_SITE_URL: ${process.env.WORDPRESS_SITE_URL || "NOT SET"}`,
148
- );
149
- console.error(
150
- ` WORDPRESS_USERNAME: ${process.env.WORDPRESS_USERNAME || "NOT SET"}`,
151
- );
152
- console.error(
153
- ` WORDPRESS_APP_PASSWORD: ${process.env.WORDPRESS_APP_PASSWORD ? "SET" : "NOT SET"}`,
154
- );
155
- console.error(
156
- ` WORDPRESS_AUTH_METHOD: ${process.env.WORDPRESS_AUTH_METHOD || "NOT SET"}`,
157
- );
190
+ // Debug output for DXT troubleshooting (reduced in DXT mode)
191
+ const isDXTMode = process.env.NODE_ENV === "dxt";
192
+ if (!isDXTMode) {
193
+ console.error("DEBUG: loadSingleSiteFromEnv called");
194
+ console.error(`DEBUG: mcpConfig provided: ${mcpConfig ? "YES" : "NO"}`);
195
+ console.error("DEBUG: Current environment variables:");
196
+ console.error(` WORDPRESS_SITE_URL: ${process.env.WORDPRESS_SITE_URL || "NOT SET"}`);
197
+ console.error(` WORDPRESS_USERNAME: ${process.env.WORDPRESS_USERNAME || "NOT SET"}`);
198
+ console.error(` WORDPRESS_APP_PASSWORD: ${process.env.WORDPRESS_APP_PASSWORD ? "SET" : "NOT SET"}`);
199
+ console.error(` WORDPRESS_AUTH_METHOD: ${process.env.WORDPRESS_AUTH_METHOD || "NOT SET"}`);
200
+ }
201
+
202
+ // Check if we're in CI environment and credentials are missing
203
+ if (this.isCIEnvironment() && !process.env.WORDPRESS_SITE_URL) {
204
+ return this.createMockConfiguration();
205
+ }
158
206
 
159
207
  // Validate MCP config if provided
160
- const validatedMcpConfig = mcpConfig
161
- ? ConfigurationValidator.validateMcpConfig(mcpConfig)
162
- : undefined;
208
+ const validatedMcpConfig = mcpConfig ? ConfigurationValidator.validateMcpConfig(mcpConfig) : undefined;
163
209
 
164
210
  // Prepare environment configuration for validation
165
211
  const envConfig = {
166
- WORDPRESS_SITE_URL:
167
- validatedMcpConfig?.wordpressSiteUrl ||
168
- process.env.WORDPRESS_SITE_URL,
169
- WORDPRESS_USERNAME:
170
- validatedMcpConfig?.wordpressUsername ||
171
- process.env.WORDPRESS_USERNAME,
172
- WORDPRESS_APP_PASSWORD:
173
- validatedMcpConfig?.wordpressAppPassword ||
174
- process.env.WORDPRESS_APP_PASSWORD,
212
+ WORDPRESS_SITE_URL: validatedMcpConfig?.wordpressSiteUrl || process.env.WORDPRESS_SITE_URL,
213
+ WORDPRESS_USERNAME: validatedMcpConfig?.wordpressUsername || process.env.WORDPRESS_USERNAME,
214
+ WORDPRESS_APP_PASSWORD: validatedMcpConfig?.wordpressAppPassword || process.env.WORDPRESS_APP_PASSWORD,
175
215
  WORDPRESS_AUTH_METHOD:
176
- validatedMcpConfig?.wordpressAuthMethod ||
177
- process.env.WORDPRESS_AUTH_METHOD ||
178
- "app-password",
216
+ validatedMcpConfig?.wordpressAuthMethod || process.env.WORDPRESS_AUTH_METHOD || "app-password",
179
217
  NODE_ENV: process.env.NODE_ENV,
180
218
  DEBUG: process.env.DEBUG,
181
219
  DISABLE_CACHE: process.env.DISABLE_CACHE,
182
220
  LOG_LEVEL: process.env.LOG_LEVEL,
183
221
  };
184
222
 
185
- console.error("DEBUG: Final envConfig for validation:");
186
- console.error(
187
- ` WORDPRESS_SITE_URL: ${envConfig.WORDPRESS_SITE_URL || "NOT SET"}`,
188
- );
189
- console.error(
190
- ` WORDPRESS_USERNAME: ${envConfig.WORDPRESS_USERNAME || "NOT SET"}`,
191
- );
192
- console.error(
193
- ` WORDPRESS_APP_PASSWORD: ${envConfig.WORDPRESS_APP_PASSWORD ? "SET" : "NOT SET"}`,
194
- );
195
- console.error(
196
- ` WORDPRESS_AUTH_METHOD: ${envConfig.WORDPRESS_AUTH_METHOD || "NOT SET"}`,
197
- );
223
+ if (!isDXTMode) {
224
+ console.error("DEBUG: Final envConfig for validation:");
225
+ console.error(` WORDPRESS_SITE_URL: ${envConfig.WORDPRESS_SITE_URL || "NOT SET"}`);
226
+ console.error(` WORDPRESS_USERNAME: ${envConfig.WORDPRESS_USERNAME || "NOT SET"}`);
227
+ console.error(` WORDPRESS_APP_PASSWORD: ${envConfig.WORDPRESS_APP_PASSWORD ? "SET" : "NOT SET"}`);
228
+ console.error(` WORDPRESS_AUTH_METHOD: ${envConfig.WORDPRESS_AUTH_METHOD || "NOT SET"}`);
229
+ }
198
230
 
199
231
  // Validate environment configuration using Zod schema
200
- const validatedConfig =
201
- ConfigurationValidator.validateEnvironmentConfig(envConfig);
232
+ const validatedConfig = ConfigurationValidator.validateEnvironmentConfig(envConfig);
202
233
 
203
234
  const clientConfig: WordPressClientConfig = {
204
235
  baseUrl: validatedConfig.WORDPRESS_SITE_URL,
@@ -228,19 +259,15 @@ export class ServerConfiguration {
228
259
  },
229
260
  };
230
261
 
231
- console.error(
232
- "INFO: Initialized client for default site in single-site mode.",
233
- );
262
+ if (!isDXTMode) {
263
+ console.error("INFO: Initialized client for default site in single-site mode.");
264
+ }
234
265
 
235
266
  return { clients, configs: [siteConfig] };
236
267
  } catch (error) {
237
- console.error(
238
- "ERROR: Configuration validation failed for single-site mode.",
239
- );
268
+ console.error("ERROR: Configuration validation failed for single-site mode.");
240
269
  console.error(`Details: ${getErrorMessage(error)}`);
241
- console.error(
242
- "Please check your environment variables or MCP configuration.",
243
- );
270
+ console.error("Please check your environment variables or MCP configuration.");
244
271
  return { clients: new Map(), configs: [] };
245
272
  }
246
273
  }