@chrischall/tripadvisor-mcp 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +224 -44
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "MCP server for the TripAdvisor Terra API — location search, details, photos, and reviews",
|
|
10
|
-
"version": "0.3.
|
|
10
|
+
"version": "0.3.2"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "TripAdvisor",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "TripAdvisor travel data via the Terra API — search hotels, restaurants, and attractions, with details, photos, and reviews",
|
|
18
|
-
"version": "0.3.
|
|
18
|
+
"version": "0.3.2",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
package/dist/bundle.js
CHANGED
|
@@ -3776,6 +3776,7 @@ var require_fast_uri = __commonJS({
|
|
|
3776
3776
|
return uriTokens.join("");
|
|
3777
3777
|
}
|
|
3778
3778
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3779
|
+
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
3779
3780
|
function getParseError(parsed, matches) {
|
|
3780
3781
|
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3781
3782
|
return 'URI path must start with "/" when authority is present.';
|
|
@@ -3805,6 +3806,11 @@ var require_fast_uri = __commonJS({
|
|
|
3805
3806
|
uri = "//" + uri;
|
|
3806
3807
|
}
|
|
3807
3808
|
}
|
|
3809
|
+
const authorityMatch = uri.match(AUTHORITY_PREFIX);
|
|
3810
|
+
if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
|
|
3811
|
+
parsed.error = "URI authority must not contain a literal backslash.";
|
|
3812
|
+
malformedAuthorityOrPort = true;
|
|
3813
|
+
}
|
|
3808
3814
|
const matches = uri.match(URI_PARSE);
|
|
3809
3815
|
if (matches) {
|
|
3810
3816
|
parsed.scheme = matches[1];
|
|
@@ -7693,6 +7699,7 @@ var require_receiver = __commonJS({
|
|
|
7693
7699
|
this._opcode = 0;
|
|
7694
7700
|
this._totalPayloadLength = 0;
|
|
7695
7701
|
this._messageLength = 0;
|
|
7702
|
+
this._numFragments = 0;
|
|
7696
7703
|
this._fragments = [];
|
|
7697
7704
|
this._errored = false;
|
|
7698
7705
|
this._loop = false;
|
|
@@ -8043,23 +8050,23 @@ var require_receiver = __commonJS({
|
|
|
8043
8050
|
this.controlMessage(data, cb);
|
|
8044
8051
|
return;
|
|
8045
8052
|
}
|
|
8053
|
+
if (this._maxFragments > 0 && ++this._numFragments > this._maxFragments) {
|
|
8054
|
+
const error51 = this.createError(
|
|
8055
|
+
RangeError,
|
|
8056
|
+
"Too many message fragments",
|
|
8057
|
+
false,
|
|
8058
|
+
1008,
|
|
8059
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
8060
|
+
);
|
|
8061
|
+
cb(error51);
|
|
8062
|
+
return;
|
|
8063
|
+
}
|
|
8046
8064
|
if (this._compressed) {
|
|
8047
8065
|
this._state = INFLATING;
|
|
8048
8066
|
this.decompress(data, cb);
|
|
8049
8067
|
return;
|
|
8050
8068
|
}
|
|
8051
8069
|
if (data.length) {
|
|
8052
|
-
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
8053
|
-
const error51 = this.createError(
|
|
8054
|
-
RangeError,
|
|
8055
|
-
"Too many message fragments",
|
|
8056
|
-
false,
|
|
8057
|
-
1008,
|
|
8058
|
-
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
8059
|
-
);
|
|
8060
|
-
cb(error51);
|
|
8061
|
-
return;
|
|
8062
|
-
}
|
|
8063
8070
|
this._messageLength = this._totalPayloadLength;
|
|
8064
8071
|
this._fragments.push(data);
|
|
8065
8072
|
}
|
|
@@ -8089,17 +8096,6 @@ var require_receiver = __commonJS({
|
|
|
8089
8096
|
cb(error51);
|
|
8090
8097
|
return;
|
|
8091
8098
|
}
|
|
8092
|
-
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
8093
|
-
const error51 = this.createError(
|
|
8094
|
-
RangeError,
|
|
8095
|
-
"Too many message fragments",
|
|
8096
|
-
false,
|
|
8097
|
-
1008,
|
|
8098
|
-
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
8099
|
-
);
|
|
8100
|
-
cb(error51);
|
|
8101
|
-
return;
|
|
8102
|
-
}
|
|
8103
8099
|
this._fragments.push(buf);
|
|
8104
8100
|
}
|
|
8105
8101
|
this.dataMessage(cb);
|
|
@@ -8122,6 +8118,7 @@ var require_receiver = __commonJS({
|
|
|
8122
8118
|
this._totalPayloadLength = 0;
|
|
8123
8119
|
this._messageLength = 0;
|
|
8124
8120
|
this._fragmented = 0;
|
|
8121
|
+
this._numFragments = 0;
|
|
8125
8122
|
this._fragments = [];
|
|
8126
8123
|
if (this._opcode === 2) {
|
|
8127
8124
|
let data;
|
|
@@ -9622,8 +9619,8 @@ var require_websocket = __commonJS({
|
|
|
9622
9619
|
autoPong: true,
|
|
9623
9620
|
closeTimeout: CLOSE_TIMEOUT,
|
|
9624
9621
|
protocolVersion: protocolVersions[1],
|
|
9625
|
-
maxBufferedChunks:
|
|
9626
|
-
maxFragments:
|
|
9622
|
+
maxBufferedChunks: 256 * 1024,
|
|
9623
|
+
maxFragments: 16 * 1024,
|
|
9627
9624
|
maxPayload: 100 * 1024 * 1024,
|
|
9628
9625
|
skipUTF8Validation: false,
|
|
9629
9626
|
perMessageDeflate: true,
|
|
@@ -10210,9 +10207,9 @@ var require_websocket_server = __commonJS({
|
|
|
10210
10207
|
* called
|
|
10211
10208
|
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
10212
10209
|
* @param {String} [options.host] The hostname where to bind the server
|
|
10213
|
-
* @param {Number} [options.maxBufferedChunks=
|
|
10210
|
+
* @param {Number} [options.maxBufferedChunks=262144] The maximum number of
|
|
10214
10211
|
* buffered data chunks
|
|
10215
|
-
* @param {Number} [options.maxFragments=
|
|
10212
|
+
* @param {Number} [options.maxFragments=16384] The maximum number of message
|
|
10216
10213
|
* fragments
|
|
10217
10214
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
10218
10215
|
* size
|
|
@@ -10235,8 +10232,8 @@ var require_websocket_server = __commonJS({
|
|
|
10235
10232
|
options = {
|
|
10236
10233
|
allowSynchronousEvents: true,
|
|
10237
10234
|
autoPong: true,
|
|
10238
|
-
maxBufferedChunks:
|
|
10239
|
-
maxFragments:
|
|
10235
|
+
maxBufferedChunks: 256 * 1024,
|
|
10236
|
+
maxFragments: 16 * 1024,
|
|
10240
10237
|
maxPayload: 100 * 1024 * 1024,
|
|
10241
10238
|
skipUTF8Validation: false,
|
|
10242
10239
|
perMessageDeflate: false,
|
|
@@ -34939,7 +34936,7 @@ var pageSchema = {
|
|
|
34939
34936
|
};
|
|
34940
34937
|
|
|
34941
34938
|
// src/version.ts
|
|
34942
|
-
var VERSION = "0.3.
|
|
34939
|
+
var VERSION = "0.3.2";
|
|
34943
34940
|
|
|
34944
34941
|
// src/client.ts
|
|
34945
34942
|
import { dirname, join } from "node:path";
|
|
@@ -35274,7 +35271,8 @@ var KNOWN_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
|
35274
35271
|
"capture_redirect",
|
|
35275
35272
|
"read_indexed_db",
|
|
35276
35273
|
"read_dom",
|
|
35277
|
-
"download"
|
|
35274
|
+
"download",
|
|
35275
|
+
"graphql"
|
|
35278
35276
|
]);
|
|
35279
35277
|
|
|
35280
35278
|
// node_modules/@fetchproxy/protocol/dist/mcp-id.js
|
|
@@ -35577,6 +35575,7 @@ function assertIndexedDbScopesArray(value, label) {
|
|
|
35577
35575
|
}
|
|
35578
35576
|
var DOM_SELECTOR_RE = /^[^-]{1,512}$/;
|
|
35579
35577
|
var DOM_ATTRIBUTE_RE = /^[A-Za-z_:][A-Za-z0-9_:.\-]{0,127}$/;
|
|
35578
|
+
var GRAPHQL_OP_NAME_RE = /^[_A-Za-z][_0-9A-Za-z]{0,127}$/;
|
|
35580
35579
|
function assertDomSelectorsArray(value, label) {
|
|
35581
35580
|
if (!Array.isArray(value)) {
|
|
35582
35581
|
throw new ProtocolError(`${label}: expected array, got ${typeof value}`);
|
|
@@ -35613,6 +35612,37 @@ function assertDomSelectorsArray(value, label) {
|
|
|
35613
35612
|
}
|
|
35614
35613
|
}
|
|
35615
35614
|
}
|
|
35615
|
+
function assertGraphqlOpsArray(value, label) {
|
|
35616
|
+
if (!Array.isArray(value)) {
|
|
35617
|
+
throw new ProtocolError(`${label}: expected array, got ${typeof value}`);
|
|
35618
|
+
}
|
|
35619
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35620
|
+
for (let i = 0; i < value.length; i++) {
|
|
35621
|
+
const entry = value[i];
|
|
35622
|
+
assertObject(entry, `${label}[${i}]`);
|
|
35623
|
+
if (entry.name === void 0) {
|
|
35624
|
+
throw new ProtocolError(`${label}[${i}].name: missing`);
|
|
35625
|
+
}
|
|
35626
|
+
if (entry.operationName === void 0) {
|
|
35627
|
+
throw new ProtocolError(`${label}[${i}].operationName: missing`);
|
|
35628
|
+
}
|
|
35629
|
+
if (typeof entry.name !== "string" || !SCOPE_KEY_RE.test(entry.name)) {
|
|
35630
|
+
throw new ProtocolError(`${label}[${i}].name: invalid ${JSON.stringify(entry.name)}`);
|
|
35631
|
+
}
|
|
35632
|
+
if (typeof entry.operationName !== "string" || !GRAPHQL_OP_NAME_RE.test(entry.operationName)) {
|
|
35633
|
+
throw new ProtocolError(`${label}[${i}].operationName: invalid ${JSON.stringify(entry.operationName)}`);
|
|
35634
|
+
}
|
|
35635
|
+
if (seen.has(entry.name)) {
|
|
35636
|
+
throw new ProtocolError(`${label}: duplicate name ${JSON.stringify(entry.name)}`);
|
|
35637
|
+
}
|
|
35638
|
+
seen.add(entry.name);
|
|
35639
|
+
for (const k of Object.keys(entry)) {
|
|
35640
|
+
if (k !== "name" && k !== "operationName") {
|
|
35641
|
+
throw new ProtocolError(`${label}[${i}]: unexpected field ${JSON.stringify(k)}`);
|
|
35642
|
+
}
|
|
35643
|
+
}
|
|
35644
|
+
}
|
|
35645
|
+
}
|
|
35616
35646
|
function validateFrame(raw) {
|
|
35617
35647
|
assertObject(raw, "frame");
|
|
35618
35648
|
const t = raw.type;
|
|
@@ -35691,6 +35721,9 @@ function validateHello(raw) {
|
|
|
35691
35721
|
if (raw.domSelectors !== void 0) {
|
|
35692
35722
|
assertDomSelectorsArray(raw.domSelectors, "hello.domSelectors");
|
|
35693
35723
|
}
|
|
35724
|
+
if (raw.graphqlOps !== void 0) {
|
|
35725
|
+
assertGraphqlOpsArray(raw.graphqlOps, "hello.graphqlOps");
|
|
35726
|
+
}
|
|
35694
35727
|
assertBase64(raw.identityX25519Pub, "hello.identityX25519Pub");
|
|
35695
35728
|
assertBase64(raw.identityEd25519Pub, "hello.identityEd25519Pub");
|
|
35696
35729
|
assertBase64(raw.sessionNonce, "hello.sessionNonce");
|
|
@@ -35940,6 +35973,28 @@ function validateInnerRequest(raw) {
|
|
|
35940
35973
|
}
|
|
35941
35974
|
return raw;
|
|
35942
35975
|
}
|
|
35976
|
+
if (raw.op === "graphql_query") {
|
|
35977
|
+
assertObject(raw.init, "inner.init");
|
|
35978
|
+
if (raw.init.name === void 0)
|
|
35979
|
+
throw new ProtocolError("inner.init.name: missing");
|
|
35980
|
+
if (raw.init.variables === void 0) {
|
|
35981
|
+
throw new ProtocolError("inner.init.variables: missing");
|
|
35982
|
+
}
|
|
35983
|
+
assertString(raw.init.name, "inner.init.name");
|
|
35984
|
+
if (raw.init.name.length === 0) {
|
|
35985
|
+
throw new ProtocolError("inner.init.name: must be non-empty");
|
|
35986
|
+
}
|
|
35987
|
+
assertObject(raw.init.variables, "inner.init.variables");
|
|
35988
|
+
if (raw.init.tabUrl !== void 0) {
|
|
35989
|
+
assertString(raw.init.tabUrl, "inner.init.tabUrl");
|
|
35990
|
+
}
|
|
35991
|
+
for (const k of Object.keys(raw.init)) {
|
|
35992
|
+
if (k !== "name" && k !== "variables" && k !== "tabUrl") {
|
|
35993
|
+
throw new ProtocolError(`inner.init: unexpected field ${JSON.stringify(k)} on graphql_query`);
|
|
35994
|
+
}
|
|
35995
|
+
}
|
|
35996
|
+
return raw;
|
|
35997
|
+
}
|
|
35943
35998
|
if (raw.op === "download") {
|
|
35944
35999
|
assertObject(raw.init, "inner.init");
|
|
35945
36000
|
if (raw.init.url === void 0) {
|
|
@@ -35965,7 +36020,7 @@ function validateInnerRequest(raw) {
|
|
|
35965
36020
|
}
|
|
35966
36021
|
return raw;
|
|
35967
36022
|
}
|
|
35968
|
-
throw new ProtocolError(`inner.op: must be one of "fetch", "read_cookies", "read_local_storage", "read_session_storage", "capture_request_header", "capture_redirect", "read_indexed_db", "read_dom", "download"; got ${JSON.stringify(raw.op)}`);
|
|
36023
|
+
throw new ProtocolError(`inner.op: must be one of "fetch", "read_cookies", "read_local_storage", "read_session_storage", "capture_request_header", "capture_redirect", "read_indexed_db", "read_dom", "download", "graphql_query"; got ${JSON.stringify(raw.op)}`);
|
|
35969
36024
|
}
|
|
35970
36025
|
function assertNonEmptyKeyArray(value, label) {
|
|
35971
36026
|
if (!Array.isArray(value)) {
|
|
@@ -35996,6 +36051,10 @@ function assertStringMap(value, label) {
|
|
|
35996
36051
|
}
|
|
35997
36052
|
}
|
|
35998
36053
|
}
|
|
36054
|
+
var KNOWN_RESPONSE_OPS = /* @__PURE__ */ new Set([
|
|
36055
|
+
...KNOWN_CAPABILITIES,
|
|
36056
|
+
"graphql_query"
|
|
36057
|
+
]);
|
|
35999
36058
|
function validateInnerResponse(raw) {
|
|
36000
36059
|
assertPositiveInt(raw.id, "inner.id");
|
|
36001
36060
|
if (raw.ok === true) {
|
|
@@ -36057,6 +36116,13 @@ function validateInnerResponse(raw) {
|
|
|
36057
36116
|
assertStringMap(raw.values, "inner.values");
|
|
36058
36117
|
return raw;
|
|
36059
36118
|
}
|
|
36119
|
+
if (op === "graphql_query") {
|
|
36120
|
+
if (raw.data === void 0) {
|
|
36121
|
+
throw new ProtocolError("inner.data: missing on graphql_query response");
|
|
36122
|
+
}
|
|
36123
|
+
assertObject(raw.data, "inner.data");
|
|
36124
|
+
return raw;
|
|
36125
|
+
}
|
|
36060
36126
|
if (op === "download") {
|
|
36061
36127
|
assertObject(raw.value, "inner.value");
|
|
36062
36128
|
assertString(raw.value.path, "inner.value.path");
|
|
@@ -36081,7 +36147,7 @@ function validateInnerResponse(raw) {
|
|
|
36081
36147
|
if (raw.ok === false) {
|
|
36082
36148
|
assertString(raw.error, "inner.error");
|
|
36083
36149
|
if (raw.op !== void 0) {
|
|
36084
|
-
if (typeof raw.op !== "string" || !
|
|
36150
|
+
if (typeof raw.op !== "string" || !KNOWN_RESPONSE_OPS.has(raw.op)) {
|
|
36085
36151
|
throw new ProtocolError(`inner.op: unknown response op ${JSON.stringify(raw.op)}`);
|
|
36086
36152
|
}
|
|
36087
36153
|
}
|
|
@@ -36273,11 +36339,33 @@ async function sealInnerFrame(sessionKey, mcpId, seq, inner) {
|
|
|
36273
36339
|
};
|
|
36274
36340
|
}
|
|
36275
36341
|
async function openEncryptedFrame(sessionKey, frame) {
|
|
36276
|
-
const
|
|
36277
|
-
|
|
36278
|
-
|
|
36279
|
-
|
|
36280
|
-
|
|
36342
|
+
const result = await openEncryptedFrameDetailed(sessionKey, frame);
|
|
36343
|
+
if (result.stage === "ok")
|
|
36344
|
+
return result.inner;
|
|
36345
|
+
throw result.error instanceof Error ? result.error : new Error(String(result.error));
|
|
36346
|
+
}
|
|
36347
|
+
async function openEncryptedFrameDetailed(sessionKey, frame) {
|
|
36348
|
+
let pt;
|
|
36349
|
+
try {
|
|
36350
|
+
const iv = fromB64(frame.iv);
|
|
36351
|
+
const ct = fromB64(frame.ciphertext);
|
|
36352
|
+
pt = await aesGcmOpen(sessionKey, iv, ct);
|
|
36353
|
+
} catch (error51) {
|
|
36354
|
+
return { stage: "decrypt-failed", error: error51 };
|
|
36355
|
+
}
|
|
36356
|
+
let parsed;
|
|
36357
|
+
try {
|
|
36358
|
+
parsed = JSON.parse(dec.decode(pt));
|
|
36359
|
+
} catch (error51) {
|
|
36360
|
+
return { stage: "validation-failed", error: error51, recoveredId: void 0 };
|
|
36361
|
+
}
|
|
36362
|
+
try {
|
|
36363
|
+
const inner = validateInnerFrame(parsed);
|
|
36364
|
+
return { stage: "ok", inner };
|
|
36365
|
+
} catch (error51) {
|
|
36366
|
+
const recoveredId = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && typeof parsed.id === "number" && Number.isInteger(parsed.id) && parsed.id > 0 ? parsed.id : void 0;
|
|
36367
|
+
return { stage: "validation-failed", error: error51, recoveredId };
|
|
36368
|
+
}
|
|
36281
36369
|
}
|
|
36282
36370
|
|
|
36283
36371
|
// node_modules/@fetchproxy/server/dist/election.js
|
|
@@ -36403,6 +36491,12 @@ async function buildServerHello(opts) {
|
|
|
36403
36491
|
...d.attribute !== void 0 ? { attribute: d.attribute } : {}
|
|
36404
36492
|
}));
|
|
36405
36493
|
}
|
|
36494
|
+
if (opts.graphqlOps && opts.graphqlOps.length > 0) {
|
|
36495
|
+
hello.graphqlOps = opts.graphqlOps.map((d) => ({
|
|
36496
|
+
name: d.name,
|
|
36497
|
+
operationName: d.operationName
|
|
36498
|
+
}));
|
|
36499
|
+
}
|
|
36406
36500
|
return hello;
|
|
36407
36501
|
}
|
|
36408
36502
|
|
|
@@ -36493,7 +36587,8 @@ async function startHost(opts) {
|
|
|
36493
36587
|
indexedDbScopes: opts.ownIndexedDbScopes,
|
|
36494
36588
|
localStoragePointers: opts.ownLocalStoragePointers,
|
|
36495
36589
|
sessionStoragePointers: opts.ownSessionStoragePointers,
|
|
36496
|
-
domSelectors: opts.ownDomSelectors
|
|
36590
|
+
domSelectors: opts.ownDomSelectors,
|
|
36591
|
+
graphqlOps: opts.ownGraphqlOps
|
|
36497
36592
|
});
|
|
36498
36593
|
const ownSessionNonce = fromB64(ownHello.sessionNonce);
|
|
36499
36594
|
let extensionWs = null;
|
|
@@ -36730,7 +36825,8 @@ async function startPeer(opts) {
|
|
|
36730
36825
|
indexedDbScopes: opts.indexedDbScopes,
|
|
36731
36826
|
domSelectors: opts.domSelectors,
|
|
36732
36827
|
localStoragePointers: opts.localStoragePointers,
|
|
36733
|
-
sessionStoragePointers: opts.sessionStoragePointers
|
|
36828
|
+
sessionStoragePointers: opts.sessionStoragePointers,
|
|
36829
|
+
graphqlOps: opts.graphqlOps
|
|
36734
36830
|
});
|
|
36735
36831
|
const sessionNonce = fromB64(hello.sessionNonce);
|
|
36736
36832
|
ws.send(JSON.stringify(hello));
|
|
@@ -36774,10 +36870,20 @@ async function startPeer(opts) {
|
|
|
36774
36870
|
return;
|
|
36775
36871
|
if (!session.acceptInboundSeq(frame.seq))
|
|
36776
36872
|
return;
|
|
36777
|
-
|
|
36778
|
-
|
|
36779
|
-
innerListeners.forEach((cb) => cb(inner));
|
|
36780
|
-
}
|
|
36873
|
+
const result = await openEncryptedFrameDetailed(session.sessionKey, frame);
|
|
36874
|
+
if (result.stage === "ok") {
|
|
36875
|
+
innerListeners.forEach((cb) => cb(result.inner));
|
|
36876
|
+
} else if (result.stage === "decrypt-failed") {
|
|
36877
|
+
} else {
|
|
36878
|
+
console.error("[fetchproxy] peer: received a frame that decrypted OK but failed validation:", result.error);
|
|
36879
|
+
if (result.recoveredId !== void 0) {
|
|
36880
|
+
innerListeners.forEach((cb) => cb({
|
|
36881
|
+
type: "response",
|
|
36882
|
+
id: result.recoveredId,
|
|
36883
|
+
ok: false,
|
|
36884
|
+
error: `malformed response failed protocol validation: ${String(result.error)}`
|
|
36885
|
+
}));
|
|
36886
|
+
}
|
|
36781
36887
|
}
|
|
36782
36888
|
}
|
|
36783
36889
|
} catch (e) {
|
|
@@ -37054,6 +37160,10 @@ var FetchproxyServer = class {
|
|
|
37054
37160
|
pendingIdb = /* @__PURE__ */ new Map();
|
|
37055
37161
|
// download awaiters resolve the saved-file metadata (path + size + mime).
|
|
37056
37162
|
pendingDownload = /* @__PURE__ */ new Map();
|
|
37163
|
+
// 1.x+: graphql_query awaiters resolve the GraphQL `data` object. Its
|
|
37164
|
+
// shape is operation-specific, so the awaiter resolves `unknown` and the
|
|
37165
|
+
// caller narrows.
|
|
37166
|
+
pendingGraphql = /* @__PURE__ */ new Map();
|
|
37057
37167
|
mcpId = null;
|
|
37058
37168
|
identity = null;
|
|
37059
37169
|
// 0.5.3+: in-flight role-election / handle-start promise. Set the
|
|
@@ -37141,6 +37251,10 @@ var FetchproxyServer = class {
|
|
|
37141
37251
|
selector: d.selector,
|
|
37142
37252
|
...d.attribute !== void 0 ? { attribute: d.attribute } : {}
|
|
37143
37253
|
})),
|
|
37254
|
+
graphqlOps: (opts.graphqlOps ?? []).map((d) => ({
|
|
37255
|
+
name: d.name,
|
|
37256
|
+
operationName: d.operationName
|
|
37257
|
+
})),
|
|
37144
37258
|
// 0.8.0+: timer + lazy-revive default to ON. Every realty MCP
|
|
37145
37259
|
// adapter was about to set these to the same numbers anyway; the
|
|
37146
37260
|
// back-door is `0` (explicit opt-out) if a caller genuinely wants
|
|
@@ -37262,6 +37376,7 @@ var FetchproxyServer = class {
|
|
|
37262
37376
|
ownLocalStoragePointers: this.opts.localStoragePointers,
|
|
37263
37377
|
ownSessionStoragePointers: this.opts.sessionStoragePointers,
|
|
37264
37378
|
ownDomSelectors: this.opts.domSelectors,
|
|
37379
|
+
ownGraphqlOps: this.opts.graphqlOps,
|
|
37265
37380
|
onPairCode: this.opts.onPairCode
|
|
37266
37381
|
});
|
|
37267
37382
|
this.hostHandle.onOwnInner((inner) => this.onInner(inner));
|
|
@@ -37290,7 +37405,8 @@ var FetchproxyServer = class {
|
|
|
37290
37405
|
indexedDbScopes: this.opts.indexedDbScopes,
|
|
37291
37406
|
localStoragePointers: this.opts.localStoragePointers,
|
|
37292
37407
|
sessionStoragePointers: this.opts.sessionStoragePointers,
|
|
37293
|
-
domSelectors: this.opts.domSelectors
|
|
37408
|
+
domSelectors: this.opts.domSelectors,
|
|
37409
|
+
graphqlOps: this.opts.graphqlOps
|
|
37294
37410
|
});
|
|
37295
37411
|
this.peerHandle.onInner((inner) => this.onInner(inner));
|
|
37296
37412
|
this.peerHandle.onRenegotiate(() => {
|
|
@@ -37496,6 +37612,7 @@ var FetchproxyServer = class {
|
|
|
37496
37612
|
this.pendingRedirect.delete(id);
|
|
37497
37613
|
this.pendingDownload.delete(id);
|
|
37498
37614
|
this.pendingIdb.delete(id);
|
|
37615
|
+
this.pendingGraphql.delete(id);
|
|
37499
37616
|
}
|
|
37500
37617
|
throw err;
|
|
37501
37618
|
}
|
|
@@ -38305,6 +38422,52 @@ var FetchproxyServer = class {
|
|
|
38305
38422
|
await this.sendInnerFrame(inner);
|
|
38306
38423
|
return this._withVerbTimeout(pending, this.pendingStorage, id, origin);
|
|
38307
38424
|
}
|
|
38425
|
+
/**
|
|
38426
|
+
* 1.x+: run a declared GraphQL operation through the page's own Apollo
|
|
38427
|
+
* client (`window.__APOLLO_CLIENT__`) in the signed-in tab's MAIN world.
|
|
38428
|
+
* Requires `'graphql'` in capabilities AND `name` to match a declared
|
|
38429
|
+
* `graphqlOps` entry. The extension resolves `name` → `operationName` →
|
|
38430
|
+
* the live DocumentNode the page already observed, then invokes
|
|
38431
|
+
* `client.query({ query, variables })` — the site's own request path, so
|
|
38432
|
+
* per-request bot telemetry (Akamai etc.) runs automatically.
|
|
38433
|
+
*
|
|
38434
|
+
* Returns the GraphQL `data` object on success (shape is
|
|
38435
|
+
* operation-specific; the caller narrows). Throws a plain `Error` on
|
|
38436
|
+
* developer mistakes (undeclared capability, undeclared name) and a
|
|
38437
|
+
* descriptive `Error` on the `ok:false` bridge path — which includes the
|
|
38438
|
+
* typed "operation not yet observed on this tab" case (open the site's
|
|
38439
|
+
* page and retry).
|
|
38440
|
+
*/
|
|
38441
|
+
async graphqlQuery(opts) {
|
|
38442
|
+
if (!this.opts.capabilities.includes("graphql")) {
|
|
38443
|
+
throw new Error('FetchproxyServer.graphqlQuery(): MCP did not declare "graphql" in capabilities');
|
|
38444
|
+
}
|
|
38445
|
+
if (typeof opts.name !== "string" || opts.name.length === 0) {
|
|
38446
|
+
throw new Error("FetchproxyServer.graphqlQuery: opts.name must be a non-empty string");
|
|
38447
|
+
}
|
|
38448
|
+
const declaredNames = this.opts.graphqlOps.map((d) => d.name);
|
|
38449
|
+
if (!declaredNames.includes(opts.name)) {
|
|
38450
|
+
throw new Error(`FetchproxyServer.graphqlQuery: operation ${JSON.stringify(opts.name)} not in declared graphqlOps [${declaredNames.map((n) => JSON.stringify(n)).join(", ")}]`);
|
|
38451
|
+
}
|
|
38452
|
+
await this.ensureConnected();
|
|
38453
|
+
this.throwIfPendingPair();
|
|
38454
|
+
const id = this.nextRequestId++;
|
|
38455
|
+
const inner = {
|
|
38456
|
+
type: "request",
|
|
38457
|
+
id,
|
|
38458
|
+
op: "graphql_query",
|
|
38459
|
+
init: {
|
|
38460
|
+
name: opts.name,
|
|
38461
|
+
variables: opts.variables,
|
|
38462
|
+
...opts.tabUrl !== void 0 ? { tabUrl: opts.tabUrl } : {}
|
|
38463
|
+
}
|
|
38464
|
+
};
|
|
38465
|
+
const pending = new Promise((resolve, reject) => {
|
|
38466
|
+
this.pendingGraphql.set(id, { resolve, reject });
|
|
38467
|
+
});
|
|
38468
|
+
await this.sendInnerFrame(inner);
|
|
38469
|
+
return this._withVerbTimeout(pending, this.pendingGraphql, id, opts.name);
|
|
38470
|
+
}
|
|
38308
38471
|
assertScopeSubset(requested, declared, label) {
|
|
38309
38472
|
const undeclared = undeclaredKeys(requested, declared);
|
|
38310
38473
|
if (undeclared.length > 0) {
|
|
@@ -38442,6 +38605,20 @@ var FetchproxyServer = class {
|
|
|
38442
38605
|
}
|
|
38443
38606
|
return;
|
|
38444
38607
|
}
|
|
38608
|
+
const graphqlCb = this.pendingGraphql.get(inner.id);
|
|
38609
|
+
if (graphqlCb) {
|
|
38610
|
+
this.pendingGraphql.delete(inner.id);
|
|
38611
|
+
if (inner.ok) {
|
|
38612
|
+
if (inner.op === "graphql_query") {
|
|
38613
|
+
graphqlCb.resolve(inner.data);
|
|
38614
|
+
} else {
|
|
38615
|
+
graphqlCb.reject(new FetchproxyProtocolError(`unexpected ${String(inner.op)} response on graphql_query awaiter`));
|
|
38616
|
+
}
|
|
38617
|
+
} else {
|
|
38618
|
+
graphqlCb.reject(new FetchproxyProtocolError(inner.error));
|
|
38619
|
+
}
|
|
38620
|
+
return;
|
|
38621
|
+
}
|
|
38445
38622
|
const cookiesCb = this.pendingReadCookies.get(inner.id);
|
|
38446
38623
|
if (cookiesCb) {
|
|
38447
38624
|
this.pendingReadCookies.delete(inner.id);
|
|
@@ -38493,6 +38670,9 @@ var FetchproxyServer = class {
|
|
|
38493
38670
|
for (const { reject } of this.pendingDownload.values())
|
|
38494
38671
|
reject(err);
|
|
38495
38672
|
this.pendingDownload.clear();
|
|
38673
|
+
for (const { reject } of this.pendingGraphql.values())
|
|
38674
|
+
reject(err);
|
|
38675
|
+
this.pendingGraphql.clear();
|
|
38496
38676
|
}
|
|
38497
38677
|
/**
|
|
38498
38678
|
* 0.5.2+: read the current pair-pending pair code from whichever handle
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Single source of the server version. release-please bumps the literal below. */
|
|
2
|
-
export const VERSION = '0.3.
|
|
2
|
+
export const VERSION = '0.3.2'; // x-release-please-version
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/tripadvisor-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"mcpName": "io.github.chrischall/tripadvisor-mcp",
|
|
5
5
|
"description": "TripAdvisor Terra API MCP server for Claude — search locations, details, photos, and reviews. Developed and maintained by AI (Claude Code).",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"test:coverage": "vitest run --coverage"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@chrischall/mcp-utils": "^0.
|
|
48
|
-
"@fetchproxy/server": "^1.
|
|
47
|
+
"@chrischall/mcp-utils": "^0.14.0",
|
|
48
|
+
"@fetchproxy/server": "^1.7.0",
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
50
50
|
"dotenv": "^17.4.0",
|
|
51
51
|
"zod": "^4.4.2"
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/tripadvisor-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.2",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/tripadvisor-mcp",
|
|
14
|
-
"version": "0.3.
|
|
14
|
+
"version": "0.3.2",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|