@automattic/mcp-wordpress-remote 0.2.18 → 0.2.19

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/dist/proxy.js CHANGED
@@ -36036,7 +36036,7 @@ async function selectCallbackPort(serverUrl, specifiedPort, _unused) {
36036
36036
  }
36037
36037
 
36038
36038
  // src/lib/config.ts
36039
- var MCP_WORDPRESS_REMOTE_VERSION = "0.2.18";
36039
+ var MCP_WORDPRESS_REMOTE_VERSION = "0.2.19";
36040
36040
  var CONFIG = {
36041
36041
  // API Configuration
36042
36042
  WP_API_URL: process.env.WP_API_URL || "https://example.com",
@@ -36086,8 +36086,57 @@ var CONFIG = {
36086
36086
  CUSTOM_HEADERS: process.env.CUSTOM_HEADERS || "",
36087
36087
  // JSON string or comma-separated header:value pairs
36088
36088
  // Environment
36089
- NODE_ENV: process.env.NODE_ENV || "development"
36089
+ NODE_ENV: process.env.NODE_ENV || "development",
36090
+ // Proxy Configuration
36091
+ USE_SYSTEM_PROXY: process.env.USE_SYSTEM_PROXY === "true"
36092
+ // Enable system proxy detection (PAC files, env vars)
36090
36093
  };
36094
+ var getConfig = () => ({
36095
+ /** WordPress site API endpoint */
36096
+ wpApiUrl: CONFIG.WP_API_URL,
36097
+ /** Whether OAuth authentication is enabled */
36098
+ oauthEnabled: CONFIG.OAUTH_ENABLED,
36099
+ /** Port for OAuth callback server (undefined for auto-detection on self-hosted sites) */
36100
+ oauthCallbackPort: CONFIG.OAUTH_CALLBACK_PORT,
36101
+ /** Hostname for OAuth callback */
36102
+ oauthHost: CONFIG.OAUTH_HOST,
36103
+ /** WordPress OAuth client ID */
36104
+ wpOAuthClientId: CONFIG.WP_OAUTH_CLIENT_ID,
36105
+ /** OAuth flow type (authorization_code recommended, implicit for legacy) */
36106
+ oauthFlowType: CONFIG.OAUTH_FLOW_TYPE,
36107
+ /** Whether to use PKCE (required for OAuth 2.1) */
36108
+ oauthUsePKCE: CONFIG.OAUTH_USE_PKCE,
36109
+ /** Whether to support dynamic client registration */
36110
+ oauthDynamicRegistration: CONFIG.OAUTH_DYNAMIC_REGISTRATION,
36111
+ /** Whether to use resource indicators (RFC 8707) */
36112
+ oauthResourceIndicator: CONFIG.OAUTH_RESOURCE_INDICATOR,
36113
+ /** Custom OAuth scopes (comma-separated) */
36114
+ oauthScopes: CONFIG.OAUTH_SCOPES,
36115
+ /** OAuth operation timeout in milliseconds */
36116
+ oauthTimeout: CONFIG.OAUTH_TIMEOUT,
36117
+ /** Lock operation timeout in milliseconds */
36118
+ lockTimeout: CONFIG.LOCK_TIMEOUT,
36119
+ /** Configuration directory path */
36120
+ configDir: CONFIG.WP_MCP_CONFIG_DIR,
36121
+ /** Log file path (null if not set) */
36122
+ logFile: CONFIG.LOG_FILE,
36123
+ /** WordPress API username (legacy) */
36124
+ wpApiUsername: CONFIG.WP_API_USERNAME,
36125
+ /** WordPress API password (legacy) */
36126
+ wpApiPassword: CONFIG.WP_API_PASSWORD,
36127
+ /** JWT token for authentication */
36128
+ jwtToken: CONFIG.JWT_TOKEN,
36129
+ /** WooCommerce customer key */
36130
+ wooCustomerKey: CONFIG.WOO_CUSTOMER_KEY,
36131
+ /** WooCommerce customer secret */
36132
+ wooCustomerSecret: CONFIG.WOO_CUSTOMER_SECRET,
36133
+ /** Custom headers for API requests */
36134
+ customHeaders: CONFIG.CUSTOM_HEADERS,
36135
+ /** Current environment */
36136
+ nodeEnv: CONFIG.NODE_ENV,
36137
+ /** Whether to use system proxy (PAC files on macOS, env vars on all platforms) */
36138
+ useSystemProxy: CONFIG.USE_SYSTEM_PROXY
36139
+ });
36091
36140
  function parseOAuthScopes(envScopes, defaultScopes) {
36092
36141
  if (!envScopes || envScopes.trim() === "") {
36093
36142
  return defaultScopes;
@@ -36250,6 +36299,165 @@ function validateNodeVersion(requiredVersion = 18) {
36250
36299
  }
36251
36300
  }
36252
36301
 
36302
+ // src/lib/proxy-utils.ts
36303
+ import { execSync } from "child_process";
36304
+ import { SocksProxyAgent } from "socks-proxy-agent";
36305
+ import { HttpsProxyAgent } from "https-proxy-agent";
36306
+ var proxyConfig = { type: "none" };
36307
+ var initializationPromise = null;
36308
+ function detectMacOsPac() {
36309
+ if (process.platform !== "darwin") return null;
36310
+ try {
36311
+ const output = execSync("scutil --proxy", { encoding: "utf-8", timeout: 3e3 });
36312
+ const pacEnabled = output.match(/ProxyAutoConfigEnable\s*:\s*(\d)/)?.[1] === "1";
36313
+ const pacUrl = output.match(/ProxyAutoConfigURLString\s*:\s*(\S+)/)?.[1];
36314
+ if (pacEnabled && pacUrl) {
36315
+ return pacUrl;
36316
+ }
36317
+ } catch {
36318
+ }
36319
+ return null;
36320
+ }
36321
+ function isSocksProxy(url) {
36322
+ return url.toLowerCase().startsWith("socks");
36323
+ }
36324
+ function sanitizeProxyUrl(url) {
36325
+ try {
36326
+ const parsed = new URL(url);
36327
+ if (parsed.password) parsed.password = "***";
36328
+ return parsed.toString();
36329
+ } catch {
36330
+ return url.replace(/\/\/[^:]+:[^@]+@/, "//***:***@");
36331
+ }
36332
+ }
36333
+ function shouldBypassProxy(targetUrl) {
36334
+ const noProxy = process.env.NO_PROXY || process.env.no_proxy;
36335
+ if (!noProxy) return false;
36336
+ let hostname2;
36337
+ try {
36338
+ hostname2 = new URL(targetUrl).hostname.toLowerCase();
36339
+ } catch {
36340
+ return false;
36341
+ }
36342
+ const rules = noProxy.split(",").map((r2) => r2.trim().toLowerCase()).filter((r2) => r2.length > 0);
36343
+ for (const rule of rules) {
36344
+ if (rule === "*") return true;
36345
+ if (hostname2 === rule) return true;
36346
+ if (rule.startsWith(".") && hostname2.endsWith(rule) || !rule.startsWith(".") && hostname2.endsWith(`.${rule}`)) {
36347
+ return true;
36348
+ }
36349
+ }
36350
+ return false;
36351
+ }
36352
+ function detectEnvProxy() {
36353
+ const socksProxy = process.env.SOCKS_PROXY || process.env.socks_proxy;
36354
+ if (socksProxy) {
36355
+ return { url: socksProxy, type: "socks" };
36356
+ }
36357
+ const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
36358
+ if (httpsProxy) {
36359
+ return { url: httpsProxy, type: isSocksProxy(httpsProxy) ? "socks" : "http" };
36360
+ }
36361
+ const allProxy = process.env.ALL_PROXY || process.env.all_proxy;
36362
+ if (allProxy) {
36363
+ return { url: allProxy, type: isSocksProxy(allProxy) ? "socks" : "http" };
36364
+ }
36365
+ const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
36366
+ if (httpProxy) {
36367
+ return { url: httpProxy, type: isSocksProxy(httpProxy) ? "socks" : "http" };
36368
+ }
36369
+ return null;
36370
+ }
36371
+ async function initializeProxy() {
36372
+ if (initializationPromise) {
36373
+ return initializationPromise;
36374
+ }
36375
+ initializationPromise = doInitializeProxy().catch((error) => {
36376
+ initializationPromise = null;
36377
+ throw error;
36378
+ });
36379
+ return initializationPromise;
36380
+ }
36381
+ async function doInitializeProxy() {
36382
+ const pacUrl = detectMacOsPac();
36383
+ if (pacUrl) {
36384
+ try {
36385
+ const response = await fetch(pacUrl);
36386
+ const pacScript = await response.text();
36387
+ const { getQuickJS } = await import("@tootallnate/quickjs-emscripten");
36388
+ const { createPacResolver } = await import("pac-resolver");
36389
+ const qjs = await getQuickJS();
36390
+ const resolver = createPacResolver(qjs, pacScript);
36391
+ proxyConfig = {
36392
+ type: "pac",
36393
+ pacResolver: resolver
36394
+ };
36395
+ logger.info(`PAC proxy initialized from ${sanitizeProxyUrl(pacUrl)}`, "PROXY");
36396
+ return;
36397
+ } catch (error) {
36398
+ logger.error(`Failed to initialize PAC proxy: ${error}`, "PROXY");
36399
+ }
36400
+ }
36401
+ const envProxy = detectEnvProxy();
36402
+ if (envProxy) {
36403
+ proxyConfig = { type: "env", envProxy };
36404
+ logger.info(`Proxy configured from environment: ${sanitizeProxyUrl(envProxy.url)}`, "PROXY");
36405
+ return;
36406
+ }
36407
+ logger.debug("No proxy configured", "PROXY");
36408
+ proxyConfig = { type: "none" };
36409
+ }
36410
+ async function getAgentForUrl(url) {
36411
+ if (proxyConfig.type === "none") {
36412
+ return void 0;
36413
+ }
36414
+ if (shouldBypassProxy(url)) {
36415
+ logger.debug(`Bypassing proxy for ${url} (matches NO_PROXY)`, "PROXY");
36416
+ return void 0;
36417
+ }
36418
+ if (proxyConfig.type === "pac" && proxyConfig.pacResolver) {
36419
+ try {
36420
+ const result = await proxyConfig.pacResolver(url);
36421
+ const directives = result.split(";");
36422
+ for (const rawDirective of directives) {
36423
+ const directive = rawDirective.trim();
36424
+ if (!directive) continue;
36425
+ if (directive.toUpperCase() === "DIRECT") {
36426
+ logger.debug(`PAC returned DIRECT for ${url}`, "PROXY");
36427
+ return void 0;
36428
+ }
36429
+ const socksMatch = directive.match(/SOCKS5?\s+(\S+):(\d+)/i);
36430
+ if (socksMatch) {
36431
+ const proxyUrl = `socks5://${socksMatch[1]}:${socksMatch[2]}`;
36432
+ logger.debug(`PAC returned SOCKS proxy for ${url}: ${sanitizeProxyUrl(proxyUrl)}`, "PROXY");
36433
+ return new SocksProxyAgent(proxyUrl);
36434
+ }
36435
+ const proxyMatch = directive.match(/PROXY\s+(\S+):(\d+)/i);
36436
+ if (proxyMatch) {
36437
+ const proxyUrl = `http://${proxyMatch[1]}:${proxyMatch[2]}`;
36438
+ logger.debug(`PAC returned HTTP proxy for ${url}: ${sanitizeProxyUrl(proxyUrl)}`, "PROXY");
36439
+ return new HttpsProxyAgent(proxyUrl);
36440
+ }
36441
+ }
36442
+ logger.debug(`PAC returned no usable proxy for ${url}: ${result}`, "PROXY");
36443
+ } catch (error) {
36444
+ logger.warn(`PAC evaluation failed for ${url}: ${error}`, "PROXY");
36445
+ }
36446
+ return void 0;
36447
+ }
36448
+ if (proxyConfig.type === "env" && proxyConfig.envProxy) {
36449
+ const { url: proxyUrl, type } = proxyConfig.envProxy;
36450
+ try {
36451
+ logger.debug(`Using env proxy ${sanitizeProxyUrl(proxyUrl)} for ${url}`, "PROXY");
36452
+ return type === "socks" ? new SocksProxyAgent(proxyUrl) : new HttpsProxyAgent(proxyUrl);
36453
+ } catch (error) {
36454
+ logger.error(`Invalid proxy URL "${proxyUrl}": ${error}`, "PROXY");
36455
+ return void 0;
36456
+ }
36457
+ }
36458
+ return void 0;
36459
+ }
36460
+
36253
36461
  // src/lib/fetch-utils.ts
36254
36462
  async function setupFetchPolyfill() {
36255
36463
  if (typeof globalThis.fetch !== "function") {
@@ -36269,6 +36477,22 @@ async function setupFetchPolyfill() {
36269
36477
  } else {
36270
36478
  logger.info("Using native fetch API", "SYSTEM");
36271
36479
  }
36480
+ if (getConfig().useSystemProxy) {
36481
+ await initializeProxy();
36482
+ } else {
36483
+ logger.debug("System proxy support disabled (USE_SYSTEM_PROXY=false)", "PROXY");
36484
+ }
36485
+ }
36486
+ async function proxyFetch(url, init) {
36487
+ if (!getConfig().useSystemProxy) {
36488
+ return fetch(url, init);
36489
+ }
36490
+ const agent = await getAgentForUrl(url);
36491
+ if (agent) {
36492
+ const nodeFetch = (await Promise.resolve().then(() => (init_src(), src_exports))).default;
36493
+ return nodeFetch(url, { ...init, agent });
36494
+ }
36495
+ return fetch(url, init);
36272
36496
  }
36273
36497
 
36274
36498
  // src/lib/wordpress-api.ts
@@ -36783,7 +37007,7 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl) {
36783
37007
  const metadataUrl = new URL("/.well-known/oauth-authorization-server", authorizationServerUrl);
36784
37008
  logger.oauth(`Discovering authorization server metadata: ${metadataUrl}`);
36785
37009
  const customHeaders = getCustomHeaders();
36786
- const response = await fetch(metadataUrl.toString(), {
37010
+ const response = await proxyFetch(metadataUrl.toString(), {
36787
37011
  headers: {
36788
37012
  "Accept": "application/json",
36789
37013
  ...customHeaders
@@ -36820,7 +37044,7 @@ async function discoverProtectedResourceMetadata(resourceUrl) {
36820
37044
  const metadataUrl = new URL("/.well-known/oauth-protected-resource", url.origin);
36821
37045
  logger.oauth(`Discovering protected resource metadata: ${metadataUrl}`);
36822
37046
  const customHeaders = getCustomHeaders();
36823
- const response = await fetch(metadataUrl.toString(), {
37047
+ const response = await proxyFetch(metadataUrl.toString(), {
36824
37048
  headers: {
36825
37049
  "Accept": "application/json",
36826
37050
  ...customHeaders
@@ -36886,7 +37110,7 @@ async function registerDynamicClient(registrationEndpoint, registrationRequest)
36886
37110
  try {
36887
37111
  logger.oauth(`Attempting dynamic client registration: ${registrationEndpoint}`);
36888
37112
  const customHeaders = getCustomHeaders();
36889
- const response = await fetch(registrationEndpoint, {
37113
+ const response = await proxyFetch(registrationEndpoint, {
36890
37114
  method: "POST",
36891
37115
  headers: {
36892
37116
  "Content-Type": "application/json",
@@ -36938,7 +37162,7 @@ async function exchangeAuthorizationCode(tokenEndpoint, code, redirectUri, clien
36938
37162
  params.set("resource", resource);
36939
37163
  }
36940
37164
  const customHeaders = getCustomHeaders();
36941
- const response = await fetch(tokenEndpoint, {
37165
+ const response = await proxyFetch(tokenEndpoint, {
36942
37166
  method: "POST",
36943
37167
  headers: {
36944
37168
  "Content-Type": "application/x-www-form-urlencoded",
@@ -37406,7 +37630,7 @@ var MCPOAuthProvider = class {
37406
37630
  try {
37407
37631
  logger.oauth("Attempting discovery via 401 response method");
37408
37632
  const customHeaders = getCustomHeaders();
37409
- const response = await fetch(this.config.serverUrl, {
37633
+ const response = await proxyFetch(this.config.serverUrl, {
37410
37634
  headers: {
37411
37635
  Accept: "application/json",
37412
37636
  ...customHeaders
@@ -37418,7 +37642,7 @@ var MCPOAuthProvider = class {
37418
37642
  const authInfo = parseWWWAuthenticateHeader(wwwAuthHeader);
37419
37643
  logger.oauth("WWW-Authenticate header parsed successfully");
37420
37644
  if (authInfo.resource_metadata_url) {
37421
- const metadataResponse = await fetch(authInfo.resource_metadata_url, {
37645
+ const metadataResponse = await proxyFetch(authInfo.resource_metadata_url, {
37422
37646
  headers: {
37423
37647
  "Accept": "application/json",
37424
37648
  ...customHeaders
@@ -38493,7 +38717,7 @@ async function wpRequest(requestData, useJsonRpc = true) {
38493
38717
  logger.api("Sending request to WordPress API...");
38494
38718
  logger.debug(`Request URL: ${url}`, "API");
38495
38719
  logger.debug(`Request method: ${method}`, "API");
38496
- const response = await fetch(url, fetchOptions);
38720
+ const response = await proxyFetch(url, fetchOptions);
38497
38721
  logger.debug(`Response status: ${response.status}`, "API");
38498
38722
  if (!response.ok) {
38499
38723
  const errorText = await response.text();
@@ -38914,7 +39138,7 @@ async function WordPressProxy() {
38914
39138
  const server = new Server(
38915
39139
  {
38916
39140
  name: "WordPress MCP Remote Proxy",
38917
- version: "0.2.17"
39141
+ version: MCP_WORDPRESS_REMOTE_VERSION
38918
39142
  },
38919
39143
  {
38920
39144
  capabilities: {
@@ -38947,7 +39171,7 @@ async function WordPressProxy() {
38947
39171
  protocolVersion: "2025-06-18",
38948
39172
  serverInfo: {
38949
39173
  name: "WordPress MCP Remote Proxy",
38950
- version: "0.2.17"
39174
+ version: MCP_WORDPRESS_REMOTE_VERSION
38951
39175
  },
38952
39176
  capabilities: {
38953
39177
  tools: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/mcp-wordpress-remote",
3
- "version": "0.2.18",
3
+ "version": "0.2.19",
4
4
  "description": "MCP WordPress Remote proxy server",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -59,9 +59,13 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "@modelcontextprotocol/sdk": "^1.8.0",
62
+ "@tootallnate/quickjs-emscripten": "^0.23.0",
62
63
  "express": "^4.18.2",
64
+ "https-proxy-agent": "^7.0.6",
63
65
  "node-fetch": "^3.3.2",
64
- "open": "^10.0.0"
66
+ "open": "^10.0.0",
67
+ "pac-resolver": "^7.0.1",
68
+ "socks-proxy-agent": "^8.0.5"
65
69
  },
66
70
  "devDependencies": {
67
71
  "@playwright/test": "^1.54.2",
@@ -101,7 +105,11 @@
101
105
  "open"
102
106
  ],
103
107
  "external": [
104
- "node:*"
108
+ "node:*",
109
+ "@tootallnate/quickjs-emscripten",
110
+ "pac-resolver",
111
+ "socks-proxy-agent",
112
+ "https-proxy-agent"
105
113
  ],
106
114
  "minify": false,
107
115
  "sourcemap": false,