@posthog/mcp 0.21.2 → 0.21.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/feedback.d.ts.map +1 -1
- package/dist/extensions/feedback.js +2 -2
- package/dist/extensions/feedback.mjs +1 -1
- package/dist/extensions/mcp-payloads.d.ts.map +1 -1
- package/dist/extensions/mcp-payloads.js +26 -9
- package/dist/extensions/mcp-payloads.mjs +19 -2
- package/dist/extensions/truncation.d.ts +1 -0
- package/dist/extensions/truncation.d.ts.map +1 -1
- package/dist/extensions/truncation.js +4 -1
- package/dist/extensions/truncation.mjs +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +2 -2
- package/src/extensions/feedback.ts +1 -1
- package/src/extensions/mcp-payloads.ts +44 -2
- package/src/extensions/truncation.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../src/extensions/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAEtB,cAAc,EAGd,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,EACX,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../src/extensions/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAEtB,cAAc,EAGd,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,EACX,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAI7C,eAAO,MAAM,uBAAuB,EAAG,eAAwB,CAAA;AAqF/D,KAAK,sBAAsB,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;AAEtE,4FAA4F;AAC5F,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,qBAAqB,GAAG,SAAS,GACxC,sBAAsB,GAAG,SAAS,CAKpC;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,sBAA2B,GAAG,sBAAsB,CA6CtG;AAkCD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACzC,OAAO,GAAE,sBAA2B,GACnC,cAAc,CAoBhB;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAElE;AAuCD,uFAAuF;AACvF,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,cAAc,GAAG,UAAU,CAqC/E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,wBAAwB,CAS7D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,sBAA2B,EACpC,MAAM,GAAE,QAAc,GACrB,OAAO,CAAC,wBAAwB,CAAC,CAiBnC"}
|
|
@@ -40,6 +40,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
40
40
|
const external_constants_js_namespaceObject = require("./constants.js");
|
|
41
41
|
const external_logger_js_namespaceObject = require("./logger.js");
|
|
42
42
|
const external_mcp_payloads_js_namespaceObject = require("./mcp-payloads.js");
|
|
43
|
+
const external_truncation_js_namespaceObject = require("./truncation.js");
|
|
43
44
|
const SEND_FEEDBACK_TOOL_NAME = 'send_feedback';
|
|
44
45
|
const FEEDBACK_TYPES = [
|
|
45
46
|
'missing_capability',
|
|
@@ -55,7 +56,6 @@ const SENTIMENTS = [
|
|
|
55
56
|
];
|
|
56
57
|
const MAX_FEEDBACK_TEXT_LENGTH = 2048;
|
|
57
58
|
const MAX_FEEDBACK_TOOL_NAME_LENGTH = 256;
|
|
58
|
-
const TRUNCATION_SUFFIX = '...';
|
|
59
59
|
const DEFAULT_FEEDBACK_DESCRIPTION = 'Send feedback about this server to its developers. Most important: report a missing capability whenever no available tool fits your task, even if you can work around it (feedback_type "missing_capability"). Also welcome: a tool that failed or confused you, an unhelpful error, or something that worked well. This records the feedback; it does not add or change tools. Do not include user PII or sensitive content.';
|
|
60
60
|
const CORE_FEEDBACK_SCHEMA_PROPERTIES = {
|
|
61
61
|
feedback_type: {
|
|
@@ -179,7 +179,7 @@ function buildFeedbackIntent(report) {
|
|
|
179
179
|
].filter(Boolean).join('\n\n');
|
|
180
180
|
}
|
|
181
181
|
function truncateFeedbackText(value, maxLength) {
|
|
182
|
-
return value.length > maxLength ? value.slice(0, maxLength) + TRUNCATION_SUFFIX : value;
|
|
182
|
+
return value.length > maxLength ? value.slice(0, maxLength) + external_truncation_js_namespaceObject.TRUNCATION_SUFFIX : value;
|
|
183
183
|
}
|
|
184
184
|
function captureFreeText(value) {
|
|
185
185
|
return truncateFeedbackText((0, external_mcp_payloads_js_namespaceObject.sanitizeFreeText)(value), MAX_FEEDBACK_TEXT_LENGTH);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PostHogMCPAnalyticsProperty } from "./constants.mjs";
|
|
2
2
|
import { log } from "./logger.mjs";
|
|
3
3
|
import { sanitizeFreeText, sanitizeFreeTextValue } from "./mcp-payloads.mjs";
|
|
4
|
+
import { TRUNCATION_SUFFIX } from "./truncation.mjs";
|
|
4
5
|
const SEND_FEEDBACK_TOOL_NAME = 'send_feedback';
|
|
5
6
|
const FEEDBACK_TYPES = [
|
|
6
7
|
'missing_capability',
|
|
@@ -16,7 +17,6 @@ const SENTIMENTS = [
|
|
|
16
17
|
];
|
|
17
18
|
const MAX_FEEDBACK_TEXT_LENGTH = 2048;
|
|
18
19
|
const MAX_FEEDBACK_TOOL_NAME_LENGTH = 256;
|
|
19
|
-
const TRUNCATION_SUFFIX = '...';
|
|
20
20
|
const DEFAULT_FEEDBACK_DESCRIPTION = 'Send feedback about this server to its developers. Most important: report a missing capability whenever no available tool fits your task, even if you can work around it (feedback_type "missing_capability"). Also welcome: a tool that failed or confused you, an unhelpful error, or something that worked well. This records the feedback; it does not add or change tools. Do not include user PII or sensitive content.';
|
|
21
21
|
const CORE_FEEDBACK_SCHEMA_PROPERTIES = {
|
|
22
22
|
feedback_type: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-payloads.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-payloads.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-payloads.d.ts","sourceRoot":"","sources":["../../src/extensions/mcp-payloads.ts"],"names":[],"mappings":"AA4HA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AA2azC;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKtD;AA6DD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AAyDD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAiBvE"}
|
|
@@ -27,6 +27,14 @@ var __webpack_require__ = {};
|
|
|
27
27
|
})();
|
|
28
28
|
var __webpack_exports__ = {};
|
|
29
29
|
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
31
|
+
buildCapturedMcpParameters: ()=>buildCapturedMcpParameters,
|
|
32
|
+
redactPii: ()=>redactPii,
|
|
33
|
+
sanitizeCapturedValue: ()=>sanitizeCapturedValue,
|
|
34
|
+
sanitizeFreeText: ()=>sanitizeFreeText,
|
|
35
|
+
sanitizeFreeTextValue: ()=>sanitizeFreeTextValue
|
|
36
|
+
});
|
|
37
|
+
const external_truncation_js_namespaceObject = require("./truncation.js");
|
|
30
38
|
const CONTEXT_ARGUMENT_NAME = 'context';
|
|
31
39
|
const REDACTED_VALUE = '[redacted]';
|
|
32
40
|
const BINARY_REDACTED_VALUE = '[binary data redacted - not supported by PostHog MCP analytics]';
|
|
@@ -36,9 +44,12 @@ const BASE64URL_SPECIFIC_CHAR_PATTERN = /[-_]/;
|
|
|
36
44
|
const BASE64_DATA_URL_PREFIX_PATTERN = /^data:[^,\s]*;base64,/i;
|
|
37
45
|
const BASE64_DATA_URL_PAYLOAD_PATTERN = /^[A-Za-z0-9+/_-]+={0,2}$/;
|
|
38
46
|
const SIZE_GATE = 10240;
|
|
47
|
+
const SCANNED_HEAD_LENGTH = 4 * external_truncation_js_namespaceObject.MAX_STRING_LENGTH;
|
|
48
|
+
const MIN_REDACTED_HEAD_LENGTH = 2 * external_truncation_js_namespaceObject.MAX_STRING_LENGTH;
|
|
39
49
|
const POSTHOG_TOKEN_PATTERN = /\bph[a-z]_[A-Za-z0-9_-]{20,}\b/g;
|
|
40
50
|
const SENSITIVE_KEY_PATTERN = /^(authorization|cookie|set-cookie|x-api-key|api[-_]?key|api[-_]?token|access[-_]?token|refresh[-_]?token|token|password|secret|client[-_]?secret|private[-_]?key)$/i;
|
|
41
51
|
const URL_PATTERN = /[a-z][a-z0-9+.-]{0,63}:[^\s<>"]+/gi;
|
|
52
|
+
const URL_END_PATTERN = /[\s<>"]/;
|
|
42
53
|
const URL_PATTERN_ONCE = new RegExp(URL_PATTERN.source, 'i');
|
|
43
54
|
const URL_AUTHORITY_SEARCH = /[a-z][a-z0-9+.-]{0,63}:\/\//i;
|
|
44
55
|
const URL_AUTHORITY_PATTERN = new RegExp(`^${URL_AUTHORITY_SEARCH.source}`, 'i');
|
|
@@ -156,6 +167,7 @@ function sanitizeFragmentText(text, allowNestedUrls) {
|
|
|
156
167
|
});
|
|
157
168
|
}
|
|
158
169
|
function findEmbeddedAuthorityIndexes(value) {
|
|
170
|
+
if (!value.includes('://')) return [];
|
|
159
171
|
const starts = [
|
|
160
172
|
...value.matchAll(URL_AUTHORITY_SEARCH_ALL)
|
|
161
173
|
].map((match)=>match.index);
|
|
@@ -259,12 +271,24 @@ function redactUrls(value) {
|
|
|
259
271
|
stripPunctuation: true
|
|
260
272
|
});
|
|
261
273
|
}
|
|
274
|
+
function redactCapturedHead(value, redact) {
|
|
275
|
+
if (value.length > SCANNED_HEAD_LENGTH) {
|
|
276
|
+
const head = redact(value.slice(0, headLength(value)));
|
|
277
|
+
if (head.length >= MIN_REDACTED_HEAD_LENGTH) return head + external_truncation_js_namespaceObject.TRUNCATION_SUFFIX;
|
|
278
|
+
}
|
|
279
|
+
return redact(value);
|
|
280
|
+
}
|
|
281
|
+
function headLength(value) {
|
|
282
|
+
let end = SCANNED_HEAD_LENGTH;
|
|
283
|
+
while(end > 0 && !URL_END_PATTERN.test(value[end - 1]))end--;
|
|
284
|
+
return end;
|
|
285
|
+
}
|
|
262
286
|
function sanitizeString(value) {
|
|
263
|
-
return isBinaryBlob(value) ? BINARY_REDACTED_VALUE : redactUrls(redactCredentials(
|
|
287
|
+
return isBinaryBlob(value) ? BINARY_REDACTED_VALUE : redactCapturedHead(value, (head)=>redactUrls(redactCredentials(head)));
|
|
264
288
|
}
|
|
265
289
|
function sanitizeFreeText(value) {
|
|
266
290
|
if (isBinaryBlob(value)) return BINARY_REDACTED_VALUE;
|
|
267
|
-
return redactUrls(redactPii(redactCredentials(
|
|
291
|
+
return redactCapturedHead(value, (head)=>redactUrls(redactPii(redactCredentials(head))));
|
|
268
292
|
}
|
|
269
293
|
function passesLuhn(digits) {
|
|
270
294
|
let sum = 0;
|
|
@@ -361,13 +385,6 @@ function buildCapturedMcpParameters(request) {
|
|
|
361
385
|
request: capturedRequest
|
|
362
386
|
};
|
|
363
387
|
}
|
|
364
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
365
|
-
buildCapturedMcpParameters: ()=>buildCapturedMcpParameters,
|
|
366
|
-
redactPii: ()=>redactPii,
|
|
367
|
-
sanitizeCapturedValue: ()=>sanitizeCapturedValue,
|
|
368
|
-
sanitizeFreeText: ()=>sanitizeFreeText,
|
|
369
|
-
sanitizeFreeTextValue: ()=>sanitizeFreeTextValue
|
|
370
|
-
});
|
|
371
388
|
exports.buildCapturedMcpParameters = __webpack_exports__.buildCapturedMcpParameters;
|
|
372
389
|
exports.redactPii = __webpack_exports__.redactPii;
|
|
373
390
|
exports.sanitizeCapturedValue = __webpack_exports__.sanitizeCapturedValue;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MAX_STRING_LENGTH, TRUNCATION_SUFFIX } from "./truncation.mjs";
|
|
1
2
|
const CONTEXT_ARGUMENT_NAME = 'context';
|
|
2
3
|
const REDACTED_VALUE = '[redacted]';
|
|
3
4
|
const BINARY_REDACTED_VALUE = '[binary data redacted - not supported by PostHog MCP analytics]';
|
|
@@ -7,9 +8,12 @@ const BASE64URL_SPECIFIC_CHAR_PATTERN = /[-_]/;
|
|
|
7
8
|
const BASE64_DATA_URL_PREFIX_PATTERN = /^data:[^,\s]*;base64,/i;
|
|
8
9
|
const BASE64_DATA_URL_PAYLOAD_PATTERN = /^[A-Za-z0-9+/_-]+={0,2}$/;
|
|
9
10
|
const SIZE_GATE = 10240;
|
|
11
|
+
const SCANNED_HEAD_LENGTH = 4 * MAX_STRING_LENGTH;
|
|
12
|
+
const MIN_REDACTED_HEAD_LENGTH = 2 * MAX_STRING_LENGTH;
|
|
10
13
|
const POSTHOG_TOKEN_PATTERN = /\bph[a-z]_[A-Za-z0-9_-]{20,}\b/g;
|
|
11
14
|
const SENSITIVE_KEY_PATTERN = /^(authorization|cookie|set-cookie|x-api-key|api[-_]?key|api[-_]?token|access[-_]?token|refresh[-_]?token|token|password|secret|client[-_]?secret|private[-_]?key)$/i;
|
|
12
15
|
const URL_PATTERN = /[a-z][a-z0-9+.-]{0,63}:[^\s<>"]+/gi;
|
|
16
|
+
const URL_END_PATTERN = /[\s<>"]/;
|
|
13
17
|
const URL_PATTERN_ONCE = new RegExp(URL_PATTERN.source, 'i');
|
|
14
18
|
const URL_AUTHORITY_SEARCH = /[a-z][a-z0-9+.-]{0,63}:\/\//i;
|
|
15
19
|
const URL_AUTHORITY_PATTERN = new RegExp(`^${URL_AUTHORITY_SEARCH.source}`, 'i');
|
|
@@ -127,6 +131,7 @@ function sanitizeFragmentText(text, allowNestedUrls) {
|
|
|
127
131
|
});
|
|
128
132
|
}
|
|
129
133
|
function findEmbeddedAuthorityIndexes(value) {
|
|
134
|
+
if (!value.includes('://')) return [];
|
|
130
135
|
const starts = [
|
|
131
136
|
...value.matchAll(URL_AUTHORITY_SEARCH_ALL)
|
|
132
137
|
].map((match)=>match.index);
|
|
@@ -230,12 +235,24 @@ function redactUrls(value) {
|
|
|
230
235
|
stripPunctuation: true
|
|
231
236
|
});
|
|
232
237
|
}
|
|
238
|
+
function redactCapturedHead(value, redact) {
|
|
239
|
+
if (value.length > SCANNED_HEAD_LENGTH) {
|
|
240
|
+
const head = redact(value.slice(0, headLength(value)));
|
|
241
|
+
if (head.length >= MIN_REDACTED_HEAD_LENGTH) return head + TRUNCATION_SUFFIX;
|
|
242
|
+
}
|
|
243
|
+
return redact(value);
|
|
244
|
+
}
|
|
245
|
+
function headLength(value) {
|
|
246
|
+
let end = SCANNED_HEAD_LENGTH;
|
|
247
|
+
while(end > 0 && !URL_END_PATTERN.test(value[end - 1]))end--;
|
|
248
|
+
return end;
|
|
249
|
+
}
|
|
233
250
|
function sanitizeString(value) {
|
|
234
|
-
return isBinaryBlob(value) ? BINARY_REDACTED_VALUE : redactUrls(redactCredentials(
|
|
251
|
+
return isBinaryBlob(value) ? BINARY_REDACTED_VALUE : redactCapturedHead(value, (head)=>redactUrls(redactCredentials(head)));
|
|
235
252
|
}
|
|
236
253
|
function sanitizeFreeText(value) {
|
|
237
254
|
if (isBinaryBlob(value)) return BINARY_REDACTED_VALUE;
|
|
238
|
-
return redactUrls(redactPii(redactCredentials(
|
|
255
|
+
return redactCapturedHead(value, (head)=>redactUrls(redactPii(redactCredentials(head))));
|
|
239
256
|
}
|
|
240
257
|
function passesLuhn(digits) {
|
|
241
258
|
let sum = 0;
|
|
@@ -3,6 +3,7 @@ export declare const MAX_DEPTH = 10;
|
|
|
3
3
|
export declare const MAX_BREADTH = 100;
|
|
4
4
|
export declare const MAX_STRING_LENGTH = 32768;
|
|
5
5
|
export declare const MAX_EVENT_BYTES = 102400;
|
|
6
|
+
export declare const TRUNCATION_SUFFIX = "...";
|
|
6
7
|
/**
|
|
7
8
|
* Recursively normalizes a value, handling:
|
|
8
9
|
* - String truncation (> MAX_STRING_LENGTH)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"truncation.d.ts","sourceRoot":"","sources":["../../src/extensions/truncation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAmB,KAAK,EAAc,QAAQ,EAAE,MAAM,UAAU,CAAA;AAG5E,eAAO,MAAM,SAAS,KAAK,CAAA;AAC3B,eAAO,MAAM,WAAW,MAAM,CAAA;AAC9B,eAAO,MAAM,iBAAiB,QAAS,CAAA;AACvC,eAAO,MAAM,eAAe,SAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"truncation.d.ts","sourceRoot":"","sources":["../../src/extensions/truncation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAmB,KAAK,EAAc,QAAQ,EAAE,MAAM,UAAU,CAAA;AAG5E,eAAO,MAAM,SAAS,KAAK,CAAA;AAC3B,eAAO,MAAM,WAAW,MAAM,CAAA;AAC9B,eAAO,MAAM,iBAAiB,QAAS,CAAA;AACvC,eAAO,MAAM,eAAe,SAAU,CAAA;AAWtC,eAAO,MAAM,iBAAiB,QAAQ,CAAA;AAKtC;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,OAAO,EACd,KAAK,GAAE,MAAkB,EACzB,UAAU,GAAE,MAAoB,EAChC,eAAe,GAAE,MAA0B,GAC1C,OAAO,CAGT;AAqXD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,KAAK,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CA2CrE"}
|
|
@@ -266,12 +266,14 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
266
266
|
MAX_BREADTH: MAX_BREADTH,
|
|
267
267
|
MAX_DEPTH: MAX_DEPTH,
|
|
268
268
|
MAX_EVENT_BYTES: MAX_EVENT_BYTES,
|
|
269
|
-
MAX_STRING_LENGTH: MAX_STRING_LENGTH
|
|
269
|
+
MAX_STRING_LENGTH: MAX_STRING_LENGTH,
|
|
270
|
+
TRUNCATION_SUFFIX: TRUNCATION_SUFFIX
|
|
270
271
|
});
|
|
271
272
|
exports.MAX_BREADTH = __webpack_exports__.MAX_BREADTH;
|
|
272
273
|
exports.MAX_DEPTH = __webpack_exports__.MAX_DEPTH;
|
|
273
274
|
exports.MAX_EVENT_BYTES = __webpack_exports__.MAX_EVENT_BYTES;
|
|
274
275
|
exports.MAX_STRING_LENGTH = __webpack_exports__.MAX_STRING_LENGTH;
|
|
276
|
+
exports.TRUNCATION_SUFFIX = __webpack_exports__.TRUNCATION_SUFFIX;
|
|
275
277
|
exports.normalize = __webpack_exports__.normalize;
|
|
276
278
|
exports.truncateEvent = __webpack_exports__.truncateEvent;
|
|
277
279
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
@@ -279,6 +281,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
279
281
|
"MAX_DEPTH",
|
|
280
282
|
"MAX_EVENT_BYTES",
|
|
281
283
|
"MAX_STRING_LENGTH",
|
|
284
|
+
"TRUNCATION_SUFFIX",
|
|
282
285
|
"normalize",
|
|
283
286
|
"truncateEvent"
|
|
284
287
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
@@ -230,4 +230,4 @@ function truncateEvent(event) {
|
|
|
230
230
|
if (null != result.error) result.error = normalize(result.error);
|
|
231
231
|
return truncateToSize(result);
|
|
232
232
|
}
|
|
233
|
-
export { MAX_BREADTH, MAX_DEPTH, MAX_EVENT_BYTES, MAX_STRING_LENGTH, normalize, truncateEvent };
|
|
233
|
+
export { MAX_BREADTH, MAX_DEPTH, MAX_EVENT_BYTES, MAX_STRING_LENGTH, TRUNCATION_SUFFIX, normalize, truncateEvent };
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "0.21.
|
|
1
|
+
export declare const version = "0.21.3";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/dist/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const version = "0.21.
|
|
1
|
+
const version = "0.21.3";
|
|
2
2
|
export { version };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/mcp",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.3",
|
|
4
4
|
"bugs": {
|
|
5
5
|
"url": "https://github.com/PostHog/posthog-js/issues"
|
|
6
6
|
},
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"module": "dist/index.mjs",
|
|
29
29
|
"types": "dist/index.d.ts",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@posthog/core": "^1.55.
|
|
31
|
+
"@posthog/core": "^1.55.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@babel/preset-env": "^7.27.1",
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
import { PostHogMCPAnalyticsProperty } from './constants'
|
|
13
13
|
import { log, type LoggerFn } from './logger'
|
|
14
14
|
import { sanitizeFreeText, sanitizeFreeTextValue } from './mcp-payloads'
|
|
15
|
+
import { TRUNCATION_SUFFIX } from './truncation'
|
|
15
16
|
|
|
16
17
|
export const SEND_FEEDBACK_TOOL_NAME = 'send_feedback' as const
|
|
17
18
|
|
|
@@ -21,7 +22,6 @@ const SENTIMENTS: readonly FeedbackSentiment[] = ['positive', 'neutral', 'negati
|
|
|
21
22
|
// Free-text fields are agent-narrated, like `$mcp_intent`; bound them the same way.
|
|
22
23
|
const MAX_FEEDBACK_TEXT_LENGTH = 2048
|
|
23
24
|
const MAX_FEEDBACK_TOOL_NAME_LENGTH = 256
|
|
24
|
-
const TRUNCATION_SUFFIX = '...'
|
|
25
25
|
|
|
26
26
|
const DEFAULT_FEEDBACK_DESCRIPTION =
|
|
27
27
|
'Send feedback about this server to its developers. Most important: report a missing capability whenever no ' +
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
// Copyright (c) 2025 AgentCat, Inc. (formerly MCPcat)
|
|
4
4
|
// Licensed under the MIT License: https://github.com/agentcathq/agentcat-typescript-sdk/blob/main/LICENSE
|
|
5
5
|
|
|
6
|
+
import { MAX_STRING_LENGTH, TRUNCATION_SUFFIX } from './truncation'
|
|
7
|
+
|
|
6
8
|
const CONTEXT_ARGUMENT_NAME = 'context'
|
|
7
9
|
const REDACTED_VALUE = '[redacted]'
|
|
8
10
|
const BINARY_REDACTED_VALUE = '[binary data redacted - not supported by PostHog MCP analytics]'
|
|
@@ -12,6 +14,10 @@ const BASE64URL_SPECIFIC_CHAR_PATTERN = /[-_]/
|
|
|
12
14
|
const BASE64_DATA_URL_PREFIX_PATTERN = /^data:[^,\s]*;base64,/i
|
|
13
15
|
const BASE64_DATA_URL_PAYLOAD_PATTERN = /^[A-Za-z0-9+/_-]+={0,2}$/
|
|
14
16
|
const SIZE_GATE = 10_240
|
|
17
|
+
const SCANNED_HEAD_LENGTH = 4 * MAX_STRING_LENGTH
|
|
18
|
+
// Twice what truncation keeps, so a match split where the head was cut sits past
|
|
19
|
+
// the part truncation keeps.
|
|
20
|
+
const MIN_REDACTED_HEAD_LENGTH = 2 * MAX_STRING_LENGTH
|
|
15
21
|
const POSTHOG_TOKEN_PATTERN = /\bph[a-z]_[A-Za-z0-9_-]{20,}\b/g
|
|
16
22
|
const SENSITIVE_KEY_PATTERN =
|
|
17
23
|
/^(authorization|cookie|set-cookie|x-api-key|api[-_]?key|api[-_]?token|access[-_]?token|refresh[-_]?token|token|password|secret|client[-_]?secret|private[-_]?key)$/i
|
|
@@ -33,6 +39,8 @@ const SENSITIVE_KEY_PATTERN =
|
|
|
33
39
|
// harmless: a match with nothing to redact is returned byte-for-byte, so the
|
|
34
40
|
// text around it is never rewritten.
|
|
35
41
|
const URL_PATTERN = /[a-z][a-z0-9+.-]{0,63}:[^\s<>"]+/gi
|
|
42
|
+
// A character no URL match can contain, so a cut just after one splits no URL.
|
|
43
|
+
const URL_END_PATTERN = /[\s<>"]/
|
|
36
44
|
/** The same pattern without `g`, for asking whether a value holds a URL at all. */
|
|
37
45
|
const URL_PATTERN_ONCE = new RegExp(URL_PATTERN.source, 'i')
|
|
38
46
|
/** Finds the first scheme that brings a real authority, i.e. what the pattern required before it went authority-less. */
|
|
@@ -315,6 +323,11 @@ function sanitizeFragmentText(text: string, allowNestedUrls: boolean): string {
|
|
|
315
323
|
* addresses together, because every one of them scanned back to the same `?`.
|
|
316
324
|
*/
|
|
317
325
|
function findEmbeddedAuthorityIndexes(value: string): number[] {
|
|
326
|
+
// The search tries up to 64 scheme characters at every position, which a long
|
|
327
|
+
// base64 `data:` URI turns into seconds; without `://` it cannot match at all.
|
|
328
|
+
if (!value.includes('://')) {
|
|
329
|
+
return []
|
|
330
|
+
}
|
|
318
331
|
const starts = [...value.matchAll(URL_AUTHORITY_SEARCH_ALL)].map((match) => match.index)
|
|
319
332
|
const indexes: number[] = []
|
|
320
333
|
const delimiters = { query: false, fragment: false, fragmentQuery: false }
|
|
@@ -503,8 +516,37 @@ function redactUrls(value: string): string {
|
|
|
503
516
|
return sanitizeUrlsInString(value, { allowNestedUrls: true, stripPunctuation: true })
|
|
504
517
|
}
|
|
505
518
|
|
|
519
|
+
/**
|
|
520
|
+
* Runs `redact` over only the head of `value` that truncation can keep, so a
|
|
521
|
+
* multi-megabyte tool result costs about the same as the part captured. The head
|
|
522
|
+
* ends where no URL crosses it, because a URL is redacted or kept on the whole
|
|
523
|
+
* address. Redaction shrinks text, so a head that ends up too short to cover
|
|
524
|
+
* truncation's cut falls back to the whole string. Either way the kept part
|
|
525
|
+
* reads exactly as if the whole string were redacted.
|
|
526
|
+
*/
|
|
527
|
+
function redactCapturedHead(value: string, redact: (value: string) => string): string {
|
|
528
|
+
if (value.length > SCANNED_HEAD_LENGTH) {
|
|
529
|
+
const head = redact(value.slice(0, headLength(value)))
|
|
530
|
+
if (head.length >= MIN_REDACTED_HEAD_LENGTH) {
|
|
531
|
+
return head + TRUNCATION_SUFFIX
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return redact(value)
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/** The scanned head, shortened to end just after the last character that ends a URL. */
|
|
538
|
+
function headLength(value: string): number {
|
|
539
|
+
let end = SCANNED_HEAD_LENGTH
|
|
540
|
+
while (end > 0 && !URL_END_PATTERN.test(value[end - 1])) {
|
|
541
|
+
end--
|
|
542
|
+
}
|
|
543
|
+
return end
|
|
544
|
+
}
|
|
545
|
+
|
|
506
546
|
function sanitizeString(value: string): string {
|
|
507
|
-
return isBinaryBlob(value)
|
|
547
|
+
return isBinaryBlob(value)
|
|
548
|
+
? BINARY_REDACTED_VALUE
|
|
549
|
+
: redactCapturedHead(value, (head) => redactUrls(redactCredentials(head)))
|
|
508
550
|
}
|
|
509
551
|
|
|
510
552
|
/**
|
|
@@ -523,7 +565,7 @@ export function sanitizeFreeText(value: string): string {
|
|
|
523
565
|
if (isBinaryBlob(value)) {
|
|
524
566
|
return BINARY_REDACTED_VALUE
|
|
525
567
|
}
|
|
526
|
-
return redactUrls(redactPii(redactCredentials(
|
|
568
|
+
return redactCapturedHead(value, (head) => redactUrls(redactPii(redactCredentials(head))))
|
|
527
569
|
}
|
|
528
570
|
|
|
529
571
|
function passesLuhn(digits: string): boolean {
|
|
@@ -20,7 +20,7 @@ const MAX_STACK_FRAMES = 50
|
|
|
20
20
|
const MAX_CONTENT_TEXT_LENGTH = 32_768
|
|
21
21
|
|
|
22
22
|
// --- Truncation markers ---
|
|
23
|
-
const TRUNCATION_SUFFIX = '...'
|
|
23
|
+
export const TRUNCATION_SUFFIX = '...'
|
|
24
24
|
|
|
25
25
|
type MutableEvent = Partial<Event | McpEvent> & Record<string, unknown>
|
|
26
26
|
type MutableRecord = Record<string, unknown>
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "0.21.
|
|
1
|
+
export const version = "0.21.3"
|