@automattic/mcp-wordpress-remote 0.3.4 → 0.4.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/LICENSE +1 -1
- package/dist/lib.d.ts +45 -2
- package/dist/lib.js +60 -20
- package/dist/proxy.js +128 -43
- package/package.json +3 -2
package/LICENSE
CHANGED
package/dist/lib.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ interface WordPressResponse {
|
|
|
15
15
|
[key: string]: any;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
declare const MCP_WORDPRESS_REMOTE_VERSION = "0.
|
|
18
|
+
declare const MCP_WORDPRESS_REMOTE_VERSION = "0.4.0";
|
|
19
19
|
/**
|
|
20
20
|
* Centralized configuration for MCP WordPress Remote
|
|
21
21
|
* All default values are defined here and can be overridden via environment variables
|
|
@@ -327,4 +327,47 @@ declare function isProxyConfigured(): boolean;
|
|
|
327
327
|
*/
|
|
328
328
|
declare function getProxyType(): 'pac' | 'env' | 'none';
|
|
329
329
|
|
|
330
|
-
|
|
330
|
+
/**
|
|
331
|
+
* MCP Request Types for WordPress Remote Proxy
|
|
332
|
+
*
|
|
333
|
+
* Type definitions for all MCP JSON-RPC request schemas
|
|
334
|
+
*/
|
|
335
|
+
|
|
336
|
+
interface WPRequestParams {
|
|
337
|
+
method: string;
|
|
338
|
+
[key: string]: unknown;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Tool-call hooks for MCP WordPress Remote.
|
|
343
|
+
*
|
|
344
|
+
* Lets an embedding package observe completed `tools/call` requests and
|
|
345
|
+
* piggyback on the proxy's live, authenticated session — for example to send
|
|
346
|
+
* usage telemetry — without forking the proxy.
|
|
347
|
+
*
|
|
348
|
+
* The registry lives on a global symbol so it is a single instance even when a
|
|
349
|
+
* consumer registers through the `/lib` bundle while the handlers run in the
|
|
350
|
+
* separate `proxy` bundle.
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
/** Context passed to each hook after a tool call completes. */
|
|
354
|
+
interface ToolCallContext {
|
|
355
|
+
/** Name of the tool the client just called. */
|
|
356
|
+
name: string;
|
|
357
|
+
/**
|
|
358
|
+
* Dispatch an additional request over the proxy's live, authenticated
|
|
359
|
+
* session. The request is prepared for the session's detected transport
|
|
360
|
+
* (JSON-RPC envelope or simple format) before it is sent, e.g.
|
|
361
|
+
* `wpRequest({ method: 'tools/call', name, arguments })`.
|
|
362
|
+
*/
|
|
363
|
+
wpRequest: (params: WPRequestParams) => Promise<WordPressResponse>;
|
|
364
|
+
}
|
|
365
|
+
/** A hook fired after each completed `tools/call`. May be async. */
|
|
366
|
+
type ToolCallHook = (context: ToolCallContext) => void | Promise<void>;
|
|
367
|
+
/**
|
|
368
|
+
* Register a hook fired after each completed `tools/call`. Returns a function
|
|
369
|
+
* that unregisters it.
|
|
370
|
+
*/
|
|
371
|
+
declare function registerToolCallHook(hook: ToolCallHook): () => void;
|
|
372
|
+
|
|
373
|
+
export { APIError, AuthError, CONFIG, ConfigError, LogLevel, MCP_WORDPRESS_REMOTE_VERSION, OAuthError, type TokenValidationResult, type ToolCallContext, type ToolCallHook, type WPClientInfo, type WPTokens, type WordPressRequestParams, type WordPressResponse, getAgentForUrl, getConfig, getCustomHeaders, getDefaultOAuthScopes, getFetchInfo, getProxyInfo, getProxyType, initializeProxy, isAPIError, isAuthError, isConfigError, isFetchAvailable, isOAuthError, isProxyConfigured, log, logger, parseCustomHeaders, proxyFetch, registerToolCallHook, setupFetchPolyfill, validateConfig, wpRequest };
|
package/dist/lib.js
CHANGED
|
@@ -20760,12 +20760,15 @@ var require_json = __commonJS({
|
|
|
20760
20760
|
var JSON_SYNTAX_REGEXP = /#+/g;
|
|
20761
20761
|
function json2(options) {
|
|
20762
20762
|
var opts = options || {};
|
|
20763
|
-
var limit = typeof opts.limit
|
|
20763
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
20764
20764
|
var inflate = opts.inflate !== false;
|
|
20765
20765
|
var reviver = opts.reviver;
|
|
20766
20766
|
var strict = opts.strict !== false;
|
|
20767
20767
|
var type = opts.type || "application/json";
|
|
20768
20768
|
var verify = opts.verify || false;
|
|
20769
|
+
if (limit === null) {
|
|
20770
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
20771
|
+
}
|
|
20769
20772
|
if (verify !== false && typeof verify !== "function") {
|
|
20770
20773
|
throw new TypeError("option verify must be function");
|
|
20771
20774
|
}
|
|
@@ -20887,9 +20890,12 @@ var require_raw = __commonJS({
|
|
|
20887
20890
|
function raw(options) {
|
|
20888
20891
|
var opts = options || {};
|
|
20889
20892
|
var inflate = opts.inflate !== false;
|
|
20890
|
-
var limit = typeof opts.limit
|
|
20893
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
20891
20894
|
var type = opts.type || "application/octet-stream";
|
|
20892
20895
|
var verify = opts.verify || false;
|
|
20896
|
+
if (limit === null) {
|
|
20897
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
20898
|
+
}
|
|
20893
20899
|
if (verify !== false && typeof verify !== "function") {
|
|
20894
20900
|
throw new TypeError("option verify must be function");
|
|
20895
20901
|
}
|
|
@@ -20945,9 +20951,12 @@ var require_text = __commonJS({
|
|
|
20945
20951
|
var opts = options || {};
|
|
20946
20952
|
var defaultCharset = opts.defaultCharset || "utf-8";
|
|
20947
20953
|
var inflate = opts.inflate !== false;
|
|
20948
|
-
var limit = typeof opts.limit
|
|
20954
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
20949
20955
|
var type = opts.type || "text/plain";
|
|
20950
20956
|
var verify = opts.verify || false;
|
|
20957
|
+
if (limit === null) {
|
|
20958
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
20959
|
+
}
|
|
20951
20960
|
if (verify !== false && typeof verify !== "function") {
|
|
20952
20961
|
throw new TypeError("option verify must be function");
|
|
20953
20962
|
}
|
|
@@ -23556,9 +23565,12 @@ var require_urlencoded = __commonJS({
|
|
|
23556
23565
|
}
|
|
23557
23566
|
var extended = opts.extended !== false;
|
|
23558
23567
|
var inflate = opts.inflate !== false;
|
|
23559
|
-
var limit = typeof opts.limit
|
|
23568
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
23560
23569
|
var type = opts.type || "application/x-www-form-urlencoded";
|
|
23561
23570
|
var verify = opts.verify || false;
|
|
23571
|
+
if (limit === null) {
|
|
23572
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
23573
|
+
}
|
|
23562
23574
|
if (verify !== false && typeof verify !== "function") {
|
|
23563
23575
|
throw new TypeError("option verify must be function");
|
|
23564
23576
|
}
|
|
@@ -47325,7 +47337,7 @@ async function selectCallbackPort(serverUrl, specifiedPort, _unused) {
|
|
|
47325
47337
|
}
|
|
47326
47338
|
|
|
47327
47339
|
// src/lib/config.ts
|
|
47328
|
-
var MCP_WORDPRESS_REMOTE_VERSION = "0.
|
|
47340
|
+
var MCP_WORDPRESS_REMOTE_VERSION = "0.4.0";
|
|
47329
47341
|
function parsePositiveIntEnv(value, defaultValue) {
|
|
47330
47342
|
if (!value) {
|
|
47331
47343
|
return defaultValue;
|
|
@@ -47760,13 +47772,19 @@ async function getAgentForUrl(url2) {
|
|
|
47760
47772
|
const socksMatch = directive.match(/SOCKS5?\s+(\S+):(\d+)/i);
|
|
47761
47773
|
if (socksMatch) {
|
|
47762
47774
|
const proxyUrl = `socks5h://${socksMatch[1]}:${socksMatch[2]}`;
|
|
47763
|
-
logger.debug(
|
|
47775
|
+
logger.debug(
|
|
47776
|
+
`PAC returned SOCKS proxy for ${url2}: ${sanitizeProxyUrl(proxyUrl)}`,
|
|
47777
|
+
"PROXY"
|
|
47778
|
+
);
|
|
47764
47779
|
return new SocksProxyAgent(proxyUrl);
|
|
47765
47780
|
}
|
|
47766
47781
|
const proxyMatch = directive.match(/PROXY\s+(\S+):(\d+)/i);
|
|
47767
47782
|
if (proxyMatch) {
|
|
47768
47783
|
const proxyUrl = `http://${proxyMatch[1]}:${proxyMatch[2]}`;
|
|
47769
|
-
logger.debug(
|
|
47784
|
+
logger.debug(
|
|
47785
|
+
`PAC returned HTTP proxy for ${url2}: ${sanitizeProxyUrl(proxyUrl)}`,
|
|
47786
|
+
"PROXY"
|
|
47787
|
+
);
|
|
47770
47788
|
return new HttpsProxyAgent(proxyUrl);
|
|
47771
47789
|
}
|
|
47772
47790
|
}
|
|
@@ -48443,7 +48461,7 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl) {
|
|
|
48443
48461
|
const customHeaders = getCustomHeaders();
|
|
48444
48462
|
const response = await proxyFetch(metadataUrl.toString(), {
|
|
48445
48463
|
headers: {
|
|
48446
|
-
|
|
48464
|
+
Accept: "application/json",
|
|
48447
48465
|
...customHeaders
|
|
48448
48466
|
}
|
|
48449
48467
|
});
|
|
@@ -48480,7 +48498,7 @@ async function discoverProtectedResourceMetadata(resourceUrl) {
|
|
|
48480
48498
|
const customHeaders = getCustomHeaders();
|
|
48481
48499
|
const response = await proxyFetch(metadataUrl.toString(), {
|
|
48482
48500
|
headers: {
|
|
48483
|
-
|
|
48501
|
+
Accept: "application/json",
|
|
48484
48502
|
...customHeaders
|
|
48485
48503
|
}
|
|
48486
48504
|
});
|
|
@@ -49075,7 +49093,7 @@ var MCPOAuthProvider = class {
|
|
|
49075
49093
|
if (authInfo.resource_metadata_url) {
|
|
49076
49094
|
const metadataResponse = await proxyFetch(authInfo.resource_metadata_url, {
|
|
49077
49095
|
headers: {
|
|
49078
|
-
|
|
49096
|
+
Accept: "application/json",
|
|
49079
49097
|
...customHeaders
|
|
49080
49098
|
}
|
|
49081
49099
|
});
|
|
@@ -49112,6 +49130,12 @@ var MCPOAuthProvider = class {
|
|
|
49112
49130
|
logger.oauth("Using provided client ID, skipping dynamic registration");
|
|
49113
49131
|
return;
|
|
49114
49132
|
}
|
|
49133
|
+
const storedClientInfo = await readClientInfo(this.serverUrlHash);
|
|
49134
|
+
if (typeof storedClientInfo?.client_id === "string" && storedClientInfo.client_id.length > 0) {
|
|
49135
|
+
this.config.clientId = storedClientInfo.client_id;
|
|
49136
|
+
logger.oauth("Reusing persisted client registration, skipping dynamic registration");
|
|
49137
|
+
return;
|
|
49138
|
+
}
|
|
49115
49139
|
if (!CONFIG.OAUTH_DYNAMIC_REGISTRATION) {
|
|
49116
49140
|
throw new OAuthError2(
|
|
49117
49141
|
"No client ID provided and dynamic registration is disabled",
|
|
@@ -50035,10 +50059,7 @@ async function getOAuthTokens() {
|
|
|
50035
50059
|
return null;
|
|
50036
50060
|
}
|
|
50037
50061
|
} else {
|
|
50038
|
-
logger.warn(
|
|
50039
|
-
"Using legacy OAuth provider. Consider enabling PKCE for MCP compliance",
|
|
50040
|
-
"AUTH"
|
|
50041
|
-
);
|
|
50062
|
+
logger.warn("Using legacy OAuth provider. Consider enabling PKCE for MCP compliance", "AUTH");
|
|
50042
50063
|
if (!authCoordinator) {
|
|
50043
50064
|
if (!globalEvents) {
|
|
50044
50065
|
globalEvents = new EventEmitter3();
|
|
@@ -50281,7 +50302,10 @@ async function executeWordPressRequest(requestData, useJsonRpc, sessionIdUsed) {
|
|
|
50281
50302
|
}
|
|
50282
50303
|
async function refreshSession(failedSessionId) {
|
|
50283
50304
|
if (failedSessionId && globalSessionId && globalSessionId !== failedSessionId) {
|
|
50284
|
-
logger.info(
|
|
50305
|
+
logger.info(
|
|
50306
|
+
"Detected newer session while handling invalid-session error; skipping refresh",
|
|
50307
|
+
"SESSION"
|
|
50308
|
+
);
|
|
50285
50309
|
return;
|
|
50286
50310
|
}
|
|
50287
50311
|
if (sessionRefreshPromise) {
|
|
@@ -50335,11 +50359,7 @@ async function wpRequest(requestData, useJsonRpc = true, options = {}) {
|
|
|
50335
50359
|
sessionIdUsed: sessionIdUsed || "none"
|
|
50336
50360
|
});
|
|
50337
50361
|
await refreshSession(sessionIdUsed);
|
|
50338
|
-
const retriedResult = await executeWordPressRequest(
|
|
50339
|
-
requestData,
|
|
50340
|
-
useJsonRpc,
|
|
50341
|
-
globalSessionId
|
|
50342
|
-
);
|
|
50362
|
+
const retriedResult = await executeWordPressRequest(requestData, useJsonRpc, globalSessionId);
|
|
50343
50363
|
return retriedResult.responseData;
|
|
50344
50364
|
}
|
|
50345
50365
|
if (error51 instanceof APIError) {
|
|
@@ -50351,6 +50371,25 @@ async function wpRequest(requestData, useJsonRpc = true, options = {}) {
|
|
|
50351
50371
|
throw new APIError(errorMessage, 0, getRequestUrl(), void 0, code);
|
|
50352
50372
|
}
|
|
50353
50373
|
}
|
|
50374
|
+
|
|
50375
|
+
// src/lib/tool-call-hooks.ts
|
|
50376
|
+
var REGISTRY_KEY = Symbol.for("@automattic/mcp-wordpress-remote:tool-call-hooks");
|
|
50377
|
+
function getRegistry() {
|
|
50378
|
+
const globalObject = globalThis;
|
|
50379
|
+
let registry2 = globalObject[REGISTRY_KEY];
|
|
50380
|
+
if (!registry2) {
|
|
50381
|
+
registry2 = /* @__PURE__ */ new Set();
|
|
50382
|
+
globalObject[REGISTRY_KEY] = registry2;
|
|
50383
|
+
}
|
|
50384
|
+
return registry2;
|
|
50385
|
+
}
|
|
50386
|
+
function registerToolCallHook(hook) {
|
|
50387
|
+
const registry2 = getRegistry();
|
|
50388
|
+
registry2.add(hook);
|
|
50389
|
+
return () => {
|
|
50390
|
+
registry2.delete(hook);
|
|
50391
|
+
};
|
|
50392
|
+
}
|
|
50354
50393
|
export {
|
|
50355
50394
|
APIError,
|
|
50356
50395
|
AuthError,
|
|
@@ -50377,6 +50416,7 @@ export {
|
|
|
50377
50416
|
logger,
|
|
50378
50417
|
parseCustomHeaders,
|
|
50379
50418
|
proxyFetch,
|
|
50419
|
+
registerToolCallHook,
|
|
50380
50420
|
setupFetchPolyfill,
|
|
50381
50421
|
validateConfig,
|
|
50382
50422
|
wpRequest
|
package/dist/proxy.js
CHANGED
|
@@ -3775,6 +3775,7 @@ var require_fast_uri = __commonJS({
|
|
|
3775
3775
|
return uriTokens.join("");
|
|
3776
3776
|
}
|
|
3777
3777
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3778
|
+
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
3778
3779
|
function getParseError(parsed, matches) {
|
|
3779
3780
|
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3780
3781
|
return 'URI path must start with "/" when authority is present.';
|
|
@@ -3804,6 +3805,11 @@ var require_fast_uri = __commonJS({
|
|
|
3804
3805
|
uri = "//" + uri;
|
|
3805
3806
|
}
|
|
3806
3807
|
}
|
|
3808
|
+
const authorityMatch = uri.match(AUTHORITY_PREFIX);
|
|
3809
|
+
if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
|
|
3810
|
+
parsed.error = "URI authority must not contain a literal backslash.";
|
|
3811
|
+
malformedAuthorityOrPort = true;
|
|
3812
|
+
}
|
|
3807
3813
|
const matches = uri.match(URI_PARSE);
|
|
3808
3814
|
if (matches) {
|
|
3809
3815
|
parsed.scheme = matches[1];
|
|
@@ -3847,7 +3853,7 @@ var require_fast_uri = __commonJS({
|
|
|
3847
3853
|
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
|
|
3848
3854
|
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP2 === false && nonSimpleDomain(parsed.host)) {
|
|
3849
3855
|
try {
|
|
3850
|
-
parsed.host = URL
|
|
3856
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3851
3857
|
} catch (e2) {
|
|
3852
3858
|
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e2;
|
|
3853
3859
|
}
|
|
@@ -27617,12 +27623,15 @@ var require_json = __commonJS({
|
|
|
27617
27623
|
var JSON_SYNTAX_REGEXP = /#+/g;
|
|
27618
27624
|
function json2(options) {
|
|
27619
27625
|
var opts = options || {};
|
|
27620
|
-
var limit = typeof opts.limit
|
|
27626
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
27621
27627
|
var inflate = opts.inflate !== false;
|
|
27622
27628
|
var reviver = opts.reviver;
|
|
27623
27629
|
var strict = opts.strict !== false;
|
|
27624
27630
|
var type = opts.type || "application/json";
|
|
27625
27631
|
var verify = opts.verify || false;
|
|
27632
|
+
if (limit === null) {
|
|
27633
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
27634
|
+
}
|
|
27626
27635
|
if (verify !== false && typeof verify !== "function") {
|
|
27627
27636
|
throw new TypeError("option verify must be function");
|
|
27628
27637
|
}
|
|
@@ -27744,9 +27753,12 @@ var require_raw = __commonJS({
|
|
|
27744
27753
|
function raw(options) {
|
|
27745
27754
|
var opts = options || {};
|
|
27746
27755
|
var inflate = opts.inflate !== false;
|
|
27747
|
-
var limit = typeof opts.limit
|
|
27756
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
27748
27757
|
var type = opts.type || "application/octet-stream";
|
|
27749
27758
|
var verify = opts.verify || false;
|
|
27759
|
+
if (limit === null) {
|
|
27760
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
27761
|
+
}
|
|
27750
27762
|
if (verify !== false && typeof verify !== "function") {
|
|
27751
27763
|
throw new TypeError("option verify must be function");
|
|
27752
27764
|
}
|
|
@@ -27802,9 +27814,12 @@ var require_text = __commonJS({
|
|
|
27802
27814
|
var opts = options || {};
|
|
27803
27815
|
var defaultCharset = opts.defaultCharset || "utf-8";
|
|
27804
27816
|
var inflate = opts.inflate !== false;
|
|
27805
|
-
var limit = typeof opts.limit
|
|
27817
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
27806
27818
|
var type = opts.type || "text/plain";
|
|
27807
27819
|
var verify = opts.verify || false;
|
|
27820
|
+
if (limit === null) {
|
|
27821
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
27822
|
+
}
|
|
27808
27823
|
if (verify !== false && typeof verify !== "function") {
|
|
27809
27824
|
throw new TypeError("option verify must be function");
|
|
27810
27825
|
}
|
|
@@ -30413,9 +30428,12 @@ var require_urlencoded = __commonJS({
|
|
|
30413
30428
|
}
|
|
30414
30429
|
var extended = opts.extended !== false;
|
|
30415
30430
|
var inflate = opts.inflate !== false;
|
|
30416
|
-
var limit = typeof opts.limit
|
|
30431
|
+
var limit = typeof opts.limit === "undefined" || opts.limit === null ? 102400 : bytes.parse(opts.limit);
|
|
30417
30432
|
var type = opts.type || "application/x-www-form-urlencoded";
|
|
30418
30433
|
var verify = opts.verify || false;
|
|
30434
|
+
if (limit === null) {
|
|
30435
|
+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid');
|
|
30436
|
+
}
|
|
30419
30437
|
if (verify !== false && typeof verify !== "function") {
|
|
30420
30438
|
throw new TypeError("option verify must be function");
|
|
30421
30439
|
}
|
|
@@ -55942,7 +55960,7 @@ async function selectCallbackPort(serverUrl, specifiedPort, _unused) {
|
|
|
55942
55960
|
}
|
|
55943
55961
|
|
|
55944
55962
|
// src/lib/config.ts
|
|
55945
|
-
var MCP_WORDPRESS_REMOTE_VERSION = "0.
|
|
55963
|
+
var MCP_WORDPRESS_REMOTE_VERSION = "0.4.0";
|
|
55946
55964
|
function parsePositiveIntEnv(value, defaultValue) {
|
|
55947
55965
|
if (!value) {
|
|
55948
55966
|
return defaultValue;
|
|
@@ -56387,13 +56405,19 @@ async function getAgentForUrl(url2) {
|
|
|
56387
56405
|
const socksMatch = directive.match(/SOCKS5?\s+(\S+):(\d+)/i);
|
|
56388
56406
|
if (socksMatch) {
|
|
56389
56407
|
const proxyUrl = `socks5h://${socksMatch[1]}:${socksMatch[2]}`;
|
|
56390
|
-
logger.debug(
|
|
56408
|
+
logger.debug(
|
|
56409
|
+
`PAC returned SOCKS proxy for ${url2}: ${sanitizeProxyUrl(proxyUrl)}`,
|
|
56410
|
+
"PROXY"
|
|
56411
|
+
);
|
|
56391
56412
|
return new SocksProxyAgent(proxyUrl);
|
|
56392
56413
|
}
|
|
56393
56414
|
const proxyMatch = directive.match(/PROXY\s+(\S+):(\d+)/i);
|
|
56394
56415
|
if (proxyMatch) {
|
|
56395
56416
|
const proxyUrl = `http://${proxyMatch[1]}:${proxyMatch[2]}`;
|
|
56396
|
-
logger.debug(
|
|
56417
|
+
logger.debug(
|
|
56418
|
+
`PAC returned HTTP proxy for ${url2}: ${sanitizeProxyUrl(proxyUrl)}`,
|
|
56419
|
+
"PROXY"
|
|
56420
|
+
);
|
|
56397
56421
|
return new HttpsProxyAgent(proxyUrl);
|
|
56398
56422
|
}
|
|
56399
56423
|
}
|
|
@@ -56574,7 +56598,7 @@ function mapHttpStatusToMcpCode(statusCode) {
|
|
|
56574
56598
|
RESOURCE_NOT_FOUND: -32002,
|
|
56575
56599
|
// Resource not found
|
|
56576
56600
|
TOOL_NOT_FOUND: -32003,
|
|
56577
|
-
// Tool not found
|
|
56601
|
+
// Tool not found
|
|
56578
56602
|
PROMPT_NOT_FOUND: -32004,
|
|
56579
56603
|
// Prompt not found
|
|
56580
56604
|
PERMISSION_DENIED: -32008,
|
|
@@ -56642,7 +56666,11 @@ function mcpErrorParts(error51) {
|
|
|
56642
56666
|
if (wpError) {
|
|
56643
56667
|
return { code: wpError.code, message: wpError.message ?? error51.message, data: wpError.data };
|
|
56644
56668
|
}
|
|
56645
|
-
return {
|
|
56669
|
+
return {
|
|
56670
|
+
code: deriveMcpErrorCode(error51),
|
|
56671
|
+
message: error51.message,
|
|
56672
|
+
data: buildApiErrorData(error51)
|
|
56673
|
+
};
|
|
56646
56674
|
}
|
|
56647
56675
|
function convertAPIErrorToMcpError(error51) {
|
|
56648
56676
|
return { error: mcpErrorParts(error51) };
|
|
@@ -57130,7 +57158,7 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl) {
|
|
|
57130
57158
|
const customHeaders = getCustomHeaders();
|
|
57131
57159
|
const response = await proxyFetch(metadataUrl.toString(), {
|
|
57132
57160
|
headers: {
|
|
57133
|
-
|
|
57161
|
+
Accept: "application/json",
|
|
57134
57162
|
...customHeaders
|
|
57135
57163
|
}
|
|
57136
57164
|
});
|
|
@@ -57167,7 +57195,7 @@ async function discoverProtectedResourceMetadata(resourceUrl) {
|
|
|
57167
57195
|
const customHeaders = getCustomHeaders();
|
|
57168
57196
|
const response = await proxyFetch(metadataUrl.toString(), {
|
|
57169
57197
|
headers: {
|
|
57170
|
-
|
|
57198
|
+
Accept: "application/json",
|
|
57171
57199
|
...customHeaders
|
|
57172
57200
|
}
|
|
57173
57201
|
});
|
|
@@ -57762,7 +57790,7 @@ var MCPOAuthProvider = class {
|
|
|
57762
57790
|
if (authInfo.resource_metadata_url) {
|
|
57763
57791
|
const metadataResponse = await proxyFetch(authInfo.resource_metadata_url, {
|
|
57764
57792
|
headers: {
|
|
57765
|
-
|
|
57793
|
+
Accept: "application/json",
|
|
57766
57794
|
...customHeaders
|
|
57767
57795
|
}
|
|
57768
57796
|
});
|
|
@@ -57799,6 +57827,12 @@ var MCPOAuthProvider = class {
|
|
|
57799
57827
|
logger.oauth("Using provided client ID, skipping dynamic registration");
|
|
57800
57828
|
return;
|
|
57801
57829
|
}
|
|
57830
|
+
const storedClientInfo = await readClientInfo(this.serverUrlHash);
|
|
57831
|
+
if (typeof storedClientInfo?.client_id === "string" && storedClientInfo.client_id.length > 0) {
|
|
57832
|
+
this.config.clientId = storedClientInfo.client_id;
|
|
57833
|
+
logger.oauth("Reusing persisted client registration, skipping dynamic registration");
|
|
57834
|
+
return;
|
|
57835
|
+
}
|
|
57802
57836
|
if (!CONFIG.OAUTH_DYNAMIC_REGISTRATION) {
|
|
57803
57837
|
throw new OAuthError2(
|
|
57804
57838
|
"No client ID provided and dynamic registration is disabled",
|
|
@@ -58722,10 +58756,7 @@ async function getOAuthTokens() {
|
|
|
58722
58756
|
return null;
|
|
58723
58757
|
}
|
|
58724
58758
|
} else {
|
|
58725
|
-
logger.warn(
|
|
58726
|
-
"Using legacy OAuth provider. Consider enabling PKCE for MCP compliance",
|
|
58727
|
-
"AUTH"
|
|
58728
|
-
);
|
|
58759
|
+
logger.warn("Using legacy OAuth provider. Consider enabling PKCE for MCP compliance", "AUTH");
|
|
58729
58760
|
if (!authCoordinator) {
|
|
58730
58761
|
if (!globalEvents) {
|
|
58731
58762
|
globalEvents = new EventEmitter3();
|
|
@@ -58971,7 +59002,10 @@ async function executeWordPressRequest(requestData, useJsonRpc, sessionIdUsed) {
|
|
|
58971
59002
|
}
|
|
58972
59003
|
async function refreshSession(failedSessionId) {
|
|
58973
59004
|
if (failedSessionId && globalSessionId && globalSessionId !== failedSessionId) {
|
|
58974
|
-
logger.info(
|
|
59005
|
+
logger.info(
|
|
59006
|
+
"Detected newer session while handling invalid-session error; skipping refresh",
|
|
59007
|
+
"SESSION"
|
|
59008
|
+
);
|
|
58975
59009
|
return;
|
|
58976
59010
|
}
|
|
58977
59011
|
if (sessionRefreshPromise) {
|
|
@@ -59025,11 +59059,7 @@ async function wpRequest(requestData, useJsonRpc = true, options = {}) {
|
|
|
59025
59059
|
sessionIdUsed: sessionIdUsed || "none"
|
|
59026
59060
|
});
|
|
59027
59061
|
await refreshSession(sessionIdUsed);
|
|
59028
|
-
const retriedResult = await executeWordPressRequest(
|
|
59029
|
-
requestData,
|
|
59030
|
-
useJsonRpc,
|
|
59031
|
-
globalSessionId
|
|
59032
|
-
);
|
|
59062
|
+
const retriedResult = await executeWordPressRequest(requestData, useJsonRpc, globalSessionId);
|
|
59033
59063
|
return retriedResult.responseData;
|
|
59034
59064
|
}
|
|
59035
59065
|
if (error51 instanceof APIError) {
|
|
@@ -59117,7 +59147,10 @@ async function waitForInit(context, timeoutMs = INIT_TIMEOUT_MS) {
|
|
|
59117
59147
|
|
|
59118
59148
|
// src/lib/transport-detection.ts
|
|
59119
59149
|
async function detectTransportType(context, initParams) {
|
|
59120
|
-
logger.info(
|
|
59150
|
+
logger.info(
|
|
59151
|
+
"\u{1F50D} Starting transport detection and WordPress API initialization...",
|
|
59152
|
+
"TRANSPORT_DETECT"
|
|
59153
|
+
);
|
|
59121
59154
|
let init;
|
|
59122
59155
|
let transportType = null;
|
|
59123
59156
|
const enhancedParams = initParams ? { ...initParams } : {};
|
|
@@ -59144,11 +59177,15 @@ async function detectTransportType(context, initParams) {
|
|
|
59144
59177
|
proxyVersion: MCP_WORDPRESS_REMOTE_VERSION
|
|
59145
59178
|
});
|
|
59146
59179
|
} else {
|
|
59147
|
-
logger.warn(
|
|
59148
|
-
|
|
59149
|
-
|
|
59150
|
-
|
|
59151
|
-
|
|
59180
|
+
logger.warn(
|
|
59181
|
+
"clientInfo is present but not a valid object, skipping enhancement",
|
|
59182
|
+
"TRANSPORT_DETECT",
|
|
59183
|
+
{
|
|
59184
|
+
clientInfoType: typeof enhancedParams.clientInfo,
|
|
59185
|
+
isArray: Array.isArray(enhancedParams.clientInfo),
|
|
59186
|
+
isNull: enhancedParams.clientInfo === null
|
|
59187
|
+
}
|
|
59188
|
+
);
|
|
59152
59189
|
}
|
|
59153
59190
|
} else {
|
|
59154
59191
|
logger.debug("No clientInfo provided in initialize parameters", "TRANSPORT_DETECT");
|
|
@@ -59202,8 +59239,14 @@ async function detectTransportType(context, initParams) {
|
|
|
59202
59239
|
logger.info("\u2705 Simple transport detected and working", "TRANSPORT_DETECT");
|
|
59203
59240
|
logger.debug("Simple initialization response:", "TRANSPORT_DETECT", init);
|
|
59204
59241
|
} catch (simpleError) {
|
|
59205
|
-
logger.error(
|
|
59206
|
-
|
|
59242
|
+
logger.error(
|
|
59243
|
+
"\u274C Both JSON-RPC and simple transports failed",
|
|
59244
|
+
"TRANSPORT_DETECT",
|
|
59245
|
+
simpleError
|
|
59246
|
+
);
|
|
59247
|
+
const connectionError = new Error(
|
|
59248
|
+
"Unable to establish connection with either transport type"
|
|
59249
|
+
);
|
|
59207
59250
|
connectionError.cause = simpleError;
|
|
59208
59251
|
throw connectionError;
|
|
59209
59252
|
}
|
|
@@ -59216,7 +59259,10 @@ async function detectTransportType(context, initParams) {
|
|
|
59216
59259
|
} else {
|
|
59217
59260
|
logger.warn("No session ID received from WordPress - continuing without session", "PROXY");
|
|
59218
59261
|
}
|
|
59219
|
-
logger.info(
|
|
59262
|
+
logger.info(
|
|
59263
|
+
`WordPress connection initialized successfully using ${transportType} transport`,
|
|
59264
|
+
"PROXY"
|
|
59265
|
+
);
|
|
59220
59266
|
return {
|
|
59221
59267
|
transportType,
|
|
59222
59268
|
initResult: init,
|
|
@@ -59224,6 +59270,31 @@ async function detectTransportType(context, initParams) {
|
|
|
59224
59270
|
};
|
|
59225
59271
|
}
|
|
59226
59272
|
|
|
59273
|
+
// src/lib/tool-call-hooks.ts
|
|
59274
|
+
var REGISTRY_KEY = Symbol.for("@automattic/mcp-wordpress-remote:tool-call-hooks");
|
|
59275
|
+
function getRegistry() {
|
|
59276
|
+
const globalObject = globalThis;
|
|
59277
|
+
let registry2 = globalObject[REGISTRY_KEY];
|
|
59278
|
+
if (!registry2) {
|
|
59279
|
+
registry2 = /* @__PURE__ */ new Set();
|
|
59280
|
+
globalObject[REGISTRY_KEY] = registry2;
|
|
59281
|
+
}
|
|
59282
|
+
return registry2;
|
|
59283
|
+
}
|
|
59284
|
+
function runToolCallHooks(context) {
|
|
59285
|
+
const hooks = [...getRegistry()];
|
|
59286
|
+
if (hooks.length === 0) return;
|
|
59287
|
+
setImmediate(() => {
|
|
59288
|
+
for (const hook of hooks) {
|
|
59289
|
+
void Promise.resolve().then(() => hook(context)).catch((error51) => {
|
|
59290
|
+
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
59291
|
+
logger.error(`Tool-call hook failed: ${message}`, "HOOKS");
|
|
59292
|
+
}).catch(() => {
|
|
59293
|
+
});
|
|
59294
|
+
}
|
|
59295
|
+
});
|
|
59296
|
+
}
|
|
59297
|
+
|
|
59227
59298
|
// src/lib/request-handler-factory.ts
|
|
59228
59299
|
function createRequestHandler(config2, context) {
|
|
59229
59300
|
return async (request) => {
|
|
@@ -59245,6 +59316,10 @@ function createRequestHandler(config2, context) {
|
|
|
59245
59316
|
const wpParams = config2.paramMapper(request);
|
|
59246
59317
|
const requestData = prepareRequest(wpParams, request, context);
|
|
59247
59318
|
const response = await wpRequest(requestData, context.transportType === "jsonrpc");
|
|
59319
|
+
if (config2.method === "tools/call") {
|
|
59320
|
+
const hookWpRequest = (params) => wpRequest(prepareRequest(params, {}, context), context.transportType === "jsonrpc");
|
|
59321
|
+
runToolCallHooks({ name: String(wpParams.name ?? ""), wpRequest: hookWpRequest });
|
|
59322
|
+
}
|
|
59248
59323
|
return response;
|
|
59249
59324
|
};
|
|
59250
59325
|
}
|
|
@@ -59285,19 +59360,27 @@ function createWrappedHandler(config2, context) {
|
|
|
59285
59360
|
});
|
|
59286
59361
|
if (isAPIError(error51)) {
|
|
59287
59362
|
if (context.transportType === "simple") {
|
|
59288
|
-
logger.debug(
|
|
59363
|
+
logger.debug(
|
|
59364
|
+
`Converting APIError to MCP error format for ${config2.name} (simple transport)`,
|
|
59365
|
+
"MCP",
|
|
59366
|
+
{
|
|
59367
|
+
statusCode: error51.statusCode,
|
|
59368
|
+
endpoint: error51.endpoint,
|
|
59369
|
+
message: error51.message
|
|
59370
|
+
}
|
|
59371
|
+
);
|
|
59372
|
+
return convertAPIErrorToMcpError(error51);
|
|
59373
|
+
}
|
|
59374
|
+
logger.debug(
|
|
59375
|
+
`Converting APIError to McpError for ${config2.name} (jsonrpc transport)`,
|
|
59376
|
+
"MCP",
|
|
59377
|
+
{
|
|
59289
59378
|
statusCode: error51.statusCode,
|
|
59379
|
+
code: error51.code,
|
|
59290
59380
|
endpoint: error51.endpoint,
|
|
59291
59381
|
message: error51.message
|
|
59292
|
-
}
|
|
59293
|
-
|
|
59294
|
-
}
|
|
59295
|
-
logger.debug(`Converting APIError to McpError for ${config2.name} (jsonrpc transport)`, "MCP", {
|
|
59296
|
-
statusCode: error51.statusCode,
|
|
59297
|
-
code: error51.code,
|
|
59298
|
-
endpoint: error51.endpoint,
|
|
59299
|
-
message: error51.message
|
|
59300
|
-
});
|
|
59382
|
+
}
|
|
59383
|
+
);
|
|
59301
59384
|
throw apiErrorToMcpError(error51);
|
|
59302
59385
|
}
|
|
59303
59386
|
throw error51;
|
|
@@ -59467,7 +59550,9 @@ async function WordPressProxy() {
|
|
|
59467
59550
|
version: MCP_WORDPRESS_REMOTE_VERSION
|
|
59468
59551
|
},
|
|
59469
59552
|
capabilities: {
|
|
59470
|
-
experimental: {
|
|
59553
|
+
experimental: {
|
|
59554
|
+
connectionFailed: connectionError.code ? { code: connectionError.code } : {}
|
|
59555
|
+
}
|
|
59471
59556
|
},
|
|
59472
59557
|
instructions: `MCP WordPress Remote Proxy Server (Connection Failed${connectionError.code ? `: ${connectionError.code}` : ""})`
|
|
59473
59558
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/mcp-wordpress-remote",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "MCP WordPress Remote proxy server",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"proxy"
|
|
13
13
|
],
|
|
14
14
|
"author": "Automattic Inc.",
|
|
15
|
+
"license": "MIT",
|
|
15
16
|
"repository": {
|
|
16
17
|
"type": "git",
|
|
17
18
|
"url": "git+https://github.com/Automattic/mcp-wordpress-remote.git"
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
"scripts": {
|
|
40
41
|
"build": "tsup",
|
|
41
42
|
"build:watch": "tsup --watch",
|
|
42
|
-
"check": "prettier --check
|
|
43
|
+
"check": "prettier --check src && tsc --noEmit",
|
|
43
44
|
"start": "NODE_ENV=development tsup --watch",
|
|
44
45
|
"dev": "NODE_ENV=development node dist/proxy.js",
|
|
45
46
|
"test": "jest",
|