@automattic/mcp-wordpress-remote 0.2.21 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -17
- package/dist/lib.d.ts +4 -2
- package/dist/lib.js +295 -50
- package/dist/proxy.js +295 -50
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Add to your MCP client configuration (e.g., Claude Desktop's `claude_desktop_con
|
|
|
38
38
|
"command": "npx",
|
|
39
39
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
40
40
|
"env": {
|
|
41
|
-
"WP_API_URL": "https://your-wordpress-site.com"
|
|
41
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server"
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -58,7 +58,7 @@ You can add custom headers to all API requests using the `CUSTOM_HEADERS` enviro
|
|
|
58
58
|
"command": "npx",
|
|
59
59
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
60
60
|
"env": {
|
|
61
|
-
"WP_API_URL": "https://your-wordpress-site.com",
|
|
61
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server",
|
|
62
62
|
"CUSTOM_HEADERS": "{\"X-MCP-API-Key\": \"*Ibo7tweixlbfuwaiufxgakjyefctwajcetb*\", \"X-Custom-Header\": \"value\"}"
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -75,7 +75,7 @@ You can add custom headers to all API requests using the `CUSTOM_HEADERS` enviro
|
|
|
75
75
|
"command": "npx",
|
|
76
76
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
77
77
|
"env": {
|
|
78
|
-
"WP_API_URL": "https://your-wordpress-site.com",
|
|
78
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server",
|
|
79
79
|
"CUSTOM_HEADERS": "X-MCP-API-Key:IOskncfyes78U8on3q7ry43o487tybrc,X-Custom-Header:value"
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -87,7 +87,7 @@ You can add custom headers to all API requests using the `CUSTOM_HEADERS` enviro
|
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
89
|
CUSTOM_HEADERS='{"X-MCP-API-Key": "wc_mcp_FaQduhQcW0mfVaZgP3yaaqDuXaZ3mw7j"}' \
|
|
90
|
-
WP_API_URL="https://your-site.com" \
|
|
90
|
+
WP_API_URL="https://your-site.com/wp-json/mcp/mcp-adapter-default-server" \
|
|
91
91
|
npx @automattic/mcp-wordpress-remote
|
|
92
92
|
```
|
|
93
93
|
|
|
@@ -109,7 +109,11 @@ Custom headers are included in:
|
|
|
109
109
|
|
|
110
110
|
## WordPress MCP Plugin
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
Install the [MCP Adapter](https://github.com/WordPress/mcp-adapter) plugin on your WordPress site. Once active, it registers a default MCP server at `/wp-json/mcp/mcp-adapter-default-server` — set `WP_API_URL` to that full URL (examples throughout this README show the pattern). To target a custom server id or namespace, pass the full URL of that server instead.
|
|
113
|
+
|
|
114
|
+
### Legacy `wordpress-mcp` plugin
|
|
115
|
+
|
|
116
|
+
Earlier versions of this proxy were designed for [`Automattic/wordpress-mcp`](https://github.com/Automattic/wordpress-mcp), which exposes its endpoint at `/wp-json/wp/v2/wpmcp`. That plugin is deprecated in favor of `mcp-adapter`, but existing installs continue to work — for backwards compatibility, a bare-domain `WP_API_URL` (e.g. `https://your-wordpress-site.com`) still resolves to the `wordpress-mcp` endpoint. New setups should install `mcp-adapter` and use the full URL shown above.
|
|
113
117
|
|
|
114
118
|
## Authentication Methods
|
|
115
119
|
|
|
@@ -126,7 +130,7 @@ OAuth 2.1 provides the most secure and user-friendly experience with full MCP Au
|
|
|
126
130
|
"command": "npx",
|
|
127
131
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
128
132
|
"env": {
|
|
129
|
-
"WP_API_URL": "https://your-wordpress-site.com",
|
|
133
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server",
|
|
130
134
|
"OAUTH_ENABLED": "true"
|
|
131
135
|
}
|
|
132
136
|
}
|
|
@@ -163,7 +167,7 @@ For server-to-server authentication or when OAuth is not available.
|
|
|
163
167
|
"command": "npx",
|
|
164
168
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
165
169
|
"env": {
|
|
166
|
-
"WP_API_URL": "https://your-wordpress-site.com",
|
|
170
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server",
|
|
167
171
|
"JWT_TOKEN": "your-jwt-token-here"
|
|
168
172
|
}
|
|
169
173
|
}
|
|
@@ -182,7 +186,7 @@ Uses WordPress username and application password for basic authentication.
|
|
|
182
186
|
"command": "npx",
|
|
183
187
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
184
188
|
"env": {
|
|
185
|
-
"WP_API_URL": "https://your-wordpress-site.com",
|
|
189
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server",
|
|
186
190
|
"WP_API_USERNAME": "your-username",
|
|
187
191
|
"WP_API_PASSWORD": "your-application-password",
|
|
188
192
|
"OAUTH_ENABLED": "false"
|
|
@@ -210,7 +214,7 @@ To create an application password:
|
|
|
210
214
|
"command": "npx",
|
|
211
215
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
212
216
|
"env": {
|
|
213
|
-
"WP_API_URL": "https://your-wordpress-site.com",
|
|
217
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server",
|
|
214
218
|
"OAUTH_CALLBACK_PORT": "7665",
|
|
215
219
|
"OAUTH_HOST": "127.0.0.1",
|
|
216
220
|
"WP_OAUTH_CLIENT_ID": "your-custom-client-id"
|
|
@@ -231,7 +235,7 @@ For WooCommerce-specific tools and reports:
|
|
|
231
235
|
"command": "npx",
|
|
232
236
|
"args": ["-y", "@automattic/mcp-wordpress-remote"],
|
|
233
237
|
"env": {
|
|
234
|
-
"WP_API_URL": "https://your-wordpress-site.com",
|
|
238
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server",
|
|
235
239
|
"WOO_CUSTOMER_KEY": "ck_your-consumer-key",
|
|
236
240
|
"WOO_CUSTOMER_SECRET": "cs_your-consumer-secret"
|
|
237
241
|
}
|
|
@@ -244,7 +248,7 @@ For WooCommerce-specific tools and reports:
|
|
|
244
248
|
|
|
245
249
|
| Variable | Description | Default | Required |
|
|
246
250
|
| ----------------------------- | ------------------------------------------------ | -------------------- | --------------------- |
|
|
247
|
-
| `WP_API_URL` | WordPress site URL
|
|
251
|
+
| `WP_API_URL` | WordPress site URL including the MCP endpoint path (e.g. `…/wp-json/mcp/mcp-adapter-default-server`). A bare domain resolves to the deprecated `wordpress-mcp` endpoint for backwards compatibility. | - | ✅ |
|
|
248
252
|
| `OAUTH_ENABLED` | Enable OAuth authentication | `true` | - |
|
|
249
253
|
| `OAUTH_CALLBACK_PORT` | OAuth callback port | `7665` | - |
|
|
250
254
|
| `OAUTH_HOST` | OAuth callback hostname | `127.0.0.1` | - |
|
|
@@ -317,7 +321,7 @@ Configure your MCP client to use the local version:
|
|
|
317
321
|
"command": "node",
|
|
318
322
|
"args": ["/path/to/your/mcp-wordpress-remote/dist/proxy.js"],
|
|
319
323
|
"env": {
|
|
320
|
-
"WP_API_URL": "https://your-wordpress-site.com"
|
|
324
|
+
"WP_API_URL": "https://your-wordpress-site.com/wp-json/mcp/mcp-adapter-default-server"
|
|
321
325
|
}
|
|
322
326
|
}
|
|
323
327
|
}
|
|
@@ -403,9 +407,8 @@ If you see "waiting for other instance" messages, this is normal behavior.
|
|
|
403
407
|
|
|
404
408
|
**API endpoint not found:**
|
|
405
409
|
|
|
406
|
-
- Verify
|
|
407
|
-
-
|
|
408
|
-
- Confirm `WP_API_URL` is correct
|
|
410
|
+
- Verify the [MCP Adapter](https://github.com/WordPress/mcp-adapter) plugin is installed and active
|
|
411
|
+
- Confirm `WP_API_URL` points at the server route (e.g. `…/wp-json/mcp/mcp-adapter-default-server`)
|
|
409
412
|
|
|
410
413
|
**Permission denied:**
|
|
411
414
|
|
|
@@ -469,7 +472,7 @@ Log levels:
|
|
|
469
472
|
## Requirements
|
|
470
473
|
|
|
471
474
|
- **Node.js 22+** (required for fetch API support)
|
|
472
|
-
- **WordPress site** with [
|
|
475
|
+
- **WordPress site** with the [MCP Adapter](https://github.com/WordPress/mcp-adapter) plugin installed and active
|
|
473
476
|
- **WordPress user account** with appropriate permissions
|
|
474
477
|
|
|
475
478
|
## License
|
|
@@ -484,7 +487,7 @@ Contributions welcome! This project is maintained by Automattic Inc.
|
|
|
484
487
|
|
|
485
488
|
- **Issues:** [GitHub Issues](https://github.com/Automattic/mcp-wordpress-remote/issues)
|
|
486
489
|
- **Documentation:** Check the troubleshooting section above
|
|
487
|
-
- **WordPress MCP Plugin:** [
|
|
490
|
+
- **WordPress MCP Plugin:** [WordPress/mcp-adapter](https://github.com/WordPress/mcp-adapter)
|
|
488
491
|
|
|
489
492
|
---
|
|
490
493
|
|
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.3.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
|
|
@@ -149,7 +149,9 @@ declare const logger: {
|
|
|
149
149
|
config: (message: string, level?: LogLevel, ...args: any[]) => void;
|
|
150
150
|
};
|
|
151
151
|
|
|
152
|
-
declare function wpRequest(requestData: any, useJsonRpc?: boolean
|
|
152
|
+
declare function wpRequest(requestData: any, useJsonRpc?: boolean, options?: {
|
|
153
|
+
allowSessionRecovery?: boolean;
|
|
154
|
+
}): Promise<WordPressResponse>;
|
|
153
155
|
|
|
154
156
|
/**
|
|
155
157
|
* WordPress OAuth types and error definitions
|
package/dist/lib.js
CHANGED
|
@@ -91,13 +91,13 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
91
91
|
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, factory(global2.WebStreamsPolyfill = {}));
|
|
92
92
|
})(exports, function(exports2) {
|
|
93
93
|
"use strict";
|
|
94
|
-
function
|
|
94
|
+
function noop3() {
|
|
95
95
|
return void 0;
|
|
96
96
|
}
|
|
97
97
|
function typeIsObject(x2) {
|
|
98
98
|
return typeof x2 === "object" && x2 !== null || typeof x2 === "function";
|
|
99
99
|
}
|
|
100
|
-
const rethrowAssertionErrorRejection =
|
|
100
|
+
const rethrowAssertionErrorRejection = noop3;
|
|
101
101
|
function setFunctionName(fn, name) {
|
|
102
102
|
try {
|
|
103
103
|
Object.defineProperty(fn, "name", {
|
|
@@ -2726,7 +2726,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
2726
2726
|
return newPromise((resolveRead, rejectRead) => {
|
|
2727
2727
|
ReadableStreamDefaultReaderRead(reader, {
|
|
2728
2728
|
_chunkSteps: (chunk) => {
|
|
2729
|
-
currentWrite = PerformPromiseThen(WritableStreamDefaultWriterWrite(writer, chunk), void 0,
|
|
2729
|
+
currentWrite = PerformPromiseThen(WritableStreamDefaultWriterWrite(writer, chunk), void 0, noop3);
|
|
2730
2730
|
resolveRead(false);
|
|
2731
2731
|
},
|
|
2732
2732
|
_closeSteps: () => resolveRead(true),
|
|
@@ -3407,7 +3407,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
3407
3407
|
function ReadableStreamFromIterable(asyncIterable) {
|
|
3408
3408
|
let stream;
|
|
3409
3409
|
const iteratorRecord = GetIterator(asyncIterable, "async");
|
|
3410
|
-
const startAlgorithm =
|
|
3410
|
+
const startAlgorithm = noop3;
|
|
3411
3411
|
function pullAlgorithm() {
|
|
3412
3412
|
let nextResult;
|
|
3413
3413
|
try {
|
|
@@ -3459,7 +3459,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
3459
3459
|
}
|
|
3460
3460
|
function ReadableStreamFromDefaultReader(reader) {
|
|
3461
3461
|
let stream;
|
|
3462
|
-
const startAlgorithm =
|
|
3462
|
+
const startAlgorithm = noop3;
|
|
3463
3463
|
function pullAlgorithm() {
|
|
3464
3464
|
let readPromise;
|
|
3465
3465
|
try {
|
|
@@ -3778,7 +3778,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
3778
3778
|
});
|
|
3779
3779
|
}
|
|
3780
3780
|
const sourceCancelPromise = stream._readableStreamController[CancelSteps](reason);
|
|
3781
|
-
return transformPromiseWith(sourceCancelPromise,
|
|
3781
|
+
return transformPromiseWith(sourceCancelPromise, noop3);
|
|
3782
3782
|
}
|
|
3783
3783
|
function ReadableStreamClose(stream) {
|
|
3784
3784
|
stream._state = "closed";
|
|
@@ -4999,7 +4999,7 @@ async function toFormData(Body2, ct) {
|
|
|
4999
4999
|
parser.end();
|
|
5000
5000
|
return formData;
|
|
5001
5001
|
}
|
|
5002
|
-
var s, S, f2, F, LF, CR, SPACE, HYPHEN, COLON, A, Z, lower,
|
|
5002
|
+
var s, S, f2, F, LF, CR, SPACE, HYPHEN, COLON, A, Z, lower, noop2, MultipartParser;
|
|
5003
5003
|
var init_multipart_parser = __esm({
|
|
5004
5004
|
"node_modules/node-fetch/src/utils/multipart-parser.js"() {
|
|
5005
5005
|
"use strict";
|
|
@@ -5031,7 +5031,7 @@ var init_multipart_parser = __esm({
|
|
|
5031
5031
|
A = 97;
|
|
5032
5032
|
Z = 122;
|
|
5033
5033
|
lower = (c) => c | 32;
|
|
5034
|
-
|
|
5034
|
+
noop2 = () => {
|
|
5035
5035
|
};
|
|
5036
5036
|
MultipartParser = class {
|
|
5037
5037
|
/**
|
|
@@ -5040,13 +5040,13 @@ var init_multipart_parser = __esm({
|
|
|
5040
5040
|
constructor(boundary) {
|
|
5041
5041
|
this.index = 0;
|
|
5042
5042
|
this.flags = 0;
|
|
5043
|
-
this.onHeaderEnd =
|
|
5044
|
-
this.onHeaderField =
|
|
5045
|
-
this.onHeadersEnd =
|
|
5046
|
-
this.onHeaderValue =
|
|
5047
|
-
this.onPartBegin =
|
|
5048
|
-
this.onPartData =
|
|
5049
|
-
this.onPartEnd =
|
|
5043
|
+
this.onHeaderEnd = noop2;
|
|
5044
|
+
this.onHeaderField = noop2;
|
|
5045
|
+
this.onHeadersEnd = noop2;
|
|
5046
|
+
this.onHeaderValue = noop2;
|
|
5047
|
+
this.onPartBegin = noop2;
|
|
5048
|
+
this.onPartData = noop2;
|
|
5049
|
+
this.onPartEnd = noop2;
|
|
5050
5050
|
this.boundaryChars = {};
|
|
5051
5051
|
boundary = "\r\n--" + boundary;
|
|
5052
5052
|
const ui8a = new Uint8Array(boundary.length);
|
|
@@ -7881,7 +7881,7 @@ var require_destroy = __commonJS({
|
|
|
7881
7881
|
}
|
|
7882
7882
|
if (isEventEmitter(stream) && suppress) {
|
|
7883
7883
|
stream.removeAllListeners("error");
|
|
7884
|
-
stream.addListener("error",
|
|
7884
|
+
stream.addListener("error", noop3);
|
|
7885
7885
|
}
|
|
7886
7886
|
return stream;
|
|
7887
7887
|
}
|
|
@@ -7936,7 +7936,7 @@ var require_destroy = __commonJS({
|
|
|
7936
7936
|
function isZlibStream(stream) {
|
|
7937
7937
|
return stream instanceof Zlib.Gzip || stream instanceof Zlib.Gunzip || stream instanceof Zlib.Deflate || stream instanceof Zlib.DeflateRaw || stream instanceof Zlib.Inflate || stream instanceof Zlib.InflateRaw || stream instanceof Zlib.Unzip;
|
|
7938
7938
|
}
|
|
7939
|
-
function
|
|
7939
|
+
function noop3() {
|
|
7940
7940
|
}
|
|
7941
7941
|
function onDrainClearBinding() {
|
|
7942
7942
|
this._binding.clear();
|
|
@@ -30288,6 +30288,109 @@ var require_express2 = __commonJS({
|
|
|
30288
30288
|
}
|
|
30289
30289
|
});
|
|
30290
30290
|
|
|
30291
|
+
// node_modules/eventsource-parser/dist/index.js
|
|
30292
|
+
var ParseError = class extends Error {
|
|
30293
|
+
constructor(message, options) {
|
|
30294
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
30295
|
+
}
|
|
30296
|
+
};
|
|
30297
|
+
function noop(_arg) {
|
|
30298
|
+
}
|
|
30299
|
+
function createParser(callbacks) {
|
|
30300
|
+
if (typeof callbacks == "function")
|
|
30301
|
+
throw new TypeError(
|
|
30302
|
+
"`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"
|
|
30303
|
+
);
|
|
30304
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks;
|
|
30305
|
+
let incompleteLine = "", isFirstChunk = true, id, data = "", eventType = "";
|
|
30306
|
+
function feed(newChunk) {
|
|
30307
|
+
const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines(`${incompleteLine}${chunk}`);
|
|
30308
|
+
for (const line of complete)
|
|
30309
|
+
parseLine(line);
|
|
30310
|
+
incompleteLine = incomplete, isFirstChunk = false;
|
|
30311
|
+
}
|
|
30312
|
+
function parseLine(line) {
|
|
30313
|
+
if (line === "") {
|
|
30314
|
+
dispatchEvent();
|
|
30315
|
+
return;
|
|
30316
|
+
}
|
|
30317
|
+
if (line.startsWith(":")) {
|
|
30318
|
+
onComment && onComment(line.slice(line.startsWith(": ") ? 2 : 1));
|
|
30319
|
+
return;
|
|
30320
|
+
}
|
|
30321
|
+
const fieldSeparatorIndex = line.indexOf(":");
|
|
30322
|
+
if (fieldSeparatorIndex !== -1) {
|
|
30323
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
30324
|
+
processField(field, value, line);
|
|
30325
|
+
return;
|
|
30326
|
+
}
|
|
30327
|
+
processField(line, "", line);
|
|
30328
|
+
}
|
|
30329
|
+
function processField(field, value, line) {
|
|
30330
|
+
switch (field) {
|
|
30331
|
+
case "event":
|
|
30332
|
+
eventType = value;
|
|
30333
|
+
break;
|
|
30334
|
+
case "data":
|
|
30335
|
+
data = `${data}${value}
|
|
30336
|
+
`;
|
|
30337
|
+
break;
|
|
30338
|
+
case "id":
|
|
30339
|
+
id = value.includes("\0") ? void 0 : value;
|
|
30340
|
+
break;
|
|
30341
|
+
case "retry":
|
|
30342
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
30343
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
30344
|
+
type: "invalid-retry",
|
|
30345
|
+
value,
|
|
30346
|
+
line
|
|
30347
|
+
})
|
|
30348
|
+
);
|
|
30349
|
+
break;
|
|
30350
|
+
default:
|
|
30351
|
+
onError(
|
|
30352
|
+
new ParseError(
|
|
30353
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
30354
|
+
{ type: "unknown-field", field, value, line }
|
|
30355
|
+
)
|
|
30356
|
+
);
|
|
30357
|
+
break;
|
|
30358
|
+
}
|
|
30359
|
+
}
|
|
30360
|
+
function dispatchEvent() {
|
|
30361
|
+
data.length > 0 && onEvent({
|
|
30362
|
+
id,
|
|
30363
|
+
event: eventType || void 0,
|
|
30364
|
+
// If the data buffer's last character is a U+000A LINE FEED (LF) character,
|
|
30365
|
+
// then remove the last character from the data buffer.
|
|
30366
|
+
data: data.endsWith(`
|
|
30367
|
+
`) ? data.slice(0, -1) : data
|
|
30368
|
+
}), id = void 0, data = "", eventType = "";
|
|
30369
|
+
}
|
|
30370
|
+
function reset(options = {}) {
|
|
30371
|
+
incompleteLine && options.consume && parseLine(incompleteLine), isFirstChunk = true, id = void 0, data = "", eventType = "", incompleteLine = "";
|
|
30372
|
+
}
|
|
30373
|
+
return { feed, reset };
|
|
30374
|
+
}
|
|
30375
|
+
function splitLines(chunk) {
|
|
30376
|
+
const lines = [];
|
|
30377
|
+
let incompleteLine = "", searchIndex = 0;
|
|
30378
|
+
for (; searchIndex < chunk.length; ) {
|
|
30379
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
30380
|
+
`, searchIndex);
|
|
30381
|
+
let lineEnd = -1;
|
|
30382
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = Math.min(crIndex, lfIndex) : crIndex !== -1 ? lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) {
|
|
30383
|
+
incompleteLine = chunk.slice(searchIndex);
|
|
30384
|
+
break;
|
|
30385
|
+
} else {
|
|
30386
|
+
const line = chunk.slice(searchIndex, lineEnd);
|
|
30387
|
+
lines.push(line), searchIndex = lineEnd + 1, chunk[searchIndex - 1] === "\r" && chunk[searchIndex] === `
|
|
30388
|
+
` && searchIndex++;
|
|
30389
|
+
}
|
|
30390
|
+
}
|
|
30391
|
+
return [lines, incompleteLine];
|
|
30392
|
+
}
|
|
30393
|
+
|
|
30291
30394
|
// node_modules/zod/lib/index.mjs
|
|
30292
30395
|
var util;
|
|
30293
30396
|
(function(util2) {
|
|
@@ -35153,10 +35256,9 @@ import crypto3 from "crypto";
|
|
|
35153
35256
|
import path from "path";
|
|
35154
35257
|
import fs from "fs/promises";
|
|
35155
35258
|
import crypto2 from "crypto";
|
|
35156
|
-
var VERSION = MCP_WORDPRESS_REMOTE_VERSION;
|
|
35157
35259
|
function getConfigDir() {
|
|
35158
35260
|
const baseConfigDir = CONFIG.WP_MCP_CONFIG_DIR;
|
|
35159
|
-
return path.join(baseConfigDir, `wordpress-remote-${
|
|
35261
|
+
return path.join(baseConfigDir, `wordpress-remote-${MCP_WORDPRESS_REMOTE_VERSION}`);
|
|
35160
35262
|
}
|
|
35161
35263
|
async function ensureConfigDir() {
|
|
35162
35264
|
try {
|
|
@@ -35346,7 +35448,7 @@ function calculateDefaultPort(serverUrlHash) {
|
|
|
35346
35448
|
}
|
|
35347
35449
|
async function findExistingClientPort(serverUrlHash) {
|
|
35348
35450
|
const clientInfo = await readJsonFile(serverUrlHash, "client_info.json");
|
|
35349
|
-
if (!clientInfo) {
|
|
35451
|
+
if (!clientInfo || !clientInfo.redirect_uris) {
|
|
35350
35452
|
return void 0;
|
|
35351
35453
|
}
|
|
35352
35454
|
const localhostRedirectUri = clientInfo.redirect_uris.map((uri) => {
|
|
@@ -35382,7 +35484,7 @@ async function selectCallbackPort(serverUrl, specifiedPort, _unused) {
|
|
|
35382
35484
|
}
|
|
35383
35485
|
|
|
35384
35486
|
// src/lib/config.ts
|
|
35385
|
-
var MCP_WORDPRESS_REMOTE_VERSION = "0.
|
|
35487
|
+
var MCP_WORDPRESS_REMOTE_VERSION = "0.3.0";
|
|
35386
35488
|
var CONFIG = {
|
|
35387
35489
|
// API Configuration
|
|
35388
35490
|
WP_API_URL: process.env.WP_API_URL || "https://example.com",
|
|
@@ -36889,17 +36991,14 @@ var OAuthCallbackServer = class {
|
|
|
36889
36991
|
});
|
|
36890
36992
|
}
|
|
36891
36993
|
async stop() {
|
|
36892
|
-
|
|
36893
|
-
|
|
36894
|
-
|
|
36895
|
-
|
|
36896
|
-
|
|
36897
|
-
|
|
36898
|
-
});
|
|
36899
|
-
} else {
|
|
36900
|
-
resolve();
|
|
36901
|
-
}
|
|
36994
|
+
if (!this.server) return;
|
|
36995
|
+
const server = this.server;
|
|
36996
|
+
this.server = null;
|
|
36997
|
+
server.close((err) => {
|
|
36998
|
+
if (err) logger.error("OAuth callback server close error", "OAUTH", err);
|
|
36999
|
+
else logger.oauth("OAuth callback server stopped");
|
|
36902
37000
|
});
|
|
37001
|
+
server.closeAllConnections?.();
|
|
36903
37002
|
}
|
|
36904
37003
|
getCallbackUrl() {
|
|
36905
37004
|
return `http://${this.options.host}:${this.options.port}/oauth/callback`;
|
|
@@ -37904,6 +38003,11 @@ var mcpOAuthProvider = null;
|
|
|
37904
38003
|
var authCoordinator = null;
|
|
37905
38004
|
var globalEvents = null;
|
|
37906
38005
|
var globalSessionId = null;
|
|
38006
|
+
var lastInitializeRequest = null;
|
|
38007
|
+
var sessionRefreshPromise = null;
|
|
38008
|
+
var WP_MCP_ENDPOINT = "/wp/v2/wpmcp";
|
|
38009
|
+
var INVALID_SESSION_ERROR_CODE = -32602;
|
|
38010
|
+
var INVALID_SESSION_ERROR_MESSAGE = "Invalid or expired session";
|
|
37907
38011
|
function validateEnvironment() {
|
|
37908
38012
|
const validation = validateConfig();
|
|
37909
38013
|
if (!validation.isValid) {
|
|
@@ -37916,6 +38020,24 @@ function validateEnvironment() {
|
|
|
37916
38020
|
function removeTrailingSlash(url) {
|
|
37917
38021
|
return url.replace(/\/+$/, "");
|
|
37918
38022
|
}
|
|
38023
|
+
function parseSSEMessage(text) {
|
|
38024
|
+
let result;
|
|
38025
|
+
let found = false;
|
|
38026
|
+
const parser = createParser({
|
|
38027
|
+
onEvent(event) {
|
|
38028
|
+
if (found) return;
|
|
38029
|
+
if (!event.event || event.event === "message") {
|
|
38030
|
+
result = JSON.parse(event.data);
|
|
38031
|
+
found = true;
|
|
38032
|
+
}
|
|
38033
|
+
}
|
|
38034
|
+
});
|
|
38035
|
+
parser.feed(text);
|
|
38036
|
+
if (!found) {
|
|
38037
|
+
throw new Error('No "message" event with data found in SSE response');
|
|
38038
|
+
}
|
|
38039
|
+
return result;
|
|
38040
|
+
}
|
|
37919
38041
|
function constructApiUrl(baseUrl, defaultEndpoint) {
|
|
37920
38042
|
const cleanUrl = removeTrailingSlash(baseUrl);
|
|
37921
38043
|
try {
|
|
@@ -38002,9 +38124,50 @@ async function getOAuthTokens() {
|
|
|
38002
38124
|
return null;
|
|
38003
38125
|
}
|
|
38004
38126
|
}
|
|
38005
|
-
|
|
38006
|
-
|
|
38007
|
-
|
|
38127
|
+
function getCurrentApiUrl() {
|
|
38128
|
+
return process.env.WP_API_URL || CONFIG.WP_API_URL;
|
|
38129
|
+
}
|
|
38130
|
+
function getRequestUrl() {
|
|
38131
|
+
return constructApiUrl(getCurrentApiUrl(), WP_MCP_ENDPOINT);
|
|
38132
|
+
}
|
|
38133
|
+
function cloneRequestData(requestData) {
|
|
38134
|
+
return JSON.parse(JSON.stringify(requestData));
|
|
38135
|
+
}
|
|
38136
|
+
function isInitializeRequest(requestData) {
|
|
38137
|
+
return requestData?.method === "initialize";
|
|
38138
|
+
}
|
|
38139
|
+
function cacheInitializeRequest(requestData, useJsonRpc) {
|
|
38140
|
+
lastInitializeRequest = {
|
|
38141
|
+
requestData: cloneRequestData(requestData),
|
|
38142
|
+
useJsonRpc
|
|
38143
|
+
};
|
|
38144
|
+
}
|
|
38145
|
+
function parseApiErrorResponse(error) {
|
|
38146
|
+
if (!error.response) {
|
|
38147
|
+
return null;
|
|
38148
|
+
}
|
|
38149
|
+
if (typeof error.response === "string") {
|
|
38150
|
+
try {
|
|
38151
|
+
return JSON.parse(error.response);
|
|
38152
|
+
} catch {
|
|
38153
|
+
return null;
|
|
38154
|
+
}
|
|
38155
|
+
}
|
|
38156
|
+
return error.response;
|
|
38157
|
+
}
|
|
38158
|
+
function isInvalidSessionError(error) {
|
|
38159
|
+
const errorResponse = parseApiErrorResponse(error);
|
|
38160
|
+
return errorResponse?.code === INVALID_SESSION_ERROR_CODE && errorResponse?.message === INVALID_SESSION_ERROR_MESSAGE;
|
|
38161
|
+
}
|
|
38162
|
+
function updateSessionId(sessionId) {
|
|
38163
|
+
if (globalSessionId === sessionId) {
|
|
38164
|
+
return;
|
|
38165
|
+
}
|
|
38166
|
+
globalSessionId = sessionId;
|
|
38167
|
+
logger.info(`Session ID received from WordPress: ${globalSessionId}`, "SESSION");
|
|
38168
|
+
}
|
|
38169
|
+
async function executeWordPressRequest(requestData, useJsonRpc, sessionIdUsed) {
|
|
38170
|
+
const url = getRequestUrl();
|
|
38008
38171
|
const method = "POST";
|
|
38009
38172
|
if (useJsonRpc) {
|
|
38010
38173
|
logger.api(`Request method: ${requestData.method || "unknown"} (JSON-RPC)`);
|
|
@@ -38063,13 +38226,12 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38063
38226
|
"NO_AUTH_METHOD"
|
|
38064
38227
|
);
|
|
38065
38228
|
}
|
|
38066
|
-
const currentApiUrl = process.env.WP_API_URL || CONFIG.WP_API_URL;
|
|
38067
38229
|
logger.debug(`Environment: ${CONFIG.NODE_ENV}`, "API");
|
|
38068
|
-
logger.debug(`Base API URL: ${
|
|
38069
|
-
const url = constructApiUrl(currentApiUrl, endpoint);
|
|
38230
|
+
logger.debug(`Base API URL: ${getCurrentApiUrl()}`, "API");
|
|
38070
38231
|
logger.debug(`Final requesting URL: ${url}`, "API");
|
|
38071
38232
|
const headers = {
|
|
38072
38233
|
"Content-Type": "application/json",
|
|
38234
|
+
Accept: "application/json, text/event-stream",
|
|
38073
38235
|
"MCP-Protocol-Version": "2025-06-18",
|
|
38074
38236
|
// MCP protocol version
|
|
38075
38237
|
...customHeaders
|
|
@@ -38078,8 +38240,8 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38078
38240
|
if (authHeader) {
|
|
38079
38241
|
headers.Authorization = authHeader;
|
|
38080
38242
|
}
|
|
38081
|
-
if (
|
|
38082
|
-
headers["Mcp-Session-Id"] =
|
|
38243
|
+
if (sessionIdUsed) {
|
|
38244
|
+
headers["Mcp-Session-Id"] = sessionIdUsed;
|
|
38083
38245
|
}
|
|
38084
38246
|
if (authHeader) {
|
|
38085
38247
|
logger.debug("Using Authorization header for authentication", "API");
|
|
@@ -38103,21 +38265,27 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38103
38265
|
logger.debug(`Request method: ${method}`, "API");
|
|
38104
38266
|
const response = await proxyFetch(url, fetchOptions);
|
|
38105
38267
|
logger.debug(`Response status: ${response.status}`, "API");
|
|
38268
|
+
const rawBody = await response.text();
|
|
38106
38269
|
if (!response.ok) {
|
|
38107
|
-
|
|
38108
|
-
logger.error(`API error response: ${errorText}`, "API");
|
|
38270
|
+
logger.error(`API error response: ${rawBody}`, "API");
|
|
38109
38271
|
throw new APIError(
|
|
38110
|
-
`WordPress API error (${response.status}): ${
|
|
38272
|
+
`WordPress API error (${response.status}): ${rawBody}`,
|
|
38111
38273
|
response.status,
|
|
38112
38274
|
url,
|
|
38113
|
-
|
|
38275
|
+
rawBody
|
|
38114
38276
|
);
|
|
38115
38277
|
}
|
|
38116
|
-
const
|
|
38278
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
38279
|
+
let responseData;
|
|
38280
|
+
if (contentType.includes("text/event-stream")) {
|
|
38281
|
+
responseData = parseSSEMessage(rawBody);
|
|
38282
|
+
logger.debug("Parsed text/event-stream response body", "API");
|
|
38283
|
+
} else {
|
|
38284
|
+
responseData = JSON.parse(rawBody);
|
|
38285
|
+
}
|
|
38117
38286
|
const sessionIdHeader = response.headers.get("Mcp-Session-Id");
|
|
38118
|
-
if (sessionIdHeader
|
|
38119
|
-
|
|
38120
|
-
logger.info(`Session ID received from WordPress: ${globalSessionId}`, "SESSION");
|
|
38287
|
+
if (sessionIdHeader) {
|
|
38288
|
+
updateSessionId(sessionIdHeader);
|
|
38121
38289
|
}
|
|
38122
38290
|
logger.api("Response received successfully");
|
|
38123
38291
|
logger.debug(`Response data: ${JSON.stringify(responseData)}`, "API");
|
|
@@ -38130,14 +38298,20 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38130
38298
|
`WordPress JSON-RPC error: ${jsonrpcResponse.error.message}`,
|
|
38131
38299
|
jsonrpcResponse.error.code || 500,
|
|
38132
38300
|
url,
|
|
38133
|
-
|
|
38301
|
+
jsonrpcResponse.error
|
|
38134
38302
|
);
|
|
38135
38303
|
} else if (jsonrpcResponse.result !== void 0) {
|
|
38136
|
-
return
|
|
38304
|
+
return {
|
|
38305
|
+
responseData: jsonrpcResponse.result,
|
|
38306
|
+
sessionIdUsed
|
|
38307
|
+
};
|
|
38137
38308
|
}
|
|
38138
38309
|
}
|
|
38139
38310
|
}
|
|
38140
|
-
return
|
|
38311
|
+
return {
|
|
38312
|
+
responseData,
|
|
38313
|
+
sessionIdUsed
|
|
38314
|
+
};
|
|
38141
38315
|
} catch (error) {
|
|
38142
38316
|
if (error instanceof APIError) {
|
|
38143
38317
|
throw error;
|
|
@@ -38147,6 +38321,77 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38147
38321
|
throw new APIError(errorMessage, 0, url);
|
|
38148
38322
|
}
|
|
38149
38323
|
}
|
|
38324
|
+
async function refreshSession(failedSessionId) {
|
|
38325
|
+
if (failedSessionId && globalSessionId && globalSessionId !== failedSessionId) {
|
|
38326
|
+
logger.info("Detected newer session while handling invalid-session error; skipping refresh", "SESSION");
|
|
38327
|
+
return;
|
|
38328
|
+
}
|
|
38329
|
+
if (sessionRefreshPromise) {
|
|
38330
|
+
logger.info("Waiting for in-flight WordPress session refresh", "SESSION");
|
|
38331
|
+
await sessionRefreshPromise;
|
|
38332
|
+
return;
|
|
38333
|
+
}
|
|
38334
|
+
if (!lastInitializeRequest) {
|
|
38335
|
+
throw new APIError(
|
|
38336
|
+
"Cannot refresh WordPress session before initialize has completed",
|
|
38337
|
+
0,
|
|
38338
|
+
getRequestUrl()
|
|
38339
|
+
);
|
|
38340
|
+
}
|
|
38341
|
+
sessionRefreshPromise = (async () => {
|
|
38342
|
+
logger.warn("WordPress session rejected; refreshing session via initialize", "SESSION");
|
|
38343
|
+
globalSessionId = null;
|
|
38344
|
+
await executeWordPressRequest(
|
|
38345
|
+
lastInitializeRequest.requestData,
|
|
38346
|
+
lastInitializeRequest.useJsonRpc,
|
|
38347
|
+
null
|
|
38348
|
+
);
|
|
38349
|
+
if (!globalSessionId) {
|
|
38350
|
+
throw new APIError(
|
|
38351
|
+
"WordPress initialize did not return a session ID during refresh",
|
|
38352
|
+
0,
|
|
38353
|
+
getRequestUrl()
|
|
38354
|
+
);
|
|
38355
|
+
}
|
|
38356
|
+
})();
|
|
38357
|
+
try {
|
|
38358
|
+
await sessionRefreshPromise;
|
|
38359
|
+
} finally {
|
|
38360
|
+
sessionRefreshPromise = null;
|
|
38361
|
+
}
|
|
38362
|
+
}
|
|
38363
|
+
async function wpRequest(requestData, useJsonRpc = true, options = {}) {
|
|
38364
|
+
validateEnvironment();
|
|
38365
|
+
const allowSessionRecovery = options.allowSessionRecovery !== false;
|
|
38366
|
+
if (isInitializeRequest(requestData)) {
|
|
38367
|
+
cacheInitializeRequest(requestData, useJsonRpc);
|
|
38368
|
+
}
|
|
38369
|
+
const sessionIdUsed = globalSessionId;
|
|
38370
|
+
try {
|
|
38371
|
+
const result = await executeWordPressRequest(requestData, useJsonRpc, sessionIdUsed);
|
|
38372
|
+
return result.responseData;
|
|
38373
|
+
} catch (error) {
|
|
38374
|
+
if (error instanceof APIError && allowSessionRecovery && !isInitializeRequest(requestData) && isInvalidSessionError(error)) {
|
|
38375
|
+
logger.warn("WordPress session expired; attempting one-time recovery", "SESSION", {
|
|
38376
|
+
method: requestData?.method || "unknown",
|
|
38377
|
+
sessionIdUsed: sessionIdUsed || "none"
|
|
38378
|
+
});
|
|
38379
|
+
await refreshSession(sessionIdUsed);
|
|
38380
|
+
const retriedResult = await executeWordPressRequest(
|
|
38381
|
+
requestData,
|
|
38382
|
+
useJsonRpc,
|
|
38383
|
+
globalSessionId
|
|
38384
|
+
);
|
|
38385
|
+
return retriedResult.responseData;
|
|
38386
|
+
}
|
|
38387
|
+
if (error instanceof APIError) {
|
|
38388
|
+
throw error;
|
|
38389
|
+
}
|
|
38390
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
38391
|
+
logger.error(`Error in wpRequest: ${errorMessage}`, "API");
|
|
38392
|
+
throw new APIError(errorMessage, 0, getRequestUrl());
|
|
38393
|
+
}
|
|
38394
|
+
}
|
|
38150
38395
|
export {
|
|
38151
38396
|
APIError,
|
|
38152
38397
|
AuthError,
|
package/dist/proxy.js
CHANGED
|
@@ -92,13 +92,13 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
92
92
|
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, factory(global2.WebStreamsPolyfill = {}));
|
|
93
93
|
})(exports, function(exports2) {
|
|
94
94
|
"use strict";
|
|
95
|
-
function
|
|
95
|
+
function noop3() {
|
|
96
96
|
return void 0;
|
|
97
97
|
}
|
|
98
98
|
function typeIsObject(x2) {
|
|
99
99
|
return typeof x2 === "object" && x2 !== null || typeof x2 === "function";
|
|
100
100
|
}
|
|
101
|
-
const rethrowAssertionErrorRejection =
|
|
101
|
+
const rethrowAssertionErrorRejection = noop3;
|
|
102
102
|
function setFunctionName(fn, name) {
|
|
103
103
|
try {
|
|
104
104
|
Object.defineProperty(fn, "name", {
|
|
@@ -2727,7 +2727,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
2727
2727
|
return newPromise((resolveRead, rejectRead) => {
|
|
2728
2728
|
ReadableStreamDefaultReaderRead(reader, {
|
|
2729
2729
|
_chunkSteps: (chunk) => {
|
|
2730
|
-
currentWrite = PerformPromiseThen(WritableStreamDefaultWriterWrite(writer, chunk), void 0,
|
|
2730
|
+
currentWrite = PerformPromiseThen(WritableStreamDefaultWriterWrite(writer, chunk), void 0, noop3);
|
|
2731
2731
|
resolveRead(false);
|
|
2732
2732
|
},
|
|
2733
2733
|
_closeSteps: () => resolveRead(true),
|
|
@@ -3408,7 +3408,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
3408
3408
|
function ReadableStreamFromIterable(asyncIterable) {
|
|
3409
3409
|
let stream;
|
|
3410
3410
|
const iteratorRecord = GetIterator(asyncIterable, "async");
|
|
3411
|
-
const startAlgorithm =
|
|
3411
|
+
const startAlgorithm = noop3;
|
|
3412
3412
|
function pullAlgorithm() {
|
|
3413
3413
|
let nextResult;
|
|
3414
3414
|
try {
|
|
@@ -3460,7 +3460,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
3460
3460
|
}
|
|
3461
3461
|
function ReadableStreamFromDefaultReader(reader) {
|
|
3462
3462
|
let stream;
|
|
3463
|
-
const startAlgorithm =
|
|
3463
|
+
const startAlgorithm = noop3;
|
|
3464
3464
|
function pullAlgorithm() {
|
|
3465
3465
|
let readPromise;
|
|
3466
3466
|
try {
|
|
@@ -3779,7 +3779,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
3779
3779
|
});
|
|
3780
3780
|
}
|
|
3781
3781
|
const sourceCancelPromise = stream._readableStreamController[CancelSteps](reason);
|
|
3782
|
-
return transformPromiseWith(sourceCancelPromise,
|
|
3782
|
+
return transformPromiseWith(sourceCancelPromise, noop3);
|
|
3783
3783
|
}
|
|
3784
3784
|
function ReadableStreamClose(stream) {
|
|
3785
3785
|
stream._state = "closed";
|
|
@@ -5000,7 +5000,7 @@ async function toFormData(Body2, ct) {
|
|
|
5000
5000
|
parser.end();
|
|
5001
5001
|
return formData;
|
|
5002
5002
|
}
|
|
5003
|
-
var s, S, f2, F, LF, CR, SPACE, HYPHEN, COLON, A, Z, lower,
|
|
5003
|
+
var s, S, f2, F, LF, CR, SPACE, HYPHEN, COLON, A, Z, lower, noop2, MultipartParser;
|
|
5004
5004
|
var init_multipart_parser = __esm({
|
|
5005
5005
|
"node_modules/node-fetch/src/utils/multipart-parser.js"() {
|
|
5006
5006
|
"use strict";
|
|
@@ -5032,7 +5032,7 @@ var init_multipart_parser = __esm({
|
|
|
5032
5032
|
A = 97;
|
|
5033
5033
|
Z = 122;
|
|
5034
5034
|
lower = (c) => c | 32;
|
|
5035
|
-
|
|
5035
|
+
noop2 = () => {
|
|
5036
5036
|
};
|
|
5037
5037
|
MultipartParser = class {
|
|
5038
5038
|
/**
|
|
@@ -5041,13 +5041,13 @@ var init_multipart_parser = __esm({
|
|
|
5041
5041
|
constructor(boundary) {
|
|
5042
5042
|
this.index = 0;
|
|
5043
5043
|
this.flags = 0;
|
|
5044
|
-
this.onHeaderEnd =
|
|
5045
|
-
this.onHeaderField =
|
|
5046
|
-
this.onHeadersEnd =
|
|
5047
|
-
this.onHeaderValue =
|
|
5048
|
-
this.onPartBegin =
|
|
5049
|
-
this.onPartData =
|
|
5050
|
-
this.onPartEnd =
|
|
5044
|
+
this.onHeaderEnd = noop2;
|
|
5045
|
+
this.onHeaderField = noop2;
|
|
5046
|
+
this.onHeadersEnd = noop2;
|
|
5047
|
+
this.onHeaderValue = noop2;
|
|
5048
|
+
this.onPartBegin = noop2;
|
|
5049
|
+
this.onPartData = noop2;
|
|
5050
|
+
this.onPartEnd = noop2;
|
|
5051
5051
|
this.boundaryChars = {};
|
|
5052
5052
|
boundary = "\r\n--" + boundary;
|
|
5053
5053
|
const ui8a = new Uint8Array(boundary.length);
|
|
@@ -7882,7 +7882,7 @@ var require_destroy = __commonJS({
|
|
|
7882
7882
|
}
|
|
7883
7883
|
if (isEventEmitter(stream) && suppress) {
|
|
7884
7884
|
stream.removeAllListeners("error");
|
|
7885
|
-
stream.addListener("error",
|
|
7885
|
+
stream.addListener("error", noop3);
|
|
7886
7886
|
}
|
|
7887
7887
|
return stream;
|
|
7888
7888
|
}
|
|
@@ -7937,7 +7937,7 @@ var require_destroy = __commonJS({
|
|
|
7937
7937
|
function isZlibStream(stream) {
|
|
7938
7938
|
return stream instanceof Zlib.Gzip || stream instanceof Zlib.Gunzip || stream instanceof Zlib.Deflate || stream instanceof Zlib.DeflateRaw || stream instanceof Zlib.Inflate || stream instanceof Zlib.InflateRaw || stream instanceof Zlib.Unzip;
|
|
7939
7939
|
}
|
|
7940
|
-
function
|
|
7940
|
+
function noop3() {
|
|
7941
7941
|
}
|
|
7942
7942
|
function onDrainClearBinding() {
|
|
7943
7943
|
this._binding.clear();
|
|
@@ -35686,6 +35686,109 @@ var StdioServerTransport = class {
|
|
|
35686
35686
|
}
|
|
35687
35687
|
};
|
|
35688
35688
|
|
|
35689
|
+
// node_modules/eventsource-parser/dist/index.js
|
|
35690
|
+
var ParseError = class extends Error {
|
|
35691
|
+
constructor(message, options) {
|
|
35692
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
35693
|
+
}
|
|
35694
|
+
};
|
|
35695
|
+
function noop(_arg) {
|
|
35696
|
+
}
|
|
35697
|
+
function createParser(callbacks) {
|
|
35698
|
+
if (typeof callbacks == "function")
|
|
35699
|
+
throw new TypeError(
|
|
35700
|
+
"`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"
|
|
35701
|
+
);
|
|
35702
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks;
|
|
35703
|
+
let incompleteLine = "", isFirstChunk = true, id, data = "", eventType = "";
|
|
35704
|
+
function feed(newChunk) {
|
|
35705
|
+
const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines(`${incompleteLine}${chunk}`);
|
|
35706
|
+
for (const line of complete)
|
|
35707
|
+
parseLine(line);
|
|
35708
|
+
incompleteLine = incomplete, isFirstChunk = false;
|
|
35709
|
+
}
|
|
35710
|
+
function parseLine(line) {
|
|
35711
|
+
if (line === "") {
|
|
35712
|
+
dispatchEvent();
|
|
35713
|
+
return;
|
|
35714
|
+
}
|
|
35715
|
+
if (line.startsWith(":")) {
|
|
35716
|
+
onComment && onComment(line.slice(line.startsWith(": ") ? 2 : 1));
|
|
35717
|
+
return;
|
|
35718
|
+
}
|
|
35719
|
+
const fieldSeparatorIndex = line.indexOf(":");
|
|
35720
|
+
if (fieldSeparatorIndex !== -1) {
|
|
35721
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
35722
|
+
processField(field, value, line);
|
|
35723
|
+
return;
|
|
35724
|
+
}
|
|
35725
|
+
processField(line, "", line);
|
|
35726
|
+
}
|
|
35727
|
+
function processField(field, value, line) {
|
|
35728
|
+
switch (field) {
|
|
35729
|
+
case "event":
|
|
35730
|
+
eventType = value;
|
|
35731
|
+
break;
|
|
35732
|
+
case "data":
|
|
35733
|
+
data = `${data}${value}
|
|
35734
|
+
`;
|
|
35735
|
+
break;
|
|
35736
|
+
case "id":
|
|
35737
|
+
id = value.includes("\0") ? void 0 : value;
|
|
35738
|
+
break;
|
|
35739
|
+
case "retry":
|
|
35740
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
35741
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
35742
|
+
type: "invalid-retry",
|
|
35743
|
+
value,
|
|
35744
|
+
line
|
|
35745
|
+
})
|
|
35746
|
+
);
|
|
35747
|
+
break;
|
|
35748
|
+
default:
|
|
35749
|
+
onError(
|
|
35750
|
+
new ParseError(
|
|
35751
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
35752
|
+
{ type: "unknown-field", field, value, line }
|
|
35753
|
+
)
|
|
35754
|
+
);
|
|
35755
|
+
break;
|
|
35756
|
+
}
|
|
35757
|
+
}
|
|
35758
|
+
function dispatchEvent() {
|
|
35759
|
+
data.length > 0 && onEvent({
|
|
35760
|
+
id,
|
|
35761
|
+
event: eventType || void 0,
|
|
35762
|
+
// If the data buffer's last character is a U+000A LINE FEED (LF) character,
|
|
35763
|
+
// then remove the last character from the data buffer.
|
|
35764
|
+
data: data.endsWith(`
|
|
35765
|
+
`) ? data.slice(0, -1) : data
|
|
35766
|
+
}), id = void 0, data = "", eventType = "";
|
|
35767
|
+
}
|
|
35768
|
+
function reset(options = {}) {
|
|
35769
|
+
incompleteLine && options.consume && parseLine(incompleteLine), isFirstChunk = true, id = void 0, data = "", eventType = "", incompleteLine = "";
|
|
35770
|
+
}
|
|
35771
|
+
return { feed, reset };
|
|
35772
|
+
}
|
|
35773
|
+
function splitLines(chunk) {
|
|
35774
|
+
const lines = [];
|
|
35775
|
+
let incompleteLine = "", searchIndex = 0;
|
|
35776
|
+
for (; searchIndex < chunk.length; ) {
|
|
35777
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
35778
|
+
`, searchIndex);
|
|
35779
|
+
let lineEnd = -1;
|
|
35780
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = Math.min(crIndex, lfIndex) : crIndex !== -1 ? lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) {
|
|
35781
|
+
incompleteLine = chunk.slice(searchIndex);
|
|
35782
|
+
break;
|
|
35783
|
+
} else {
|
|
35784
|
+
const line = chunk.slice(searchIndex, lineEnd);
|
|
35785
|
+
lines.push(line), searchIndex = lineEnd + 1, chunk[searchIndex - 1] === "\r" && chunk[searchIndex] === `
|
|
35786
|
+
` && searchIndex++;
|
|
35787
|
+
}
|
|
35788
|
+
}
|
|
35789
|
+
return [lines, incompleteLine];
|
|
35790
|
+
}
|
|
35791
|
+
|
|
35689
35792
|
// node_modules/pkce-challenge/dist/index.node.js
|
|
35690
35793
|
var crypto;
|
|
35691
35794
|
crypto = globalThis.crypto?.webcrypto ?? // Node.js [18-16] REPL
|
|
@@ -35775,10 +35878,9 @@ import path from "path";
|
|
|
35775
35878
|
import fs from "fs/promises";
|
|
35776
35879
|
import fsSync from "fs";
|
|
35777
35880
|
import crypto2 from "crypto";
|
|
35778
|
-
var VERSION = MCP_WORDPRESS_REMOTE_VERSION;
|
|
35779
35881
|
function getConfigDir() {
|
|
35780
35882
|
const baseConfigDir = CONFIG.WP_MCP_CONFIG_DIR;
|
|
35781
|
-
return path.join(baseConfigDir, `wordpress-remote-${
|
|
35883
|
+
return path.join(baseConfigDir, `wordpress-remote-${MCP_WORDPRESS_REMOTE_VERSION}`);
|
|
35782
35884
|
}
|
|
35783
35885
|
async function ensureConfigDir() {
|
|
35784
35886
|
try {
|
|
@@ -36000,7 +36102,7 @@ function calculateDefaultPort(serverUrlHash) {
|
|
|
36000
36102
|
}
|
|
36001
36103
|
async function findExistingClientPort(serverUrlHash) {
|
|
36002
36104
|
const clientInfo = await readJsonFile(serverUrlHash, "client_info.json");
|
|
36003
|
-
if (!clientInfo) {
|
|
36105
|
+
if (!clientInfo || !clientInfo.redirect_uris) {
|
|
36004
36106
|
return void 0;
|
|
36005
36107
|
}
|
|
36006
36108
|
const localhostRedirectUri = clientInfo.redirect_uris.map((uri) => {
|
|
@@ -36036,7 +36138,7 @@ async function selectCallbackPort(serverUrl, specifiedPort, _unused) {
|
|
|
36036
36138
|
}
|
|
36037
36139
|
|
|
36038
36140
|
// src/lib/config.ts
|
|
36039
|
-
var MCP_WORDPRESS_REMOTE_VERSION = "0.
|
|
36141
|
+
var MCP_WORDPRESS_REMOTE_VERSION = "0.3.0";
|
|
36040
36142
|
var CONFIG = {
|
|
36041
36143
|
// API Configuration
|
|
36042
36144
|
WP_API_URL: process.env.WP_API_URL || "https://example.com",
|
|
@@ -37514,17 +37616,14 @@ var OAuthCallbackServer = class {
|
|
|
37514
37616
|
});
|
|
37515
37617
|
}
|
|
37516
37618
|
async stop() {
|
|
37517
|
-
|
|
37518
|
-
|
|
37519
|
-
|
|
37520
|
-
|
|
37521
|
-
|
|
37522
|
-
|
|
37523
|
-
});
|
|
37524
|
-
} else {
|
|
37525
|
-
resolve();
|
|
37526
|
-
}
|
|
37619
|
+
if (!this.server) return;
|
|
37620
|
+
const server = this.server;
|
|
37621
|
+
this.server = null;
|
|
37622
|
+
server.close((err) => {
|
|
37623
|
+
if (err) logger.error("OAuth callback server close error", "OAUTH", err);
|
|
37624
|
+
else logger.oauth("OAuth callback server stopped");
|
|
37527
37625
|
});
|
|
37626
|
+
server.closeAllConnections?.();
|
|
37528
37627
|
}
|
|
37529
37628
|
getCallbackUrl() {
|
|
37530
37629
|
return `http://${this.options.host}:${this.options.port}/oauth/callback`;
|
|
@@ -38529,6 +38628,11 @@ var mcpOAuthProvider = null;
|
|
|
38529
38628
|
var authCoordinator = null;
|
|
38530
38629
|
var globalEvents = null;
|
|
38531
38630
|
var globalSessionId = null;
|
|
38631
|
+
var lastInitializeRequest = null;
|
|
38632
|
+
var sessionRefreshPromise = null;
|
|
38633
|
+
var WP_MCP_ENDPOINT = "/wp/v2/wpmcp";
|
|
38634
|
+
var INVALID_SESSION_ERROR_CODE = -32602;
|
|
38635
|
+
var INVALID_SESSION_ERROR_MESSAGE = "Invalid or expired session";
|
|
38532
38636
|
function validateEnvironment() {
|
|
38533
38637
|
const validation = validateConfig();
|
|
38534
38638
|
if (!validation.isValid) {
|
|
@@ -38541,6 +38645,24 @@ function validateEnvironment() {
|
|
|
38541
38645
|
function removeTrailingSlash(url) {
|
|
38542
38646
|
return url.replace(/\/+$/, "");
|
|
38543
38647
|
}
|
|
38648
|
+
function parseSSEMessage(text) {
|
|
38649
|
+
let result;
|
|
38650
|
+
let found = false;
|
|
38651
|
+
const parser = createParser({
|
|
38652
|
+
onEvent(event) {
|
|
38653
|
+
if (found) return;
|
|
38654
|
+
if (!event.event || event.event === "message") {
|
|
38655
|
+
result = JSON.parse(event.data);
|
|
38656
|
+
found = true;
|
|
38657
|
+
}
|
|
38658
|
+
}
|
|
38659
|
+
});
|
|
38660
|
+
parser.feed(text);
|
|
38661
|
+
if (!found) {
|
|
38662
|
+
throw new Error('No "message" event with data found in SSE response');
|
|
38663
|
+
}
|
|
38664
|
+
return result;
|
|
38665
|
+
}
|
|
38544
38666
|
function constructApiUrl(baseUrl, defaultEndpoint) {
|
|
38545
38667
|
const cleanUrl = removeTrailingSlash(baseUrl);
|
|
38546
38668
|
try {
|
|
@@ -38630,9 +38752,50 @@ async function getOAuthTokens() {
|
|
|
38630
38752
|
function getSessionId() {
|
|
38631
38753
|
return globalSessionId;
|
|
38632
38754
|
}
|
|
38633
|
-
|
|
38634
|
-
|
|
38635
|
-
|
|
38755
|
+
function getCurrentApiUrl() {
|
|
38756
|
+
return process.env.WP_API_URL || CONFIG.WP_API_URL;
|
|
38757
|
+
}
|
|
38758
|
+
function getRequestUrl() {
|
|
38759
|
+
return constructApiUrl(getCurrentApiUrl(), WP_MCP_ENDPOINT);
|
|
38760
|
+
}
|
|
38761
|
+
function cloneRequestData(requestData) {
|
|
38762
|
+
return JSON.parse(JSON.stringify(requestData));
|
|
38763
|
+
}
|
|
38764
|
+
function isInitializeRequest(requestData) {
|
|
38765
|
+
return requestData?.method === "initialize";
|
|
38766
|
+
}
|
|
38767
|
+
function cacheInitializeRequest(requestData, useJsonRpc) {
|
|
38768
|
+
lastInitializeRequest = {
|
|
38769
|
+
requestData: cloneRequestData(requestData),
|
|
38770
|
+
useJsonRpc
|
|
38771
|
+
};
|
|
38772
|
+
}
|
|
38773
|
+
function parseApiErrorResponse(error) {
|
|
38774
|
+
if (!error.response) {
|
|
38775
|
+
return null;
|
|
38776
|
+
}
|
|
38777
|
+
if (typeof error.response === "string") {
|
|
38778
|
+
try {
|
|
38779
|
+
return JSON.parse(error.response);
|
|
38780
|
+
} catch {
|
|
38781
|
+
return null;
|
|
38782
|
+
}
|
|
38783
|
+
}
|
|
38784
|
+
return error.response;
|
|
38785
|
+
}
|
|
38786
|
+
function isInvalidSessionError(error) {
|
|
38787
|
+
const errorResponse = parseApiErrorResponse(error);
|
|
38788
|
+
return errorResponse?.code === INVALID_SESSION_ERROR_CODE && errorResponse?.message === INVALID_SESSION_ERROR_MESSAGE;
|
|
38789
|
+
}
|
|
38790
|
+
function updateSessionId(sessionId) {
|
|
38791
|
+
if (globalSessionId === sessionId) {
|
|
38792
|
+
return;
|
|
38793
|
+
}
|
|
38794
|
+
globalSessionId = sessionId;
|
|
38795
|
+
logger.info(`Session ID received from WordPress: ${globalSessionId}`, "SESSION");
|
|
38796
|
+
}
|
|
38797
|
+
async function executeWordPressRequest(requestData, useJsonRpc, sessionIdUsed) {
|
|
38798
|
+
const url = getRequestUrl();
|
|
38636
38799
|
const method = "POST";
|
|
38637
38800
|
if (useJsonRpc) {
|
|
38638
38801
|
logger.api(`Request method: ${requestData.method || "unknown"} (JSON-RPC)`);
|
|
@@ -38691,13 +38854,12 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38691
38854
|
"NO_AUTH_METHOD"
|
|
38692
38855
|
);
|
|
38693
38856
|
}
|
|
38694
|
-
const currentApiUrl = process.env.WP_API_URL || CONFIG.WP_API_URL;
|
|
38695
38857
|
logger.debug(`Environment: ${CONFIG.NODE_ENV}`, "API");
|
|
38696
|
-
logger.debug(`Base API URL: ${
|
|
38697
|
-
const url = constructApiUrl(currentApiUrl, endpoint);
|
|
38858
|
+
logger.debug(`Base API URL: ${getCurrentApiUrl()}`, "API");
|
|
38698
38859
|
logger.debug(`Final requesting URL: ${url}`, "API");
|
|
38699
38860
|
const headers = {
|
|
38700
38861
|
"Content-Type": "application/json",
|
|
38862
|
+
Accept: "application/json, text/event-stream",
|
|
38701
38863
|
"MCP-Protocol-Version": "2025-06-18",
|
|
38702
38864
|
// MCP protocol version
|
|
38703
38865
|
...customHeaders
|
|
@@ -38706,8 +38868,8 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38706
38868
|
if (authHeader) {
|
|
38707
38869
|
headers.Authorization = authHeader;
|
|
38708
38870
|
}
|
|
38709
|
-
if (
|
|
38710
|
-
headers["Mcp-Session-Id"] =
|
|
38871
|
+
if (sessionIdUsed) {
|
|
38872
|
+
headers["Mcp-Session-Id"] = sessionIdUsed;
|
|
38711
38873
|
}
|
|
38712
38874
|
if (authHeader) {
|
|
38713
38875
|
logger.debug("Using Authorization header for authentication", "API");
|
|
@@ -38731,21 +38893,27 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38731
38893
|
logger.debug(`Request method: ${method}`, "API");
|
|
38732
38894
|
const response = await proxyFetch(url, fetchOptions);
|
|
38733
38895
|
logger.debug(`Response status: ${response.status}`, "API");
|
|
38896
|
+
const rawBody = await response.text();
|
|
38734
38897
|
if (!response.ok) {
|
|
38735
|
-
|
|
38736
|
-
logger.error(`API error response: ${errorText}`, "API");
|
|
38898
|
+
logger.error(`API error response: ${rawBody}`, "API");
|
|
38737
38899
|
throw new APIError(
|
|
38738
|
-
`WordPress API error (${response.status}): ${
|
|
38900
|
+
`WordPress API error (${response.status}): ${rawBody}`,
|
|
38739
38901
|
response.status,
|
|
38740
38902
|
url,
|
|
38741
|
-
|
|
38903
|
+
rawBody
|
|
38742
38904
|
);
|
|
38743
38905
|
}
|
|
38744
|
-
const
|
|
38906
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
38907
|
+
let responseData;
|
|
38908
|
+
if (contentType.includes("text/event-stream")) {
|
|
38909
|
+
responseData = parseSSEMessage(rawBody);
|
|
38910
|
+
logger.debug("Parsed text/event-stream response body", "API");
|
|
38911
|
+
} else {
|
|
38912
|
+
responseData = JSON.parse(rawBody);
|
|
38913
|
+
}
|
|
38745
38914
|
const sessionIdHeader = response.headers.get("Mcp-Session-Id");
|
|
38746
|
-
if (sessionIdHeader
|
|
38747
|
-
|
|
38748
|
-
logger.info(`Session ID received from WordPress: ${globalSessionId}`, "SESSION");
|
|
38915
|
+
if (sessionIdHeader) {
|
|
38916
|
+
updateSessionId(sessionIdHeader);
|
|
38749
38917
|
}
|
|
38750
38918
|
logger.api("Response received successfully");
|
|
38751
38919
|
logger.debug(`Response data: ${JSON.stringify(responseData)}`, "API");
|
|
@@ -38758,14 +38926,20 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38758
38926
|
`WordPress JSON-RPC error: ${jsonrpcResponse.error.message}`,
|
|
38759
38927
|
jsonrpcResponse.error.code || 500,
|
|
38760
38928
|
url,
|
|
38761
|
-
|
|
38929
|
+
jsonrpcResponse.error
|
|
38762
38930
|
);
|
|
38763
38931
|
} else if (jsonrpcResponse.result !== void 0) {
|
|
38764
|
-
return
|
|
38932
|
+
return {
|
|
38933
|
+
responseData: jsonrpcResponse.result,
|
|
38934
|
+
sessionIdUsed
|
|
38935
|
+
};
|
|
38765
38936
|
}
|
|
38766
38937
|
}
|
|
38767
38938
|
}
|
|
38768
|
-
return
|
|
38939
|
+
return {
|
|
38940
|
+
responseData,
|
|
38941
|
+
sessionIdUsed
|
|
38942
|
+
};
|
|
38769
38943
|
} catch (error) {
|
|
38770
38944
|
if (error instanceof APIError) {
|
|
38771
38945
|
throw error;
|
|
@@ -38775,6 +38949,77 @@ async function wpRequest(requestData, useJsonRpc = true) {
|
|
|
38775
38949
|
throw new APIError(errorMessage, 0, url);
|
|
38776
38950
|
}
|
|
38777
38951
|
}
|
|
38952
|
+
async function refreshSession(failedSessionId) {
|
|
38953
|
+
if (failedSessionId && globalSessionId && globalSessionId !== failedSessionId) {
|
|
38954
|
+
logger.info("Detected newer session while handling invalid-session error; skipping refresh", "SESSION");
|
|
38955
|
+
return;
|
|
38956
|
+
}
|
|
38957
|
+
if (sessionRefreshPromise) {
|
|
38958
|
+
logger.info("Waiting for in-flight WordPress session refresh", "SESSION");
|
|
38959
|
+
await sessionRefreshPromise;
|
|
38960
|
+
return;
|
|
38961
|
+
}
|
|
38962
|
+
if (!lastInitializeRequest) {
|
|
38963
|
+
throw new APIError(
|
|
38964
|
+
"Cannot refresh WordPress session before initialize has completed",
|
|
38965
|
+
0,
|
|
38966
|
+
getRequestUrl()
|
|
38967
|
+
);
|
|
38968
|
+
}
|
|
38969
|
+
sessionRefreshPromise = (async () => {
|
|
38970
|
+
logger.warn("WordPress session rejected; refreshing session via initialize", "SESSION");
|
|
38971
|
+
globalSessionId = null;
|
|
38972
|
+
await executeWordPressRequest(
|
|
38973
|
+
lastInitializeRequest.requestData,
|
|
38974
|
+
lastInitializeRequest.useJsonRpc,
|
|
38975
|
+
null
|
|
38976
|
+
);
|
|
38977
|
+
if (!globalSessionId) {
|
|
38978
|
+
throw new APIError(
|
|
38979
|
+
"WordPress initialize did not return a session ID during refresh",
|
|
38980
|
+
0,
|
|
38981
|
+
getRequestUrl()
|
|
38982
|
+
);
|
|
38983
|
+
}
|
|
38984
|
+
})();
|
|
38985
|
+
try {
|
|
38986
|
+
await sessionRefreshPromise;
|
|
38987
|
+
} finally {
|
|
38988
|
+
sessionRefreshPromise = null;
|
|
38989
|
+
}
|
|
38990
|
+
}
|
|
38991
|
+
async function wpRequest(requestData, useJsonRpc = true, options = {}) {
|
|
38992
|
+
validateEnvironment();
|
|
38993
|
+
const allowSessionRecovery = options.allowSessionRecovery !== false;
|
|
38994
|
+
if (isInitializeRequest(requestData)) {
|
|
38995
|
+
cacheInitializeRequest(requestData, useJsonRpc);
|
|
38996
|
+
}
|
|
38997
|
+
const sessionIdUsed = globalSessionId;
|
|
38998
|
+
try {
|
|
38999
|
+
const result = await executeWordPressRequest(requestData, useJsonRpc, sessionIdUsed);
|
|
39000
|
+
return result.responseData;
|
|
39001
|
+
} catch (error) {
|
|
39002
|
+
if (error instanceof APIError && allowSessionRecovery && !isInitializeRequest(requestData) && isInvalidSessionError(error)) {
|
|
39003
|
+
logger.warn("WordPress session expired; attempting one-time recovery", "SESSION", {
|
|
39004
|
+
method: requestData?.method || "unknown",
|
|
39005
|
+
sessionIdUsed: sessionIdUsed || "none"
|
|
39006
|
+
});
|
|
39007
|
+
await refreshSession(sessionIdUsed);
|
|
39008
|
+
const retriedResult = await executeWordPressRequest(
|
|
39009
|
+
requestData,
|
|
39010
|
+
useJsonRpc,
|
|
39011
|
+
globalSessionId
|
|
39012
|
+
);
|
|
39013
|
+
return retriedResult.responseData;
|
|
39014
|
+
}
|
|
39015
|
+
if (error instanceof APIError) {
|
|
39016
|
+
throw error;
|
|
39017
|
+
}
|
|
39018
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
39019
|
+
logger.error(`Error in wpRequest: ${errorMessage}`, "API");
|
|
39020
|
+
throw new APIError(errorMessage, 0, getRequestUrl());
|
|
39021
|
+
}
|
|
39022
|
+
}
|
|
38778
39023
|
|
|
38779
39024
|
// src/lib/session-utils.ts
|
|
38780
39025
|
function addSessionInfo(wpRequestParams, mcpRequest, context) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/mcp-wordpress-remote",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP WordPress Remote proxy server",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"bin": {
|
|
37
|
-
"
|
|
37
|
+
"mcp-wordpress-remote": "./dist/proxy.js"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsup",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@modelcontextprotocol/sdk": "^1.8.0",
|
|
62
62
|
"@tootallnate/quickjs-emscripten": "^0.23.0",
|
|
63
|
+
"eventsource-parser": "^3.0.1",
|
|
63
64
|
"express": "^4.18.2",
|
|
64
65
|
"https-proxy-agent": "^7.0.6",
|
|
65
66
|
"node-fetch": "^3.3.2",
|
|
@@ -100,6 +101,7 @@
|
|
|
100
101
|
"splitting": false,
|
|
101
102
|
"noExternal": [
|
|
102
103
|
"@modelcontextprotocol/sdk",
|
|
104
|
+
"eventsource-parser",
|
|
103
105
|
"express",
|
|
104
106
|
"node-fetch",
|
|
105
107
|
"open"
|