@savvly/mcp-server 1.0.19 → 1.0.21
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/cli.js +3836 -11
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2231,8 +2231,8 @@ var require_resolve = __commonJS({
|
|
|
2231
2231
|
}
|
|
2232
2232
|
return count;
|
|
2233
2233
|
}
|
|
2234
|
-
function getFullPath(resolver, id = "",
|
|
2235
|
-
if (
|
|
2234
|
+
function getFullPath(resolver, id = "", normalize2) {
|
|
2235
|
+
if (normalize2 !== false)
|
|
2236
2236
|
id = normalizeId(id);
|
|
2237
2237
|
const p = resolver.parse(id);
|
|
2238
2238
|
return _getFullPath(resolver, p);
|
|
@@ -3628,7 +3628,7 @@ var require_fast_uri = __commonJS({
|
|
|
3628
3628
|
"use strict";
|
|
3629
3629
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3630
3630
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3631
|
-
function
|
|
3631
|
+
function normalize2(uri, options) {
|
|
3632
3632
|
if (typeof uri === "string") {
|
|
3633
3633
|
uri = /** @type {T} */
|
|
3634
3634
|
normalizeString(uri, options);
|
|
@@ -3895,7 +3895,7 @@ var require_fast_uri = __commonJS({
|
|
|
3895
3895
|
}
|
|
3896
3896
|
var fastUri = {
|
|
3897
3897
|
SCHEMES,
|
|
3898
|
-
normalize,
|
|
3898
|
+
normalize: normalize2,
|
|
3899
3899
|
resolve,
|
|
3900
3900
|
resolveComponent,
|
|
3901
3901
|
equal,
|
|
@@ -11044,7 +11044,7 @@ var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
|
|
|
11044
11044
|
inst.element = def.element;
|
|
11045
11045
|
inst.min = (minLength, params) => inst.check(_minLength(minLength, params));
|
|
11046
11046
|
inst.nonempty = (params) => inst.check(_minLength(1, params));
|
|
11047
|
-
inst.max = (
|
|
11047
|
+
inst.max = (maxLength2, params) => inst.check(_maxLength(maxLength2, params));
|
|
11048
11048
|
inst.length = (len, params) => inst.check(_length(len, params));
|
|
11049
11049
|
inst.unwrap = () => inst.element;
|
|
11050
11050
|
});
|
|
@@ -14455,10 +14455,10 @@ var ZodString2 = class _ZodString2 extends ZodType2 {
|
|
|
14455
14455
|
...errorUtil.errToObj(message)
|
|
14456
14456
|
});
|
|
14457
14457
|
}
|
|
14458
|
-
max(
|
|
14458
|
+
max(maxLength2, message) {
|
|
14459
14459
|
return this._addCheck({
|
|
14460
14460
|
kind: "max",
|
|
14461
|
-
value:
|
|
14461
|
+
value: maxLength2,
|
|
14462
14462
|
...errorUtil.errToObj(message)
|
|
14463
14463
|
});
|
|
14464
14464
|
}
|
|
@@ -15322,10 +15322,10 @@ var ZodArray2 = class _ZodArray extends ZodType2 {
|
|
|
15322
15322
|
minLength: { value: minLength, message: errorUtil.toString(message) }
|
|
15323
15323
|
});
|
|
15324
15324
|
}
|
|
15325
|
-
max(
|
|
15325
|
+
max(maxLength2, message) {
|
|
15326
15326
|
return new _ZodArray({
|
|
15327
15327
|
...this._def,
|
|
15328
|
-
maxLength: { value:
|
|
15328
|
+
maxLength: { value: maxLength2, message: errorUtil.toString(message) }
|
|
15329
15329
|
});
|
|
15330
15330
|
}
|
|
15331
15331
|
length(len, message) {
|
|
@@ -21704,7 +21704,7 @@ var PRODUCT_COMPARISON = {
|
|
|
21704
21704
|
var VALID_PRODUCT_TYPES = COMPARISONS.map((c) => c.product_type);
|
|
21705
21705
|
|
|
21706
21706
|
// ../../src/mcp/version.ts
|
|
21707
|
-
var SERVER_VERSION = "1.0.
|
|
21707
|
+
var SERVER_VERSION = "1.0.21";
|
|
21708
21708
|
|
|
21709
21709
|
// ../../src/mcp/ui/payout-chart.ts
|
|
21710
21710
|
var PAYOUT_UI_URI = "ui://savvly/payout-chart.html";
|
|
@@ -23818,7 +23818,7 @@ function disclosureBlock() {
|
|
|
23818
23818
|
};
|
|
23819
23819
|
}
|
|
23820
23820
|
var DISCLOSURE_REQUIRED_TERSE = "DISCLOSURE REQUIRED: display `disclosure.text` verbatim and link `disclosure.url` to the user alongside any figures from this response. Required by SEC Marketing Rule and FINRA Rule 2210 \u2014 do not paraphrase or omit.";
|
|
23821
|
-
var VISUALIZATION_RECOMMENDED_TERSE = "VISUALIZATION: this tool
|
|
23821
|
+
var VISUALIZATION_RECOMMENDED_TERSE = "VISUALIZATION: this tool emits an interactive chart widget (MCP Apps \u2014 see `_meta.ui`). MCP-Apps-capable hosts render it inline and editable; other clients render only your text and show no chart. Do NOT draw, generate, or render your own chart, graph, or table of these numbers \u2014 there is no fallback chart for you to build, so never produce a duplicate. Do NOT claim or imply a chart is visible (avoid 'the chart above shows\u2026'); you cannot tell whether the host rendered the widget. Summarize the key figures in prose and show the `disclosure` text and link, and reference the chart only conditionally (e.g. 'if your client shows the interactive chart, its fields are editable to re-run the projection').";
|
|
23822
23822
|
var INPUTS_OPTIONAL_NO_PROMPT_TERSE = "INPUTS: every parameter is OPTIONAL and defaults to a sensible value. Call this tool IMMEDIATELY \u2014 pass only the values the user explicitly stated and omit the rest. Do NOT ask the user for starting values, assumptions, or missing parameters before calling; the rendered widget has editable fields so they adjust age, amounts, and other assumptions inline after it appears.";
|
|
23823
23823
|
var SAVVLY_VS_MARKET_ALONE_PAYOUT_METHODOLOGY = "Payout methodology \u2014 Savvly vs market alone: the payout values are calculated by comparing two investors of the same age committing the same principal. Investor 1 invests in the market with Savvly's Longevity Benefit Fund; Investor 2 invests in the market alone (no longevity overlay). To make the comparison apples-to-apples, at each milestone age (80, 85, 90, 95) Investor 2 withdraws from their market alone portfolio the same dollar amount Investor 1 receives as a payout from Savvly. The `payout_market_alone_*` and `total_market_alone_*` figures are therefore what Investor 2 can actually withdraw to match Savvly's payouts before running out \u2014 they fall to 0 once the market alone portfolio is depleted. The `savvly_upside_*` (and `total_savvly_upside_*`) fields quantify how much more total money Investor 1 receives in payouts from Savvly than Investor 2 is able to withdraw over time to match those payouts.";
|
|
23824
23824
|
function summarizePayouts(envelope, depositType, deposited) {
|
|
@@ -24082,6 +24082,3827 @@ function wrapToolHandler(name, handler) {
|
|
|
24082
24082
|
}
|
|
24083
24083
|
var MAX_BODY_HASH_BYTES = 64 * 1024;
|
|
24084
24084
|
|
|
24085
|
+
// ../../node_modules/mcpcat/dist/index.mjs
|
|
24086
|
+
import { createRequire } from "module";
|
|
24087
|
+
|
|
24088
|
+
// ../../node_modules/mcpcat-api/dist/esm/runtime.js
|
|
24089
|
+
var __awaiter = function(thisArg, _arguments, P, generator) {
|
|
24090
|
+
function adopt(value) {
|
|
24091
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
24092
|
+
resolve(value);
|
|
24093
|
+
});
|
|
24094
|
+
}
|
|
24095
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
24096
|
+
function fulfilled(value) {
|
|
24097
|
+
try {
|
|
24098
|
+
step(generator.next(value));
|
|
24099
|
+
} catch (e) {
|
|
24100
|
+
reject(e);
|
|
24101
|
+
}
|
|
24102
|
+
}
|
|
24103
|
+
function rejected(value) {
|
|
24104
|
+
try {
|
|
24105
|
+
step(generator["throw"](value));
|
|
24106
|
+
} catch (e) {
|
|
24107
|
+
reject(e);
|
|
24108
|
+
}
|
|
24109
|
+
}
|
|
24110
|
+
function step(result) {
|
|
24111
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
24112
|
+
}
|
|
24113
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24114
|
+
});
|
|
24115
|
+
};
|
|
24116
|
+
var BASE_PATH = "http://localhost:8000".replace(/\/+$/, "");
|
|
24117
|
+
var Configuration = class {
|
|
24118
|
+
constructor(configuration = {}) {
|
|
24119
|
+
this.configuration = configuration;
|
|
24120
|
+
}
|
|
24121
|
+
set config(configuration) {
|
|
24122
|
+
this.configuration = configuration;
|
|
24123
|
+
}
|
|
24124
|
+
get basePath() {
|
|
24125
|
+
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
|
24126
|
+
}
|
|
24127
|
+
get fetchApi() {
|
|
24128
|
+
return this.configuration.fetchApi;
|
|
24129
|
+
}
|
|
24130
|
+
get middleware() {
|
|
24131
|
+
return this.configuration.middleware || [];
|
|
24132
|
+
}
|
|
24133
|
+
get queryParamsStringify() {
|
|
24134
|
+
return this.configuration.queryParamsStringify || querystring;
|
|
24135
|
+
}
|
|
24136
|
+
get username() {
|
|
24137
|
+
return this.configuration.username;
|
|
24138
|
+
}
|
|
24139
|
+
get password() {
|
|
24140
|
+
return this.configuration.password;
|
|
24141
|
+
}
|
|
24142
|
+
get apiKey() {
|
|
24143
|
+
const apiKey = this.configuration.apiKey;
|
|
24144
|
+
if (apiKey) {
|
|
24145
|
+
return typeof apiKey === "function" ? apiKey : () => apiKey;
|
|
24146
|
+
}
|
|
24147
|
+
return void 0;
|
|
24148
|
+
}
|
|
24149
|
+
get accessToken() {
|
|
24150
|
+
const accessToken = this.configuration.accessToken;
|
|
24151
|
+
if (accessToken) {
|
|
24152
|
+
return typeof accessToken === "function" ? accessToken : () => __awaiter(this, void 0, void 0, function* () {
|
|
24153
|
+
return accessToken;
|
|
24154
|
+
});
|
|
24155
|
+
}
|
|
24156
|
+
return void 0;
|
|
24157
|
+
}
|
|
24158
|
+
get headers() {
|
|
24159
|
+
return this.configuration.headers;
|
|
24160
|
+
}
|
|
24161
|
+
get credentials() {
|
|
24162
|
+
return this.configuration.credentials;
|
|
24163
|
+
}
|
|
24164
|
+
};
|
|
24165
|
+
var DefaultConfig = new Configuration();
|
|
24166
|
+
var BaseAPI = class _BaseAPI {
|
|
24167
|
+
constructor(configuration = DefaultConfig) {
|
|
24168
|
+
this.configuration = configuration;
|
|
24169
|
+
this.fetchApi = (url, init) => __awaiter(this, void 0, void 0, function* () {
|
|
24170
|
+
let fetchParams = { url, init };
|
|
24171
|
+
for (const middleware of this.middleware) {
|
|
24172
|
+
if (middleware.pre) {
|
|
24173
|
+
fetchParams = (yield middleware.pre(Object.assign({ fetch: this.fetchApi }, fetchParams))) || fetchParams;
|
|
24174
|
+
}
|
|
24175
|
+
}
|
|
24176
|
+
let response = void 0;
|
|
24177
|
+
try {
|
|
24178
|
+
response = yield (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init);
|
|
24179
|
+
} catch (e) {
|
|
24180
|
+
for (const middleware of this.middleware) {
|
|
24181
|
+
if (middleware.onError) {
|
|
24182
|
+
response = (yield middleware.onError({
|
|
24183
|
+
fetch: this.fetchApi,
|
|
24184
|
+
url: fetchParams.url,
|
|
24185
|
+
init: fetchParams.init,
|
|
24186
|
+
error: e,
|
|
24187
|
+
response: response ? response.clone() : void 0
|
|
24188
|
+
})) || response;
|
|
24189
|
+
}
|
|
24190
|
+
}
|
|
24191
|
+
if (response === void 0) {
|
|
24192
|
+
if (e instanceof Error) {
|
|
24193
|
+
throw new FetchError(e, "The request failed and the interceptors did not return an alternative response");
|
|
24194
|
+
} else {
|
|
24195
|
+
throw e;
|
|
24196
|
+
}
|
|
24197
|
+
}
|
|
24198
|
+
}
|
|
24199
|
+
for (const middleware of this.middleware) {
|
|
24200
|
+
if (middleware.post) {
|
|
24201
|
+
response = (yield middleware.post({
|
|
24202
|
+
fetch: this.fetchApi,
|
|
24203
|
+
url: fetchParams.url,
|
|
24204
|
+
init: fetchParams.init,
|
|
24205
|
+
response: response.clone()
|
|
24206
|
+
})) || response;
|
|
24207
|
+
}
|
|
24208
|
+
}
|
|
24209
|
+
return response;
|
|
24210
|
+
});
|
|
24211
|
+
this.middleware = configuration.middleware;
|
|
24212
|
+
}
|
|
24213
|
+
withMiddleware(...middlewares) {
|
|
24214
|
+
const next = this.clone();
|
|
24215
|
+
next.middleware = next.middleware.concat(...middlewares);
|
|
24216
|
+
return next;
|
|
24217
|
+
}
|
|
24218
|
+
withPreMiddleware(...preMiddlewares) {
|
|
24219
|
+
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
|
24220
|
+
return this.withMiddleware(...middlewares);
|
|
24221
|
+
}
|
|
24222
|
+
withPostMiddleware(...postMiddlewares) {
|
|
24223
|
+
const middlewares = postMiddlewares.map((post) => ({ post }));
|
|
24224
|
+
return this.withMiddleware(...middlewares);
|
|
24225
|
+
}
|
|
24226
|
+
/**
|
|
24227
|
+
* Check if the given MIME is a JSON MIME.
|
|
24228
|
+
* JSON MIME examples:
|
|
24229
|
+
* application/json
|
|
24230
|
+
* application/json; charset=UTF8
|
|
24231
|
+
* APPLICATION/JSON
|
|
24232
|
+
* application/vnd.company+json
|
|
24233
|
+
* @param mime - MIME (Multipurpose Internet Mail Extensions)
|
|
24234
|
+
* @return True if the given MIME is JSON, false otherwise.
|
|
24235
|
+
*/
|
|
24236
|
+
isJsonMime(mime) {
|
|
24237
|
+
if (!mime) {
|
|
24238
|
+
return false;
|
|
24239
|
+
}
|
|
24240
|
+
return _BaseAPI.jsonRegex.test(mime);
|
|
24241
|
+
}
|
|
24242
|
+
request(context, initOverrides) {
|
|
24243
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24244
|
+
const { url, init } = yield this.createFetchParams(context, initOverrides);
|
|
24245
|
+
const response = yield this.fetchApi(url, init);
|
|
24246
|
+
if (response && (response.status >= 200 && response.status < 300)) {
|
|
24247
|
+
return response;
|
|
24248
|
+
}
|
|
24249
|
+
throw new ResponseError(response, "Response returned an error code");
|
|
24250
|
+
});
|
|
24251
|
+
}
|
|
24252
|
+
createFetchParams(context, initOverrides) {
|
|
24253
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24254
|
+
let url = this.configuration.basePath + context.path;
|
|
24255
|
+
if (context.query !== void 0 && Object.keys(context.query).length !== 0) {
|
|
24256
|
+
url += "?" + this.configuration.queryParamsStringify(context.query);
|
|
24257
|
+
}
|
|
24258
|
+
const headers = Object.assign({}, this.configuration.headers, context.headers);
|
|
24259
|
+
Object.keys(headers).forEach((key) => headers[key] === void 0 ? delete headers[key] : {});
|
|
24260
|
+
const initOverrideFn = typeof initOverrides === "function" ? initOverrides : () => __awaiter(this, void 0, void 0, function* () {
|
|
24261
|
+
return initOverrides;
|
|
24262
|
+
});
|
|
24263
|
+
const initParams = {
|
|
24264
|
+
method: context.method,
|
|
24265
|
+
headers,
|
|
24266
|
+
body: context.body,
|
|
24267
|
+
credentials: this.configuration.credentials
|
|
24268
|
+
};
|
|
24269
|
+
const overriddenInit = Object.assign(Object.assign({}, initParams), yield initOverrideFn({
|
|
24270
|
+
init: initParams,
|
|
24271
|
+
context
|
|
24272
|
+
}));
|
|
24273
|
+
let body;
|
|
24274
|
+
if (isFormData(overriddenInit.body) || overriddenInit.body instanceof URLSearchParams || isBlob(overriddenInit.body)) {
|
|
24275
|
+
body = overriddenInit.body;
|
|
24276
|
+
} else if (this.isJsonMime(headers["Content-Type"])) {
|
|
24277
|
+
body = JSON.stringify(overriddenInit.body);
|
|
24278
|
+
} else {
|
|
24279
|
+
body = overriddenInit.body;
|
|
24280
|
+
}
|
|
24281
|
+
const init = Object.assign(Object.assign({}, overriddenInit), { body });
|
|
24282
|
+
return { url, init };
|
|
24283
|
+
});
|
|
24284
|
+
}
|
|
24285
|
+
/**
|
|
24286
|
+
* Create a shallow clone of `this` by constructing a new instance
|
|
24287
|
+
* and then shallow cloning data members.
|
|
24288
|
+
*/
|
|
24289
|
+
clone() {
|
|
24290
|
+
const constructor = this.constructor;
|
|
24291
|
+
const next = new constructor(this.configuration);
|
|
24292
|
+
next.middleware = this.middleware.slice();
|
|
24293
|
+
return next;
|
|
24294
|
+
}
|
|
24295
|
+
};
|
|
24296
|
+
BaseAPI.jsonRegex = new RegExp("^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$", "i");
|
|
24297
|
+
function isBlob(value) {
|
|
24298
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
24299
|
+
}
|
|
24300
|
+
function isFormData(value) {
|
|
24301
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
24302
|
+
}
|
|
24303
|
+
var ResponseError = class extends Error {
|
|
24304
|
+
constructor(response, msg) {
|
|
24305
|
+
super(msg);
|
|
24306
|
+
this.response = response;
|
|
24307
|
+
this.name = "ResponseError";
|
|
24308
|
+
}
|
|
24309
|
+
};
|
|
24310
|
+
var FetchError = class extends Error {
|
|
24311
|
+
constructor(cause, msg) {
|
|
24312
|
+
super(msg);
|
|
24313
|
+
this.cause = cause;
|
|
24314
|
+
this.name = "FetchError";
|
|
24315
|
+
}
|
|
24316
|
+
};
|
|
24317
|
+
function querystring(params, prefix = "") {
|
|
24318
|
+
return Object.keys(params).map((key) => querystringSingleKey(key, params[key], prefix)).filter((part) => part.length > 0).join("&");
|
|
24319
|
+
}
|
|
24320
|
+
function querystringSingleKey(key, value, keyPrefix = "") {
|
|
24321
|
+
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
|
24322
|
+
if (value instanceof Array) {
|
|
24323
|
+
const multiValue = value.map((singleValue) => encodeURIComponent(String(singleValue))).join(`&${encodeURIComponent(fullKey)}=`);
|
|
24324
|
+
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
|
24325
|
+
}
|
|
24326
|
+
if (value instanceof Set) {
|
|
24327
|
+
const valueAsArray = Array.from(value);
|
|
24328
|
+
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
|
24329
|
+
}
|
|
24330
|
+
if (value instanceof Date) {
|
|
24331
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
|
24332
|
+
}
|
|
24333
|
+
if (value instanceof Object) {
|
|
24334
|
+
return querystring(value, fullKey);
|
|
24335
|
+
}
|
|
24336
|
+
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
|
24337
|
+
}
|
|
24338
|
+
var JSONApiResponse = class {
|
|
24339
|
+
constructor(raw, transformer = (jsonValue) => jsonValue) {
|
|
24340
|
+
this.raw = raw;
|
|
24341
|
+
this.transformer = transformer;
|
|
24342
|
+
}
|
|
24343
|
+
value() {
|
|
24344
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24345
|
+
return this.transformer(yield this.raw.json());
|
|
24346
|
+
});
|
|
24347
|
+
}
|
|
24348
|
+
};
|
|
24349
|
+
|
|
24350
|
+
// ../../node_modules/mcpcat-api/dist/esm/models/EventAcceptedResponse.js
|
|
24351
|
+
function EventAcceptedResponseFromJSON(json) {
|
|
24352
|
+
return EventAcceptedResponseFromJSONTyped(json, false);
|
|
24353
|
+
}
|
|
24354
|
+
function EventAcceptedResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
24355
|
+
if (json == null) {
|
|
24356
|
+
return json;
|
|
24357
|
+
}
|
|
24358
|
+
return {
|
|
24359
|
+
"status": json["status"] == null ? void 0 : json["status"]
|
|
24360
|
+
};
|
|
24361
|
+
}
|
|
24362
|
+
|
|
24363
|
+
// ../../node_modules/mcpcat-api/dist/esm/models/PublishEventRequest.js
|
|
24364
|
+
var PublishEventRequestEventTypeEnum = {
|
|
24365
|
+
mcpPing: "mcp:ping",
|
|
24366
|
+
mcpInitialize: "mcp:initialize",
|
|
24367
|
+
mcpCompletionComplete: "mcp:completion/complete",
|
|
24368
|
+
mcpLoggingSetLevel: "mcp:logging/setLevel",
|
|
24369
|
+
mcpPromptsGet: "mcp:prompts/get",
|
|
24370
|
+
mcpPromptsList: "mcp:prompts/list",
|
|
24371
|
+
mcpResourcesList: "mcp:resources/list",
|
|
24372
|
+
mcpResourcesTemplatesList: "mcp:resources/templates/list",
|
|
24373
|
+
mcpResourcesRead: "mcp:resources/read",
|
|
24374
|
+
mcpResourcesSubscribe: "mcp:resources/subscribe",
|
|
24375
|
+
mcpResourcesUnsubscribe: "mcp:resources/unsubscribe",
|
|
24376
|
+
mcpToolsCall: "mcp:tools/call",
|
|
24377
|
+
mcpToolsList: "mcp:tools/list",
|
|
24378
|
+
mcpcatIdentify: "mcpcat:identify"
|
|
24379
|
+
};
|
|
24380
|
+
function PublishEventRequestToJSON(json) {
|
|
24381
|
+
return PublishEventRequestToJSONTyped(json, false);
|
|
24382
|
+
}
|
|
24383
|
+
function PublishEventRequestToJSONTyped(value, ignoreDiscriminator = false) {
|
|
24384
|
+
if (value == null) {
|
|
24385
|
+
return value;
|
|
24386
|
+
}
|
|
24387
|
+
return Object.assign(Object.assign({}, value), { "id": value["id"], "project_id": value["projectId"], "session_id": value["sessionId"], "actor_id": value["actorId"], "event_id": value["eventId"], "event_type": value["eventType"], "is_error": value["isError"], "error": value["error"], "resource_name": value["resourceName"], "duration": value["duration"], "timestamp": value["timestamp"] == null ? void 0 : value["timestamp"].toISOString(), "user_intent": value["userIntent"], "parameters": value["parameters"], "response": value["response"], "identify_actor_given_id": value["identifyActorGivenId"], "identify_actor_name": value["identifyActorName"], "identify_data": value["identifyData"], "tags": value["tags"], "properties": value["properties"], "ip_address": value["ipAddress"], "sdk_language": value["sdkLanguage"], "mcpcat_version": value["mcpcatVersion"], "server_name": value["serverName"], "server_version": value["serverVersion"], "client_name": value["clientName"], "client_version": value["clientVersion"] });
|
|
24388
|
+
}
|
|
24389
|
+
|
|
24390
|
+
// ../../node_modules/mcpcat-api/dist/esm/apis/EventsApi.js
|
|
24391
|
+
var __awaiter2 = function(thisArg, _arguments, P, generator) {
|
|
24392
|
+
function adopt(value) {
|
|
24393
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
24394
|
+
resolve(value);
|
|
24395
|
+
});
|
|
24396
|
+
}
|
|
24397
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
24398
|
+
function fulfilled(value) {
|
|
24399
|
+
try {
|
|
24400
|
+
step(generator.next(value));
|
|
24401
|
+
} catch (e) {
|
|
24402
|
+
reject(e);
|
|
24403
|
+
}
|
|
24404
|
+
}
|
|
24405
|
+
function rejected(value) {
|
|
24406
|
+
try {
|
|
24407
|
+
step(generator["throw"](value));
|
|
24408
|
+
} catch (e) {
|
|
24409
|
+
reject(e);
|
|
24410
|
+
}
|
|
24411
|
+
}
|
|
24412
|
+
function step(result) {
|
|
24413
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
24414
|
+
}
|
|
24415
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
24416
|
+
});
|
|
24417
|
+
};
|
|
24418
|
+
var EventsApi = class extends BaseAPI {
|
|
24419
|
+
/**
|
|
24420
|
+
* Submit analytics events for a project. Returns immediately with 202 Accepted.
|
|
24421
|
+
* Publish analytics event
|
|
24422
|
+
*/
|
|
24423
|
+
publishEventRaw(requestParameters, initOverrides) {
|
|
24424
|
+
return __awaiter2(this, void 0, void 0, function* () {
|
|
24425
|
+
const queryParameters = {};
|
|
24426
|
+
const headerParameters = {};
|
|
24427
|
+
headerParameters["Content-Type"] = "application/json";
|
|
24428
|
+
if (this.configuration && this.configuration.apiKey) {
|
|
24429
|
+
headerParameters["Authorization"] = yield this.configuration.apiKey("Authorization");
|
|
24430
|
+
}
|
|
24431
|
+
let urlPath = `/v1/public/events/`;
|
|
24432
|
+
const response = yield this.request({
|
|
24433
|
+
path: urlPath,
|
|
24434
|
+
method: "POST",
|
|
24435
|
+
headers: headerParameters,
|
|
24436
|
+
query: queryParameters,
|
|
24437
|
+
body: PublishEventRequestToJSON(requestParameters["publishEventRequest"])
|
|
24438
|
+
}, initOverrides);
|
|
24439
|
+
return new JSONApiResponse(response, (jsonValue) => EventAcceptedResponseFromJSON(jsonValue));
|
|
24440
|
+
});
|
|
24441
|
+
}
|
|
24442
|
+
/**
|
|
24443
|
+
* Submit analytics events for a project. Returns immediately with 202 Accepted.
|
|
24444
|
+
* Publish analytics event
|
|
24445
|
+
*/
|
|
24446
|
+
publishEvent() {
|
|
24447
|
+
return __awaiter2(this, arguments, void 0, function* (requestParameters = {}, initOverrides) {
|
|
24448
|
+
const response = yield this.publishEventRaw(requestParameters, initOverrides);
|
|
24449
|
+
return yield response.value();
|
|
24450
|
+
});
|
|
24451
|
+
}
|
|
24452
|
+
};
|
|
24453
|
+
|
|
24454
|
+
// ../../node_modules/mcpcat/dist/index.mjs
|
|
24455
|
+
import { randomBytes } from "crypto";
|
|
24456
|
+
import { inspect } from "util";
|
|
24457
|
+
import { promisify } from "util";
|
|
24458
|
+
import { createHash as createHash2 } from "crypto";
|
|
24459
|
+
import { createRequire as createRequire2 } from "module";
|
|
24460
|
+
import { createHash as createHash22, randomBytes as randomBytes2 } from "crypto";
|
|
24461
|
+
import { createHash as createHash3 } from "crypto";
|
|
24462
|
+
var fsModule = null;
|
|
24463
|
+
var logFilePath = null;
|
|
24464
|
+
var initAttempted = false;
|
|
24465
|
+
var useConsoleFallback = false;
|
|
24466
|
+
function tryInitSync() {
|
|
24467
|
+
if (initAttempted) return;
|
|
24468
|
+
initAttempted = true;
|
|
24469
|
+
try {
|
|
24470
|
+
const require2 = createRequire(import.meta.url);
|
|
24471
|
+
const fs = require2("fs");
|
|
24472
|
+
const os = require2("os");
|
|
24473
|
+
const path = require2("path");
|
|
24474
|
+
const home = os.homedir?.();
|
|
24475
|
+
if (home) {
|
|
24476
|
+
fsModule = fs;
|
|
24477
|
+
logFilePath = path.join(home, "mcpcat.log");
|
|
24478
|
+
} else {
|
|
24479
|
+
useConsoleFallback = true;
|
|
24480
|
+
}
|
|
24481
|
+
} catch {
|
|
24482
|
+
useConsoleFallback = true;
|
|
24483
|
+
fsModule = null;
|
|
24484
|
+
logFilePath = null;
|
|
24485
|
+
}
|
|
24486
|
+
}
|
|
24487
|
+
function writeToLog(message) {
|
|
24488
|
+
tryInitSync();
|
|
24489
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
24490
|
+
const logEntry = `[${timestamp}] ${message}`;
|
|
24491
|
+
if (useConsoleFallback) {
|
|
24492
|
+
console.log(`[mcpcat] ${logEntry}`);
|
|
24493
|
+
return;
|
|
24494
|
+
}
|
|
24495
|
+
if (!logFilePath || !fsModule) {
|
|
24496
|
+
return;
|
|
24497
|
+
}
|
|
24498
|
+
try {
|
|
24499
|
+
if (!fsModule.existsSync(logFilePath)) {
|
|
24500
|
+
fsModule.writeFileSync(logFilePath, logEntry + "\n");
|
|
24501
|
+
} else {
|
|
24502
|
+
fsModule.appendFileSync(logFilePath, logEntry + "\n");
|
|
24503
|
+
}
|
|
24504
|
+
} catch {
|
|
24505
|
+
}
|
|
24506
|
+
}
|
|
24507
|
+
function logCompatibilityWarning() {
|
|
24508
|
+
writeToLog(
|
|
24509
|
+
"MCPCat SDK Compatibility: This version only supports Model Context Protocol TypeScript SDK v1.11 and above. Please upgrade if using an older version."
|
|
24510
|
+
);
|
|
24511
|
+
}
|
|
24512
|
+
function isHighLevelServer(server) {
|
|
24513
|
+
return server && typeof server === "object" && server.server && typeof server.server === "object";
|
|
24514
|
+
}
|
|
24515
|
+
function isCompatibleServerType(server) {
|
|
24516
|
+
if (!server || typeof server !== "object") {
|
|
24517
|
+
logCompatibilityWarning();
|
|
24518
|
+
throw new Error(
|
|
24519
|
+
"MCPCat SDK compatibility error: Server must be an object. Ensure you're using MCP SDK v1.11 or higher."
|
|
24520
|
+
);
|
|
24521
|
+
}
|
|
24522
|
+
if (isHighLevelServer(server)) {
|
|
24523
|
+
if (!server._registeredTools || typeof server._registeredTools !== "object") {
|
|
24524
|
+
logCompatibilityWarning();
|
|
24525
|
+
throw new Error(
|
|
24526
|
+
"MCPCat SDK compatibility error: High-level server must have _registeredTools object. This requires MCP SDK v1.11 or higher."
|
|
24527
|
+
);
|
|
24528
|
+
}
|
|
24529
|
+
if (typeof server.tool !== "function") {
|
|
24530
|
+
logCompatibilityWarning();
|
|
24531
|
+
throw new Error(
|
|
24532
|
+
"MCPCat SDK compatibility error: High-level server must have tool() method. This requires MCP SDK v1.11 or higher."
|
|
24533
|
+
);
|
|
24534
|
+
}
|
|
24535
|
+
const targetServer = server.server;
|
|
24536
|
+
validateLowLevelServer(targetServer);
|
|
24537
|
+
return server;
|
|
24538
|
+
} else {
|
|
24539
|
+
validateLowLevelServer(server);
|
|
24540
|
+
return server;
|
|
24541
|
+
}
|
|
24542
|
+
}
|
|
24543
|
+
function validateLowLevelServer(server) {
|
|
24544
|
+
if (typeof server.setRequestHandler !== "function") {
|
|
24545
|
+
logCompatibilityWarning();
|
|
24546
|
+
throw new Error(
|
|
24547
|
+
"MCPCat SDK compatibility error: Server must have a setRequestHandler method. This requires MCP SDK v1.11 or higher."
|
|
24548
|
+
);
|
|
24549
|
+
}
|
|
24550
|
+
if (!server._requestHandlers || !(server._requestHandlers instanceof Map)) {
|
|
24551
|
+
logCompatibilityWarning();
|
|
24552
|
+
throw new Error(
|
|
24553
|
+
"MCPCat SDK compatibility error: Server._requestHandlers is not accessible. This requires MCP SDK v1.11 or higher."
|
|
24554
|
+
);
|
|
24555
|
+
}
|
|
24556
|
+
if (typeof server._requestHandlers.get !== "function") {
|
|
24557
|
+
logCompatibilityWarning();
|
|
24558
|
+
throw new Error(
|
|
24559
|
+
"MCPCat SDK compatibility error: Server._requestHandlers must be a Map with a get method. This requires MCP SDK v1.11 or higher."
|
|
24560
|
+
);
|
|
24561
|
+
}
|
|
24562
|
+
if (typeof server.getClientVersion !== "function") {
|
|
24563
|
+
logCompatibilityWarning();
|
|
24564
|
+
throw new Error(
|
|
24565
|
+
"MCPCat SDK compatibility error: Server.getClientVersion must be a function. This requires MCP SDK v1.11 or higher."
|
|
24566
|
+
);
|
|
24567
|
+
}
|
|
24568
|
+
if (!server._serverInfo || typeof server._serverInfo !== "object" || !server._serverInfo.name) {
|
|
24569
|
+
logCompatibilityWarning();
|
|
24570
|
+
throw new Error(
|
|
24571
|
+
"MCPCat SDK compatibility error: Server._serverInfo is not accessible or missing name. This requires MCP SDK v1.11 or higher."
|
|
24572
|
+
);
|
|
24573
|
+
}
|
|
24574
|
+
}
|
|
24575
|
+
function getMCPCompatibleErrorMessage(error2) {
|
|
24576
|
+
if (error2 instanceof Error) {
|
|
24577
|
+
try {
|
|
24578
|
+
return JSON.stringify(error2, Object.getOwnPropertyNames(error2));
|
|
24579
|
+
} catch {
|
|
24580
|
+
return "Unknown error";
|
|
24581
|
+
}
|
|
24582
|
+
} else if (typeof error2 === "string") {
|
|
24583
|
+
return error2;
|
|
24584
|
+
} else if (typeof error2 === "object" && error2 !== null) {
|
|
24585
|
+
return JSON.stringify(error2);
|
|
24586
|
+
}
|
|
24587
|
+
return "Unknown error";
|
|
24588
|
+
}
|
|
24589
|
+
var maxLength = (array2, from, to) => Math.ceil(array2.length * Math.log2(from) / Math.log2(to));
|
|
24590
|
+
function baseConvertIntArray(array2, { from, to, fixedLength = null }) {
|
|
24591
|
+
const length = fixedLength === null ? maxLength(array2, from, to) : fixedLength;
|
|
24592
|
+
const result = new Array(length);
|
|
24593
|
+
let offset = length;
|
|
24594
|
+
let input = array2;
|
|
24595
|
+
while (input.length > 0) {
|
|
24596
|
+
if (offset === 0) {
|
|
24597
|
+
throw new RangeError(
|
|
24598
|
+
`Fixed length of ${fixedLength} is too small, expected at least ${maxLength(array2, from, to)}`
|
|
24599
|
+
);
|
|
24600
|
+
}
|
|
24601
|
+
const quotients = [];
|
|
24602
|
+
let remainder = 0;
|
|
24603
|
+
for (const digit of input) {
|
|
24604
|
+
const acc = digit + remainder * from;
|
|
24605
|
+
const q = Math.floor(acc / to);
|
|
24606
|
+
remainder = acc % to;
|
|
24607
|
+
if (quotients.length > 0 || q > 0) {
|
|
24608
|
+
quotients.push(q);
|
|
24609
|
+
}
|
|
24610
|
+
}
|
|
24611
|
+
result[--offset] = remainder;
|
|
24612
|
+
input = quotients;
|
|
24613
|
+
}
|
|
24614
|
+
if (fixedLength === null) {
|
|
24615
|
+
return offset > 0 ? result.slice(offset) : result;
|
|
24616
|
+
}
|
|
24617
|
+
while (offset > 0) {
|
|
24618
|
+
result[--offset] = 0;
|
|
24619
|
+
}
|
|
24620
|
+
return result;
|
|
24621
|
+
}
|
|
24622
|
+
var base_convert_int_array_default = baseConvertIntArray;
|
|
24623
|
+
var CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
24624
|
+
function encode(buffer, fixedLength) {
|
|
24625
|
+
return base_convert_int_array_default(buffer, { from: 256, to: 62, fixedLength }).map((value) => CHARS[value]).join("");
|
|
24626
|
+
}
|
|
24627
|
+
function decode(string3, fixedLength) {
|
|
24628
|
+
const input = Array.from(string3, (char) => {
|
|
24629
|
+
const charCode = char.charCodeAt(0);
|
|
24630
|
+
if (charCode < 58) return charCode - 48;
|
|
24631
|
+
if (charCode < 91) return charCode - 55;
|
|
24632
|
+
return charCode - 61;
|
|
24633
|
+
});
|
|
24634
|
+
return Buffer.from(
|
|
24635
|
+
base_convert_int_array_default(input, { from: 62, to: 256, fixedLength })
|
|
24636
|
+
);
|
|
24637
|
+
}
|
|
24638
|
+
var customInspectSymbol = inspect.custom;
|
|
24639
|
+
var asyncRandomBytes = promisify(randomBytes);
|
|
24640
|
+
var EPOCH_IN_MS = 14e11;
|
|
24641
|
+
var MAX_TIME_IN_MS = 1e3 * (2 ** 32 - 1) + EPOCH_IN_MS;
|
|
24642
|
+
var TIMESTAMP_BYTE_LENGTH = 4;
|
|
24643
|
+
var PAYLOAD_BYTE_LENGTH = 16;
|
|
24644
|
+
var BYTE_LENGTH = TIMESTAMP_BYTE_LENGTH + PAYLOAD_BYTE_LENGTH;
|
|
24645
|
+
var STRING_ENCODED_LENGTH = 27;
|
|
24646
|
+
var TIME_IN_MS_ASSERTION = `Valid KSUID timestamps must be in milliseconds since ${(/* @__PURE__ */ new Date(0)).toISOString()},
|
|
24647
|
+
no earlier than ${new Date(EPOCH_IN_MS).toISOString()} and no later than ${new Date(MAX_TIME_IN_MS).toISOString()}
|
|
24648
|
+
`.trim().replace(/(\n|\s)+/g, " ").replace(/\.000Z/g, "Z");
|
|
24649
|
+
var VALID_ENCODING_ASSERTION = `Valid encoded KSUIDs are ${STRING_ENCODED_LENGTH} characters`;
|
|
24650
|
+
var VALID_BUFFER_ASSERTION = `Valid KSUID buffers are ${BYTE_LENGTH} bytes`;
|
|
24651
|
+
var VALID_PAYLOAD_ASSERTION = `Valid KSUID payloads are ${PAYLOAD_BYTE_LENGTH} bytes`;
|
|
24652
|
+
function fromParts(timeInMs, payload) {
|
|
24653
|
+
const timestamp = Math.floor((timeInMs - EPOCH_IN_MS) / 1e3);
|
|
24654
|
+
const timestampBuffer = Buffer.allocUnsafe(TIMESTAMP_BYTE_LENGTH);
|
|
24655
|
+
timestampBuffer.writeUInt32BE(timestamp, 0);
|
|
24656
|
+
return Buffer.concat([timestampBuffer, payload], BYTE_LENGTH);
|
|
24657
|
+
}
|
|
24658
|
+
var bufferLookup = /* @__PURE__ */ new WeakMap();
|
|
24659
|
+
var KSUID = class _KSUID {
|
|
24660
|
+
constructor(buffer) {
|
|
24661
|
+
if (!_KSUID.isValid(buffer)) {
|
|
24662
|
+
throw new TypeError(VALID_BUFFER_ASSERTION);
|
|
24663
|
+
}
|
|
24664
|
+
bufferLookup.set(this, buffer);
|
|
24665
|
+
Object.defineProperty(this, "buffer", {
|
|
24666
|
+
enumerable: true,
|
|
24667
|
+
get() {
|
|
24668
|
+
return Buffer.from(buffer);
|
|
24669
|
+
}
|
|
24670
|
+
});
|
|
24671
|
+
}
|
|
24672
|
+
get raw() {
|
|
24673
|
+
return Buffer.from(bufferLookup.get(this).slice(0));
|
|
24674
|
+
}
|
|
24675
|
+
get date() {
|
|
24676
|
+
return new Date(1e3 * this.timestamp + EPOCH_IN_MS);
|
|
24677
|
+
}
|
|
24678
|
+
get timestamp() {
|
|
24679
|
+
return bufferLookup.get(this).readUInt32BE(0);
|
|
24680
|
+
}
|
|
24681
|
+
get payload() {
|
|
24682
|
+
const payload = bufferLookup.get(this).slice(TIMESTAMP_BYTE_LENGTH, BYTE_LENGTH);
|
|
24683
|
+
return Buffer.from(payload);
|
|
24684
|
+
}
|
|
24685
|
+
get string() {
|
|
24686
|
+
const encoded = encode(
|
|
24687
|
+
bufferLookup.get(this),
|
|
24688
|
+
STRING_ENCODED_LENGTH
|
|
24689
|
+
);
|
|
24690
|
+
return encoded.padStart(STRING_ENCODED_LENGTH, "0");
|
|
24691
|
+
}
|
|
24692
|
+
compare(other) {
|
|
24693
|
+
if (!bufferLookup.has(other)) {
|
|
24694
|
+
return 0;
|
|
24695
|
+
}
|
|
24696
|
+
return bufferLookup.get(this).compare(bufferLookup.get(other), 0, BYTE_LENGTH);
|
|
24697
|
+
}
|
|
24698
|
+
equals(other) {
|
|
24699
|
+
return this === other || bufferLookup.has(other) && this.compare(other) === 0;
|
|
24700
|
+
}
|
|
24701
|
+
toString() {
|
|
24702
|
+
return `${this[Symbol.toStringTag]} { ${this.string} }`;
|
|
24703
|
+
}
|
|
24704
|
+
toJSON() {
|
|
24705
|
+
return this.string;
|
|
24706
|
+
}
|
|
24707
|
+
[customInspectSymbol]() {
|
|
24708
|
+
return this.toString();
|
|
24709
|
+
}
|
|
24710
|
+
static async random(time3 = Date.now()) {
|
|
24711
|
+
const payload = await asyncRandomBytes(PAYLOAD_BYTE_LENGTH);
|
|
24712
|
+
return new _KSUID(fromParts(Number(time3), payload));
|
|
24713
|
+
}
|
|
24714
|
+
static randomSync(time3 = Date.now()) {
|
|
24715
|
+
const payload = randomBytes(PAYLOAD_BYTE_LENGTH);
|
|
24716
|
+
return new _KSUID(fromParts(Number(time3), payload));
|
|
24717
|
+
}
|
|
24718
|
+
static fromParts(timeInMs, payload) {
|
|
24719
|
+
if (!Number.isInteger(timeInMs) || timeInMs < EPOCH_IN_MS || timeInMs > MAX_TIME_IN_MS) {
|
|
24720
|
+
throw new TypeError(TIME_IN_MS_ASSERTION);
|
|
24721
|
+
}
|
|
24722
|
+
if (!Buffer.isBuffer(payload) || payload.byteLength !== PAYLOAD_BYTE_LENGTH) {
|
|
24723
|
+
throw new TypeError(VALID_PAYLOAD_ASSERTION);
|
|
24724
|
+
}
|
|
24725
|
+
return new _KSUID(fromParts(timeInMs, payload));
|
|
24726
|
+
}
|
|
24727
|
+
static isValid(buffer) {
|
|
24728
|
+
return Buffer.isBuffer(buffer) && buffer.byteLength === BYTE_LENGTH;
|
|
24729
|
+
}
|
|
24730
|
+
static parse(string3) {
|
|
24731
|
+
if (string3.length !== STRING_ENCODED_LENGTH) {
|
|
24732
|
+
throw new TypeError(VALID_ENCODING_ASSERTION);
|
|
24733
|
+
}
|
|
24734
|
+
const decoded = decode(string3, BYTE_LENGTH);
|
|
24735
|
+
if (decoded.byteLength === BYTE_LENGTH) {
|
|
24736
|
+
return new _KSUID(decoded);
|
|
24737
|
+
}
|
|
24738
|
+
const buffer = Buffer.allocUnsafe(BYTE_LENGTH);
|
|
24739
|
+
const padEnd = BYTE_LENGTH - decoded.byteLength;
|
|
24740
|
+
buffer.fill(0, 0, padEnd);
|
|
24741
|
+
decoded.copy(buffer, padEnd);
|
|
24742
|
+
return new _KSUID(buffer);
|
|
24743
|
+
}
|
|
24744
|
+
};
|
|
24745
|
+
Object.defineProperty(KSUID.prototype, Symbol.toStringTag, { value: "KSUID" });
|
|
24746
|
+
Object.defineProperty(KSUID, "MAX_STRING_ENCODED", {
|
|
24747
|
+
value: "aWgEPTl1tmebfsQzFP4bxwgy80V"
|
|
24748
|
+
});
|
|
24749
|
+
Object.defineProperty(KSUID, "MIN_STRING_ENCODED", {
|
|
24750
|
+
value: "000000000000000000000000000"
|
|
24751
|
+
});
|
|
24752
|
+
KSUID.withPrefix = function(prefix) {
|
|
24753
|
+
return {
|
|
24754
|
+
random: async (time3 = Date.now()) => {
|
|
24755
|
+
const ksuid2 = await KSUID.random(time3);
|
|
24756
|
+
return `${prefix}_${ksuid2.string}`;
|
|
24757
|
+
},
|
|
24758
|
+
randomSync: (time3 = Date.now()) => {
|
|
24759
|
+
const ksuid2 = KSUID.randomSync(time3);
|
|
24760
|
+
return `${prefix}_${ksuid2.string}`;
|
|
24761
|
+
},
|
|
24762
|
+
fromParts: (timeInMs, payload) => {
|
|
24763
|
+
const ksuid2 = KSUID.fromParts(timeInMs, payload);
|
|
24764
|
+
return `${prefix}_${ksuid2.string}`;
|
|
24765
|
+
}
|
|
24766
|
+
};
|
|
24767
|
+
};
|
|
24768
|
+
var ksuid_default = KSUID;
|
|
24769
|
+
var package_default = {
|
|
24770
|
+
name: "mcpcat",
|
|
24771
|
+
version: "0.1.16",
|
|
24772
|
+
description: "Analytics tool for MCP (Model Context Protocol) servers - tracks tool usage patterns and provides insights",
|
|
24773
|
+
type: "module",
|
|
24774
|
+
main: "dist/index.js",
|
|
24775
|
+
module: "dist/index.mjs",
|
|
24776
|
+
types: "dist/index.d.ts",
|
|
24777
|
+
exports: {
|
|
24778
|
+
".": {
|
|
24779
|
+
types: "./dist/index.d.ts",
|
|
24780
|
+
import: "./dist/index.mjs",
|
|
24781
|
+
require: "./dist/index.cjs"
|
|
24782
|
+
}
|
|
24783
|
+
},
|
|
24784
|
+
scripts: {
|
|
24785
|
+
build: "tsup",
|
|
24786
|
+
dev: "tsup --watch",
|
|
24787
|
+
test: "vitest",
|
|
24788
|
+
"test:compatibility": "vitest run src/tests/mcp-version-compatibility.test.ts",
|
|
24789
|
+
"test:esm-consume": "vitest run src/tests/esm-consumer.test.ts",
|
|
24790
|
+
lint: "eslint src/",
|
|
24791
|
+
typecheck: "tsc --noEmit",
|
|
24792
|
+
prepare: "husky",
|
|
24793
|
+
prepublishOnly: "pnpm run build && pnpm run test && pnpm run lint && pnpm run typecheck"
|
|
24794
|
+
},
|
|
24795
|
+
keywords: [
|
|
24796
|
+
"ai",
|
|
24797
|
+
"authentication",
|
|
24798
|
+
"mcp",
|
|
24799
|
+
"observability",
|
|
24800
|
+
"ai-agents",
|
|
24801
|
+
"ai-platform",
|
|
24802
|
+
"ai-agent",
|
|
24803
|
+
"mcps",
|
|
24804
|
+
"aiagents",
|
|
24805
|
+
"ai-agent-tools",
|
|
24806
|
+
"mcp-servers",
|
|
24807
|
+
"mcp-server",
|
|
24808
|
+
"mcp-tools",
|
|
24809
|
+
"agent-runtime",
|
|
24810
|
+
"mcp-framework",
|
|
24811
|
+
"mcp-analytics"
|
|
24812
|
+
],
|
|
24813
|
+
author: "MCPcat",
|
|
24814
|
+
license: "MIT",
|
|
24815
|
+
repository: {
|
|
24816
|
+
type: "git",
|
|
24817
|
+
url: "git+https://github.com/MCPCat/mcpcat-typescript-sdk.git"
|
|
24818
|
+
},
|
|
24819
|
+
bugs: {
|
|
24820
|
+
url: "https://github.com/MCPCat/mcpcat-typescript-sdk/issues"
|
|
24821
|
+
},
|
|
24822
|
+
homepage: "https://github.com/MCPCat/mcpcat-typescript-sdk#readme",
|
|
24823
|
+
packageManager: "pnpm@10.11.0",
|
|
24824
|
+
devDependencies: {
|
|
24825
|
+
"@changesets/cli": "^2.29.8",
|
|
24826
|
+
"@modelcontextprotocol/sdk": "~1.24.2",
|
|
24827
|
+
"@types/node": "^22.15.21",
|
|
24828
|
+
"@types/uuid": "^11.0.0",
|
|
24829
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
24830
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
24831
|
+
"@vitest/coverage-v8": "^4.0.14",
|
|
24832
|
+
"@vitest/ui": "^4.0.14",
|
|
24833
|
+
eslint: "^9.39.1",
|
|
24834
|
+
husky: "^9.1.7",
|
|
24835
|
+
"lint-staged": "^16.1.0",
|
|
24836
|
+
prettier: "^3.5.3",
|
|
24837
|
+
tsup: "^8.5.0",
|
|
24838
|
+
typescript: "^5.8.3",
|
|
24839
|
+
uuid: "^13.0.0",
|
|
24840
|
+
vitest: "^4.0.14",
|
|
24841
|
+
zod: "^3.25 || ^4.0"
|
|
24842
|
+
},
|
|
24843
|
+
peerDependencies: {
|
|
24844
|
+
"@modelcontextprotocol/sdk": ">=1.11"
|
|
24845
|
+
},
|
|
24846
|
+
dependencies: {
|
|
24847
|
+
"mcpcat-api": "0.1.9"
|
|
24848
|
+
},
|
|
24849
|
+
"lint-staged": {
|
|
24850
|
+
"*.{ts,js}": [
|
|
24851
|
+
"eslint --fix",
|
|
24852
|
+
"prettier --write"
|
|
24853
|
+
],
|
|
24854
|
+
"*.{json,md,yml,yaml}": [
|
|
24855
|
+
"prettier --write"
|
|
24856
|
+
]
|
|
24857
|
+
},
|
|
24858
|
+
pnpm: {
|
|
24859
|
+
overrides: {
|
|
24860
|
+
"js-yaml": ">=4.1.1",
|
|
24861
|
+
tmp: ">=0.2.4",
|
|
24862
|
+
vite: ">=6.4.1",
|
|
24863
|
+
"body-parser": ">=2.2.1",
|
|
24864
|
+
"brace-expansion": "2.0.2"
|
|
24865
|
+
},
|
|
24866
|
+
overridesComments: {
|
|
24867
|
+
"js-yaml": "Fixes GHSA-mh29-5h37-fv8m (prototype pollution in merge) - via @changesets/cli",
|
|
24868
|
+
tmp: "Fixes GHSA-52f5-9888-hmc6 (symlink attack) - via @changesets/cli",
|
|
24869
|
+
vite: "Fixes GHSA-93m4-6634-74q7 and other vite security issues - via vitest",
|
|
24870
|
+
"body-parser": "Fixes GHSA-wqch-xfxh-vrr4 (DoS via url encoding) - via @modelcontextprotocol/sdk",
|
|
24871
|
+
"brace-expansion": "Fixes GHSA-v6h2-p8h4-qcjw (ReDoS vulnerability) - via eslint"
|
|
24872
|
+
}
|
|
24873
|
+
}
|
|
24874
|
+
};
|
|
24875
|
+
var INACTIVITY_TIMEOUT_IN_MINUTES = 30;
|
|
24876
|
+
var DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = `Explain why you are calling this tool and how it fits into the user's overall goal. This parameter is used for analytics and user intent tracking. YOU MUST provide 15-25 words (count carefully). NEVER use first person ('I', 'we', 'you') - maintain third-person perspective. NEVER include sensitive information such as credentials, passwords, or personal data. Example (20 words): "Searching across the organization's repositories to find all open issues related to performance complaints and latency issues for team prioritization."`;
|
|
24877
|
+
var MCPCAT_SOURCE = "mcpcat";
|
|
24878
|
+
function newSessionId() {
|
|
24879
|
+
return ksuid_default.withPrefix("ses").randomSync();
|
|
24880
|
+
}
|
|
24881
|
+
function deriveSessionIdFromMCPSession(mcpSessionId, projectId) {
|
|
24882
|
+
const input = projectId ? `${mcpSessionId}:${projectId}` : mcpSessionId;
|
|
24883
|
+
const hash = createHash2("sha256").update(input).digest();
|
|
24884
|
+
const EPOCH_2024 = (/* @__PURE__ */ new Date("2024-01-01T00:00:00Z")).getTime();
|
|
24885
|
+
const timestampOffset = hash.readUInt32BE(0) % (365 * 24 * 60 * 60 * 1e3);
|
|
24886
|
+
const timestamp = EPOCH_2024 + timestampOffset;
|
|
24887
|
+
const payload = hash.subarray(4, 20);
|
|
24888
|
+
return ksuid_default.withPrefix("ses").fromParts(timestamp, payload);
|
|
24889
|
+
}
|
|
24890
|
+
function getServerSessionId(server, extra) {
|
|
24891
|
+
const data = getServerTrackingData(server);
|
|
24892
|
+
if (!data) {
|
|
24893
|
+
throw new Error("Server tracking data not found");
|
|
24894
|
+
}
|
|
24895
|
+
const mcpSessionId = extra?.sessionId;
|
|
24896
|
+
if (mcpSessionId) {
|
|
24897
|
+
data.sessionId = deriveSessionIdFromMCPSession(
|
|
24898
|
+
mcpSessionId,
|
|
24899
|
+
data.projectId || void 0
|
|
24900
|
+
);
|
|
24901
|
+
data.lastMcpSessionId = mcpSessionId;
|
|
24902
|
+
data.sessionSource = "mcp";
|
|
24903
|
+
setServerTrackingData(server, data);
|
|
24904
|
+
setLastActivity(server);
|
|
24905
|
+
return data.sessionId;
|
|
24906
|
+
}
|
|
24907
|
+
if (data.sessionSource === "mcp" && data.lastMcpSessionId) {
|
|
24908
|
+
setLastActivity(server);
|
|
24909
|
+
return data.sessionId;
|
|
24910
|
+
}
|
|
24911
|
+
const now = Date.now();
|
|
24912
|
+
const timeoutMs = INACTIVITY_TIMEOUT_IN_MINUTES * 60 * 1e3;
|
|
24913
|
+
if (now - data.lastActivity.getTime() > timeoutMs) {
|
|
24914
|
+
data.sessionId = newSessionId();
|
|
24915
|
+
data.sessionSource = "mcpcat";
|
|
24916
|
+
setServerTrackingData(server, data);
|
|
24917
|
+
}
|
|
24918
|
+
setLastActivity(server);
|
|
24919
|
+
return data.sessionId;
|
|
24920
|
+
}
|
|
24921
|
+
function setLastActivity(server) {
|
|
24922
|
+
const data = getServerTrackingData(server);
|
|
24923
|
+
if (!data) {
|
|
24924
|
+
throw new Error("Server tracking data not found");
|
|
24925
|
+
}
|
|
24926
|
+
data.lastActivity = /* @__PURE__ */ new Date();
|
|
24927
|
+
setServerTrackingData(server, data);
|
|
24928
|
+
}
|
|
24929
|
+
function getSessionInfo(server, data) {
|
|
24930
|
+
let clientInfo = {
|
|
24931
|
+
name: void 0,
|
|
24932
|
+
version: void 0
|
|
24933
|
+
};
|
|
24934
|
+
if (!data?.sessionInfo.clientName) {
|
|
24935
|
+
clientInfo = server.getClientVersion();
|
|
24936
|
+
}
|
|
24937
|
+
const actorInfo = data?.identifiedSessions.get(data.sessionId);
|
|
24938
|
+
const sessionInfo = {
|
|
24939
|
+
ipAddress: void 0,
|
|
24940
|
+
// grab from django
|
|
24941
|
+
sdkLanguage: "TypeScript",
|
|
24942
|
+
// hardcoded for now
|
|
24943
|
+
mcpcatVersion: package_default.version,
|
|
24944
|
+
serverName: server._serverInfo?.name,
|
|
24945
|
+
serverVersion: server._serverInfo?.version,
|
|
24946
|
+
clientName: clientInfo?.name,
|
|
24947
|
+
clientVersion: clientInfo?.version,
|
|
24948
|
+
identifyActorGivenId: actorInfo?.userId,
|
|
24949
|
+
identifyActorName: actorInfo?.userName,
|
|
24950
|
+
identifyActorData: actorInfo?.userData || {}
|
|
24951
|
+
};
|
|
24952
|
+
if (!data) {
|
|
24953
|
+
return sessionInfo;
|
|
24954
|
+
}
|
|
24955
|
+
data.sessionInfo = sessionInfo;
|
|
24956
|
+
setServerTrackingData(server, data);
|
|
24957
|
+
return data.sessionInfo;
|
|
24958
|
+
}
|
|
24959
|
+
var PROTECTED_FIELDS = /* @__PURE__ */ new Set([
|
|
24960
|
+
"sessionId",
|
|
24961
|
+
"id",
|
|
24962
|
+
"projectId",
|
|
24963
|
+
"server",
|
|
24964
|
+
"identifyActorGivenId",
|
|
24965
|
+
"identifyActorName",
|
|
24966
|
+
"identifyData",
|
|
24967
|
+
"resourceName",
|
|
24968
|
+
"eventType",
|
|
24969
|
+
"actorId",
|
|
24970
|
+
"tags",
|
|
24971
|
+
"properties"
|
|
24972
|
+
]);
|
|
24973
|
+
async function redactStringsInObject(obj, redactFn, path = "", isProtected = false) {
|
|
24974
|
+
if (obj === null || obj === void 0) {
|
|
24975
|
+
return obj;
|
|
24976
|
+
}
|
|
24977
|
+
if (typeof obj === "string") {
|
|
24978
|
+
if (isProtected) {
|
|
24979
|
+
return obj;
|
|
24980
|
+
}
|
|
24981
|
+
return await redactFn(obj);
|
|
24982
|
+
}
|
|
24983
|
+
if (Array.isArray(obj)) {
|
|
24984
|
+
return Promise.all(
|
|
24985
|
+
obj.map(
|
|
24986
|
+
(item, index) => redactStringsInObject(item, redactFn, `${path}[${index}]`, isProtected)
|
|
24987
|
+
)
|
|
24988
|
+
);
|
|
24989
|
+
}
|
|
24990
|
+
if (obj instanceof Date) {
|
|
24991
|
+
return obj;
|
|
24992
|
+
}
|
|
24993
|
+
if (typeof obj === "object") {
|
|
24994
|
+
const redactedObj = {};
|
|
24995
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
24996
|
+
if (typeof value === "function" || value === void 0) {
|
|
24997
|
+
continue;
|
|
24998
|
+
}
|
|
24999
|
+
const fieldPath = path ? `${path}.${key}` : key;
|
|
25000
|
+
const isFieldProtected = isProtected || path === "" && PROTECTED_FIELDS.has(key);
|
|
25001
|
+
redactedObj[key] = await redactStringsInObject(
|
|
25002
|
+
value,
|
|
25003
|
+
redactFn,
|
|
25004
|
+
fieldPath,
|
|
25005
|
+
isFieldProtected
|
|
25006
|
+
);
|
|
25007
|
+
}
|
|
25008
|
+
return redactedObj;
|
|
25009
|
+
}
|
|
25010
|
+
return obj;
|
|
25011
|
+
}
|
|
25012
|
+
async function redactEvent(event, redactFn) {
|
|
25013
|
+
return redactStringsInObject(event, redactFn, "", false);
|
|
25014
|
+
}
|
|
25015
|
+
var BASE64_PATTERN = /^[A-Za-z0-9+/\n\r]+=*$/;
|
|
25016
|
+
var SIZE_GATE = 10240;
|
|
25017
|
+
function sanitizeEvent(event) {
|
|
25018
|
+
const result = { ...event };
|
|
25019
|
+
if (result.response != null) {
|
|
25020
|
+
result.response = sanitizeResponse(result.response);
|
|
25021
|
+
}
|
|
25022
|
+
if (result.parameters != null) {
|
|
25023
|
+
result.parameters = sanitizeParameters(result.parameters);
|
|
25024
|
+
}
|
|
25025
|
+
return result;
|
|
25026
|
+
}
|
|
25027
|
+
function sanitizeResponse(response) {
|
|
25028
|
+
if (response == null || typeof response !== "object") {
|
|
25029
|
+
return response;
|
|
25030
|
+
}
|
|
25031
|
+
const result = { ...response };
|
|
25032
|
+
if (Array.isArray(result.content)) {
|
|
25033
|
+
result.content = result.content.map(sanitizeContentBlock);
|
|
25034
|
+
}
|
|
25035
|
+
if (result.structuredContent != null && typeof result.structuredContent === "object") {
|
|
25036
|
+
result.structuredContent = sanitizeParameters(result.structuredContent);
|
|
25037
|
+
}
|
|
25038
|
+
return result;
|
|
25039
|
+
}
|
|
25040
|
+
function sanitizeContentBlock(block) {
|
|
25041
|
+
if (block == null || typeof block !== "object") {
|
|
25042
|
+
return block;
|
|
25043
|
+
}
|
|
25044
|
+
switch (block.type) {
|
|
25045
|
+
case "text":
|
|
25046
|
+
return block;
|
|
25047
|
+
case "image":
|
|
25048
|
+
return {
|
|
25049
|
+
type: "text",
|
|
25050
|
+
text: "[image content redacted - not supported by MCPcat]"
|
|
25051
|
+
};
|
|
25052
|
+
case "audio":
|
|
25053
|
+
return {
|
|
25054
|
+
type: "text",
|
|
25055
|
+
text: "[audio content redacted - not supported by MCPcat]"
|
|
25056
|
+
};
|
|
25057
|
+
case "resource":
|
|
25058
|
+
return sanitizeResourceBlock(block);
|
|
25059
|
+
case "resource_link":
|
|
25060
|
+
return block;
|
|
25061
|
+
default:
|
|
25062
|
+
return {
|
|
25063
|
+
type: "text",
|
|
25064
|
+
text: `[unsupported content type "${block.type}" redacted - not supported by MCPcat]`
|
|
25065
|
+
};
|
|
25066
|
+
}
|
|
25067
|
+
}
|
|
25068
|
+
function sanitizeResourceBlock(block) {
|
|
25069
|
+
if (block.resource && block.resource.blob !== void 0) {
|
|
25070
|
+
return {
|
|
25071
|
+
type: "text",
|
|
25072
|
+
text: "[binary resource content redacted - not supported by MCPcat]"
|
|
25073
|
+
};
|
|
25074
|
+
}
|
|
25075
|
+
return block;
|
|
25076
|
+
}
|
|
25077
|
+
function sanitizeParameters(obj) {
|
|
25078
|
+
if (obj == null) {
|
|
25079
|
+
return obj;
|
|
25080
|
+
}
|
|
25081
|
+
if (typeof obj === "string") {
|
|
25082
|
+
if (obj.length >= SIZE_GATE && BASE64_PATTERN.test(obj)) {
|
|
25083
|
+
return "[binary data redacted - not supported by MCPcat]";
|
|
25084
|
+
}
|
|
25085
|
+
return obj;
|
|
25086
|
+
}
|
|
25087
|
+
if (Array.isArray(obj)) {
|
|
25088
|
+
return obj.map(sanitizeParameters);
|
|
25089
|
+
}
|
|
25090
|
+
if (obj instanceof Date) {
|
|
25091
|
+
return obj;
|
|
25092
|
+
}
|
|
25093
|
+
if (typeof obj === "object") {
|
|
25094
|
+
const result = {};
|
|
25095
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
25096
|
+
result[key] = sanitizeParameters(value);
|
|
25097
|
+
}
|
|
25098
|
+
return result;
|
|
25099
|
+
}
|
|
25100
|
+
return obj;
|
|
25101
|
+
}
|
|
25102
|
+
var MAX_DEPTH = 10;
|
|
25103
|
+
var MAX_BREADTH = 100;
|
|
25104
|
+
var MAX_STRING_LENGTH = 32768;
|
|
25105
|
+
var MAX_EVENT_BYTES = 102400;
|
|
25106
|
+
var MAX_USER_INTENT_LENGTH = 2048;
|
|
25107
|
+
var MAX_ERROR_MESSAGE_LENGTH = 2048;
|
|
25108
|
+
var MAX_RESOURCE_NAME_LENGTH = 256;
|
|
25109
|
+
var MAX_METADATA_LENGTH = 256;
|
|
25110
|
+
var MAX_STACK_FRAMES = 50;
|
|
25111
|
+
var MAX_CONTENT_TEXT_LENGTH = 32768;
|
|
25112
|
+
var TRUNCATION_SUFFIX = "...";
|
|
25113
|
+
function normalize(input, depth = MAX_DEPTH, maxBreadth = MAX_BREADTH, maxStringLength = MAX_STRING_LENGTH) {
|
|
25114
|
+
const memo = /* @__PURE__ */ new WeakSet();
|
|
25115
|
+
return visit(input, depth, maxBreadth, maxStringLength, memo);
|
|
25116
|
+
}
|
|
25117
|
+
function visit(value, remainingDepth, maxBreadth, maxStringLength, memo) {
|
|
25118
|
+
if (value === null) return null;
|
|
25119
|
+
if (value === void 0) return "[undefined]";
|
|
25120
|
+
if (typeof value === "boolean") return value;
|
|
25121
|
+
if (typeof value === "number") {
|
|
25122
|
+
if (Number.isNaN(value)) return "[NaN]";
|
|
25123
|
+
if (!Number.isFinite(value))
|
|
25124
|
+
return value > 0 ? "[Infinity]" : "[-Infinity]";
|
|
25125
|
+
return value;
|
|
25126
|
+
}
|
|
25127
|
+
if (typeof value === "bigint") return `[BigInt: ${value}]`;
|
|
25128
|
+
if (typeof value === "string") {
|
|
25129
|
+
if (value.length > maxStringLength) {
|
|
25130
|
+
return value.slice(0, maxStringLength) + TRUNCATION_SUFFIX;
|
|
25131
|
+
}
|
|
25132
|
+
return value;
|
|
25133
|
+
}
|
|
25134
|
+
if (typeof value === "symbol") {
|
|
25135
|
+
const desc = value.description;
|
|
25136
|
+
return desc ? `[Symbol(${desc})]` : "[Symbol()]";
|
|
25137
|
+
}
|
|
25138
|
+
if (typeof value === "function") {
|
|
25139
|
+
const name = value.name || "<anonymous>";
|
|
25140
|
+
return `[Function: ${name}]`;
|
|
25141
|
+
}
|
|
25142
|
+
if (value instanceof Date) {
|
|
25143
|
+
return Number.isNaN(value.getTime()) ? "[Invalid Date]" : value.toISOString();
|
|
25144
|
+
}
|
|
25145
|
+
if (typeof value === "object") {
|
|
25146
|
+
if (memo.has(value)) return "[Circular ~]";
|
|
25147
|
+
if (remainingDepth <= 0) {
|
|
25148
|
+
return Array.isArray(value) ? "[Array]" : "[Object]";
|
|
25149
|
+
}
|
|
25150
|
+
memo.add(value);
|
|
25151
|
+
let result;
|
|
25152
|
+
if (Array.isArray(value)) {
|
|
25153
|
+
result = visitArray(
|
|
25154
|
+
value,
|
|
25155
|
+
remainingDepth - 1,
|
|
25156
|
+
maxBreadth,
|
|
25157
|
+
maxStringLength,
|
|
25158
|
+
memo
|
|
25159
|
+
);
|
|
25160
|
+
} else {
|
|
25161
|
+
result = visitObject(
|
|
25162
|
+
value,
|
|
25163
|
+
remainingDepth - 1,
|
|
25164
|
+
maxBreadth,
|
|
25165
|
+
maxStringLength,
|
|
25166
|
+
memo
|
|
25167
|
+
);
|
|
25168
|
+
}
|
|
25169
|
+
memo.delete(value);
|
|
25170
|
+
return result;
|
|
25171
|
+
}
|
|
25172
|
+
return String(value);
|
|
25173
|
+
}
|
|
25174
|
+
function visitArray(arr, remainingDepth, maxBreadth, maxStringLength, memo) {
|
|
25175
|
+
const result = [];
|
|
25176
|
+
for (let i = 0; i < arr.length; i++) {
|
|
25177
|
+
if (i >= maxBreadth) {
|
|
25178
|
+
result.push("[MaxProperties ~]");
|
|
25179
|
+
break;
|
|
25180
|
+
}
|
|
25181
|
+
result.push(
|
|
25182
|
+
visit(arr[i], remainingDepth, maxBreadth, maxStringLength, memo)
|
|
25183
|
+
);
|
|
25184
|
+
}
|
|
25185
|
+
return result;
|
|
25186
|
+
}
|
|
25187
|
+
function visitObject(obj, remainingDepth, maxBreadth, maxStringLength, memo) {
|
|
25188
|
+
const result = {};
|
|
25189
|
+
const keys = Object.keys(obj);
|
|
25190
|
+
let count = 0;
|
|
25191
|
+
for (const key of keys) {
|
|
25192
|
+
if (count >= maxBreadth) {
|
|
25193
|
+
result["..."] = "[MaxProperties ~]";
|
|
25194
|
+
break;
|
|
25195
|
+
}
|
|
25196
|
+
if (obj[key] === void 0) continue;
|
|
25197
|
+
result[key] = visit(
|
|
25198
|
+
obj[key],
|
|
25199
|
+
remainingDepth,
|
|
25200
|
+
maxBreadth,
|
|
25201
|
+
maxStringLength,
|
|
25202
|
+
memo
|
|
25203
|
+
);
|
|
25204
|
+
count++;
|
|
25205
|
+
}
|
|
25206
|
+
return result;
|
|
25207
|
+
}
|
|
25208
|
+
function truncateString(str, maxLength2) {
|
|
25209
|
+
if (str == null) return str;
|
|
25210
|
+
if (str.length <= maxLength2) return str;
|
|
25211
|
+
return str.slice(0, maxLength2) + TRUNCATION_SUFFIX;
|
|
25212
|
+
}
|
|
25213
|
+
function truncateStackFrames(frames) {
|
|
25214
|
+
if (!frames || frames.length <= MAX_STACK_FRAMES) return frames;
|
|
25215
|
+
const half = Math.floor(MAX_STACK_FRAMES / 2);
|
|
25216
|
+
return [...frames.slice(0, half), ...frames.slice(-half)];
|
|
25217
|
+
}
|
|
25218
|
+
function truncateResponseContent(response) {
|
|
25219
|
+
if (response == null || typeof response !== "object") return response;
|
|
25220
|
+
const result = { ...response };
|
|
25221
|
+
if (Array.isArray(result.content)) {
|
|
25222
|
+
result.content = result.content.map((block) => {
|
|
25223
|
+
if (block?.type === "text" && typeof block.text === "string" && block.text.length > MAX_CONTENT_TEXT_LENGTH) {
|
|
25224
|
+
return {
|
|
25225
|
+
...block,
|
|
25226
|
+
text: block.text.slice(0, MAX_CONTENT_TEXT_LENGTH) + TRUNCATION_SUFFIX
|
|
25227
|
+
};
|
|
25228
|
+
}
|
|
25229
|
+
return block;
|
|
25230
|
+
});
|
|
25231
|
+
}
|
|
25232
|
+
return result;
|
|
25233
|
+
}
|
|
25234
|
+
var textEncoder = new TextEncoder();
|
|
25235
|
+
function jsonByteSize(value) {
|
|
25236
|
+
return textEncoder.encode(JSON.stringify(value)).length;
|
|
25237
|
+
}
|
|
25238
|
+
function truncateLargestFields(obj, maxBytes) {
|
|
25239
|
+
let result = structuredClone(obj);
|
|
25240
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
25241
|
+
const currentSize = jsonByteSize(result);
|
|
25242
|
+
if (currentSize <= maxBytes) return result;
|
|
25243
|
+
const excess = currentSize - maxBytes;
|
|
25244
|
+
const stringPaths = [];
|
|
25245
|
+
collectStringPaths(result, [], stringPaths);
|
|
25246
|
+
stringPaths.sort((a, b) => b.length - a.length);
|
|
25247
|
+
if (stringPaths.length === 0) break;
|
|
25248
|
+
let remaining = excess + 200;
|
|
25249
|
+
let truncated = false;
|
|
25250
|
+
for (const { path, length } of stringPaths) {
|
|
25251
|
+
if (remaining <= 0) break;
|
|
25252
|
+
const reduction = Math.min(remaining, Math.floor(length * 0.5));
|
|
25253
|
+
if (reduction < 10) continue;
|
|
25254
|
+
const newLength = length - reduction;
|
|
25255
|
+
setNestedValue(
|
|
25256
|
+
result,
|
|
25257
|
+
path,
|
|
25258
|
+
getNestedValue(result, path).slice(0, newLength) + TRUNCATION_SUFFIX
|
|
25259
|
+
);
|
|
25260
|
+
remaining -= reduction;
|
|
25261
|
+
truncated = true;
|
|
25262
|
+
}
|
|
25263
|
+
if (!truncated) break;
|
|
25264
|
+
}
|
|
25265
|
+
return result;
|
|
25266
|
+
}
|
|
25267
|
+
function collectStringPaths(obj, currentPath, results) {
|
|
25268
|
+
if (typeof obj === "string" && obj.length > 100) {
|
|
25269
|
+
results.push({ path: [...currentPath], length: obj.length });
|
|
25270
|
+
return;
|
|
25271
|
+
}
|
|
25272
|
+
if (Array.isArray(obj)) {
|
|
25273
|
+
obj.forEach(
|
|
25274
|
+
(item, i) => collectStringPaths(item, [...currentPath, String(i)], results)
|
|
25275
|
+
);
|
|
25276
|
+
return;
|
|
25277
|
+
}
|
|
25278
|
+
if (obj != null && typeof obj === "object") {
|
|
25279
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
25280
|
+
collectStringPaths(value, [...currentPath, key], results);
|
|
25281
|
+
}
|
|
25282
|
+
}
|
|
25283
|
+
}
|
|
25284
|
+
function getNestedValue(obj, path) {
|
|
25285
|
+
let current = obj;
|
|
25286
|
+
for (const key of path) current = current[key];
|
|
25287
|
+
return current;
|
|
25288
|
+
}
|
|
25289
|
+
function setNestedValue(obj, path, value) {
|
|
25290
|
+
let current = obj;
|
|
25291
|
+
for (let i = 0; i < path.length - 1; i++) current = current[path[i]];
|
|
25292
|
+
current[path[path.length - 1]] = value;
|
|
25293
|
+
}
|
|
25294
|
+
function truncateToSize(event) {
|
|
25295
|
+
if (jsonByteSize(event) <= MAX_EVENT_BYTES) return event;
|
|
25296
|
+
for (let depth = MAX_DEPTH - 1; depth >= 1; depth--) {
|
|
25297
|
+
const reduced = { ...event };
|
|
25298
|
+
if (reduced.parameters != null)
|
|
25299
|
+
reduced.parameters = normalize(reduced.parameters, depth);
|
|
25300
|
+
if (reduced.response != null)
|
|
25301
|
+
reduced.response = normalize(reduced.response, depth);
|
|
25302
|
+
if (reduced.identifyActorData != null)
|
|
25303
|
+
reduced.identifyActorData = normalize(reduced.identifyActorData, depth);
|
|
25304
|
+
if (reduced.error != null) reduced.error = normalize(reduced.error, depth);
|
|
25305
|
+
if (jsonByteSize(reduced) <= MAX_EVENT_BYTES) return reduced;
|
|
25306
|
+
}
|
|
25307
|
+
const minimal = { ...event };
|
|
25308
|
+
if (minimal.parameters != null)
|
|
25309
|
+
minimal.parameters = normalize(minimal.parameters, 1);
|
|
25310
|
+
if (minimal.response != null)
|
|
25311
|
+
minimal.response = normalize(minimal.response, 1);
|
|
25312
|
+
if (minimal.identifyActorData != null)
|
|
25313
|
+
minimal.identifyActorData = normalize(minimal.identifyActorData, 1);
|
|
25314
|
+
if (minimal.error != null) minimal.error = normalize(minimal.error, 1);
|
|
25315
|
+
return truncateLargestFields(minimal, MAX_EVENT_BYTES);
|
|
25316
|
+
}
|
|
25317
|
+
function truncateEvent(event) {
|
|
25318
|
+
const result = { ...event };
|
|
25319
|
+
result.userIntent = truncateString(result.userIntent, MAX_USER_INTENT_LENGTH);
|
|
25320
|
+
result.resourceName = truncateString(
|
|
25321
|
+
result.resourceName,
|
|
25322
|
+
MAX_RESOURCE_NAME_LENGTH
|
|
25323
|
+
);
|
|
25324
|
+
result.serverName = truncateString(result.serverName, MAX_METADATA_LENGTH);
|
|
25325
|
+
result.serverVersion = truncateString(
|
|
25326
|
+
result.serverVersion,
|
|
25327
|
+
MAX_METADATA_LENGTH
|
|
25328
|
+
);
|
|
25329
|
+
result.clientName = truncateString(result.clientName, MAX_METADATA_LENGTH);
|
|
25330
|
+
result.clientVersion = truncateString(
|
|
25331
|
+
result.clientVersion,
|
|
25332
|
+
MAX_METADATA_LENGTH
|
|
25333
|
+
);
|
|
25334
|
+
if (result.error != null && typeof result.error === "object") {
|
|
25335
|
+
result.error = { ...result.error };
|
|
25336
|
+
result.error.message = truncateString(
|
|
25337
|
+
result.error.message,
|
|
25338
|
+
MAX_ERROR_MESSAGE_LENGTH
|
|
25339
|
+
);
|
|
25340
|
+
if (result.error.frames !== void 0) {
|
|
25341
|
+
result.error.frames = truncateStackFrames(result.error.frames);
|
|
25342
|
+
}
|
|
25343
|
+
}
|
|
25344
|
+
result.response = truncateResponseContent(result.response);
|
|
25345
|
+
if (result.parameters != null) {
|
|
25346
|
+
result.parameters = normalize(result.parameters);
|
|
25347
|
+
}
|
|
25348
|
+
if (result.response != null) {
|
|
25349
|
+
result.response = normalize(result.response);
|
|
25350
|
+
}
|
|
25351
|
+
if (result.identifyActorData != null) {
|
|
25352
|
+
result.identifyActorData = normalize(result.identifyActorData);
|
|
25353
|
+
}
|
|
25354
|
+
if (result.error != null) {
|
|
25355
|
+
result.error = normalize(result.error);
|
|
25356
|
+
}
|
|
25357
|
+
return truncateToSize(result);
|
|
25358
|
+
}
|
|
25359
|
+
var EventQueue = class {
|
|
25360
|
+
constructor() {
|
|
25361
|
+
this.queue = [];
|
|
25362
|
+
this.processing = false;
|
|
25363
|
+
this.maxRetries = 3;
|
|
25364
|
+
this.maxQueueSize = 1e4;
|
|
25365
|
+
this.concurrency = 5;
|
|
25366
|
+
this.activeRequests = 0;
|
|
25367
|
+
const config2 = new Configuration({ basePath: "https://api.mcpcat.io" });
|
|
25368
|
+
this.apiClient = new EventsApi(config2);
|
|
25369
|
+
}
|
|
25370
|
+
configure(apiBaseUrl) {
|
|
25371
|
+
const config2 = new Configuration({ basePath: apiBaseUrl });
|
|
25372
|
+
this.apiClient = new EventsApi(config2);
|
|
25373
|
+
}
|
|
25374
|
+
setTelemetryManager(telemetryManager) {
|
|
25375
|
+
this.telemetryManager = telemetryManager;
|
|
25376
|
+
}
|
|
25377
|
+
add(event) {
|
|
25378
|
+
if (this.queue.length >= this.maxQueueSize) {
|
|
25379
|
+
writeToLog("Event queue full, dropping oldest event");
|
|
25380
|
+
this.queue.shift();
|
|
25381
|
+
}
|
|
25382
|
+
this.queue.push(event);
|
|
25383
|
+
this.process();
|
|
25384
|
+
}
|
|
25385
|
+
async process() {
|
|
25386
|
+
if (this.processing) return;
|
|
25387
|
+
this.processing = true;
|
|
25388
|
+
while (this.queue.length > 0 && this.activeRequests < this.concurrency) {
|
|
25389
|
+
const event = this.queue.shift();
|
|
25390
|
+
if (!event) continue;
|
|
25391
|
+
if (event.redactionFn) {
|
|
25392
|
+
try {
|
|
25393
|
+
const redactedEvent = await redactEvent(event, event.redactionFn);
|
|
25394
|
+
event.redactionFn = void 0;
|
|
25395
|
+
Object.assign(event, redactedEvent);
|
|
25396
|
+
} catch (error2) {
|
|
25397
|
+
writeToLog(`Failed to redact event: ${error2}`);
|
|
25398
|
+
continue;
|
|
25399
|
+
}
|
|
25400
|
+
}
|
|
25401
|
+
try {
|
|
25402
|
+
Object.assign(event, sanitizeEvent(event));
|
|
25403
|
+
} catch (error2) {
|
|
25404
|
+
writeToLog(`Failed to sanitize event: ${error2}`);
|
|
25405
|
+
continue;
|
|
25406
|
+
}
|
|
25407
|
+
try {
|
|
25408
|
+
Object.assign(event, truncateEvent(event));
|
|
25409
|
+
} catch (error2) {
|
|
25410
|
+
writeToLog(`Failed to truncate event: ${error2}`);
|
|
25411
|
+
continue;
|
|
25412
|
+
}
|
|
25413
|
+
event.id = event.id || await ksuid_default.withPrefix("evt").random();
|
|
25414
|
+
this.activeRequests++;
|
|
25415
|
+
this.sendEvent(event).finally(() => {
|
|
25416
|
+
this.activeRequests--;
|
|
25417
|
+
this.process();
|
|
25418
|
+
});
|
|
25419
|
+
}
|
|
25420
|
+
this.processing = false;
|
|
25421
|
+
}
|
|
25422
|
+
toPublishEventRequest(event) {
|
|
25423
|
+
return {
|
|
25424
|
+
// Core fields
|
|
25425
|
+
id: event.id,
|
|
25426
|
+
projectId: event.projectId,
|
|
25427
|
+
sessionId: event.sessionId,
|
|
25428
|
+
timestamp: event.timestamp,
|
|
25429
|
+
duration: event.duration,
|
|
25430
|
+
// Event data
|
|
25431
|
+
eventType: event.eventType,
|
|
25432
|
+
resourceName: event.resourceName,
|
|
25433
|
+
parameters: event.parameters,
|
|
25434
|
+
response: event.response,
|
|
25435
|
+
userIntent: event.userIntent,
|
|
25436
|
+
isError: event.isError,
|
|
25437
|
+
error: event.error,
|
|
25438
|
+
// Actor fields
|
|
25439
|
+
identifyActorGivenId: event.identifyActorGivenId,
|
|
25440
|
+
identifyActorName: event.identifyActorName,
|
|
25441
|
+
identifyData: event.identifyActorData,
|
|
25442
|
+
// Session info
|
|
25443
|
+
ipAddress: event.ipAddress,
|
|
25444
|
+
sdkLanguage: event.sdkLanguage,
|
|
25445
|
+
mcpcatVersion: event.mcpcatVersion,
|
|
25446
|
+
serverName: event.serverName,
|
|
25447
|
+
serverVersion: event.serverVersion,
|
|
25448
|
+
clientName: event.clientName,
|
|
25449
|
+
clientVersion: event.clientVersion,
|
|
25450
|
+
// Legacy fields
|
|
25451
|
+
actorId: event.actorId || event.identifyActorGivenId,
|
|
25452
|
+
eventId: event.eventId,
|
|
25453
|
+
// Customer-defined metadata
|
|
25454
|
+
tags: event.tags ?? void 0,
|
|
25455
|
+
properties: event.properties ?? void 0
|
|
25456
|
+
};
|
|
25457
|
+
}
|
|
25458
|
+
async sendEvent(event, retries = 0) {
|
|
25459
|
+
if (this.telemetryManager) {
|
|
25460
|
+
this.telemetryManager.export(event).catch((error2) => {
|
|
25461
|
+
writeToLog(
|
|
25462
|
+
`Telemetry export error: ${getMCPCompatibleErrorMessage(error2)}`
|
|
25463
|
+
);
|
|
25464
|
+
});
|
|
25465
|
+
}
|
|
25466
|
+
if (event.projectId) {
|
|
25467
|
+
try {
|
|
25468
|
+
const publishRequest = this.toPublishEventRequest(event);
|
|
25469
|
+
await this.apiClient.publishEvent({
|
|
25470
|
+
publishEventRequest: publishRequest
|
|
25471
|
+
});
|
|
25472
|
+
writeToLog(
|
|
25473
|
+
`Successfully sent event ${event.id} | ${event.eventType} | ${event.projectId} | ${event.duration} ms | ${event.identifyActorGivenId || "anonymous"}`
|
|
25474
|
+
);
|
|
25475
|
+
writeToLog(`Event details: ${JSON.stringify(event)}`);
|
|
25476
|
+
} catch (error2) {
|
|
25477
|
+
writeToLog(
|
|
25478
|
+
`Failed to send event ${event.id}, retrying... [Error: ${getMCPCompatibleErrorMessage(error2)}]`
|
|
25479
|
+
);
|
|
25480
|
+
if (retries < this.maxRetries) {
|
|
25481
|
+
await this.delay(Math.pow(2, retries) * 1e3);
|
|
25482
|
+
return this.sendEvent(event, retries + 1);
|
|
25483
|
+
}
|
|
25484
|
+
throw error2;
|
|
25485
|
+
}
|
|
25486
|
+
}
|
|
25487
|
+
}
|
|
25488
|
+
delay(ms) {
|
|
25489
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
25490
|
+
}
|
|
25491
|
+
// Get queue stats for monitoring
|
|
25492
|
+
getStats() {
|
|
25493
|
+
return {
|
|
25494
|
+
queueLength: this.queue.length,
|
|
25495
|
+
activeRequests: this.activeRequests,
|
|
25496
|
+
isProcessing: this.processing
|
|
25497
|
+
};
|
|
25498
|
+
}
|
|
25499
|
+
// Graceful shutdown - wait for active requests
|
|
25500
|
+
async destroy() {
|
|
25501
|
+
this.add = () => {
|
|
25502
|
+
writeToLog("Queue is shutting down, event dropped");
|
|
25503
|
+
};
|
|
25504
|
+
const timeout = 5e3;
|
|
25505
|
+
const start = Date.now();
|
|
25506
|
+
while ((this.queue.length > 0 || this.activeRequests > 0) && Date.now() - start < timeout) {
|
|
25507
|
+
await this.delay(100);
|
|
25508
|
+
}
|
|
25509
|
+
if (this.queue.length > 0) {
|
|
25510
|
+
writeToLog(
|
|
25511
|
+
`Shutting down with ${this.queue.length} events still in queue`
|
|
25512
|
+
);
|
|
25513
|
+
}
|
|
25514
|
+
}
|
|
25515
|
+
};
|
|
25516
|
+
var eventQueue = new EventQueue();
|
|
25517
|
+
try {
|
|
25518
|
+
if (typeof process !== "undefined" && typeof process.once === "function") {
|
|
25519
|
+
process.once("SIGINT", () => eventQueue.destroy());
|
|
25520
|
+
process.once("SIGTERM", () => eventQueue.destroy());
|
|
25521
|
+
process.once("beforeExit", () => eventQueue.destroy());
|
|
25522
|
+
}
|
|
25523
|
+
} catch {
|
|
25524
|
+
}
|
|
25525
|
+
function setTelemetryManager(telemetryManager) {
|
|
25526
|
+
eventQueue.setTelemetryManager(telemetryManager);
|
|
25527
|
+
}
|
|
25528
|
+
function publishEvent(server, eventInput) {
|
|
25529
|
+
const data = getServerTrackingData(server);
|
|
25530
|
+
if (!data) {
|
|
25531
|
+
writeToLog(
|
|
25532
|
+
"Warning: Server tracking data not found. Event will not be published."
|
|
25533
|
+
);
|
|
25534
|
+
return;
|
|
25535
|
+
}
|
|
25536
|
+
if (!data.options.enableTracing) {
|
|
25537
|
+
return;
|
|
25538
|
+
}
|
|
25539
|
+
const sessionInfo = getSessionInfo(server, data);
|
|
25540
|
+
const duration3 = eventInput.duration || (eventInput.timestamp ? (/* @__PURE__ */ new Date()).getTime() - eventInput.timestamp.getTime() : void 0);
|
|
25541
|
+
const fullEvent = {
|
|
25542
|
+
// Core fields (id will be generated later in the queue)
|
|
25543
|
+
id: eventInput.id || "",
|
|
25544
|
+
sessionId: eventInput.sessionId || data.sessionId,
|
|
25545
|
+
projectId: data.projectId,
|
|
25546
|
+
// Event metadata
|
|
25547
|
+
eventType: eventInput.eventType || "",
|
|
25548
|
+
timestamp: eventInput.timestamp || /* @__PURE__ */ new Date(),
|
|
25549
|
+
duration: duration3,
|
|
25550
|
+
// Session context from sessionInfo
|
|
25551
|
+
ipAddress: sessionInfo.ipAddress,
|
|
25552
|
+
sdkLanguage: sessionInfo.sdkLanguage,
|
|
25553
|
+
mcpcatVersion: sessionInfo.mcpcatVersion,
|
|
25554
|
+
serverName: sessionInfo.serverName,
|
|
25555
|
+
serverVersion: sessionInfo.serverVersion,
|
|
25556
|
+
clientName: sessionInfo.clientName,
|
|
25557
|
+
clientVersion: sessionInfo.clientVersion,
|
|
25558
|
+
// Actor information from sessionInfo
|
|
25559
|
+
identifyActorGivenId: sessionInfo.identifyActorGivenId,
|
|
25560
|
+
identifyActorName: sessionInfo.identifyActorName,
|
|
25561
|
+
identifyActorData: sessionInfo.identifyActorData,
|
|
25562
|
+
// Event-specific data from input
|
|
25563
|
+
resourceName: eventInput.resourceName,
|
|
25564
|
+
parameters: eventInput.parameters,
|
|
25565
|
+
response: eventInput.response,
|
|
25566
|
+
userIntent: eventInput.userIntent,
|
|
25567
|
+
isError: eventInput.isError,
|
|
25568
|
+
error: eventInput.error,
|
|
25569
|
+
// Preserve redaction function
|
|
25570
|
+
redactionFn: eventInput.redactionFn,
|
|
25571
|
+
// Customer-defined metadata
|
|
25572
|
+
tags: eventInput.tags,
|
|
25573
|
+
properties: eventInput.properties
|
|
25574
|
+
};
|
|
25575
|
+
eventQueue.add(fullEvent);
|
|
25576
|
+
}
|
|
25577
|
+
var TAG_KEY_REGEX = /^[a-zA-Z0-9$_.:\- ]+$/;
|
|
25578
|
+
var MAX_TAG_KEY_LENGTH = 32;
|
|
25579
|
+
var MAX_TAG_VALUE_LENGTH = 200;
|
|
25580
|
+
var MAX_TAG_ENTRIES = 50;
|
|
25581
|
+
function validateTags(tags) {
|
|
25582
|
+
const entries = Object.entries(tags);
|
|
25583
|
+
if (entries.length === 0) {
|
|
25584
|
+
return null;
|
|
25585
|
+
}
|
|
25586
|
+
const valid = [];
|
|
25587
|
+
for (const [key, value] of entries) {
|
|
25588
|
+
if (typeof key !== "string" || !TAG_KEY_REGEX.test(key)) {
|
|
25589
|
+
writeToLog(
|
|
25590
|
+
`Dropping invalid tag: "${String(key)}" \u2014 key contains invalid characters or is empty`
|
|
25591
|
+
);
|
|
25592
|
+
continue;
|
|
25593
|
+
}
|
|
25594
|
+
if (key.length > MAX_TAG_KEY_LENGTH) {
|
|
25595
|
+
writeToLog(
|
|
25596
|
+
`Dropping invalid tag: "${key}" \u2014 key exceeds max length of ${MAX_TAG_KEY_LENGTH}`
|
|
25597
|
+
);
|
|
25598
|
+
continue;
|
|
25599
|
+
}
|
|
25600
|
+
if (typeof value !== "string") {
|
|
25601
|
+
writeToLog(
|
|
25602
|
+
`Dropping invalid tag: "${key}" \u2014 non-string value (got ${typeof value})`
|
|
25603
|
+
);
|
|
25604
|
+
continue;
|
|
25605
|
+
}
|
|
25606
|
+
if (value.length > MAX_TAG_VALUE_LENGTH) {
|
|
25607
|
+
writeToLog(
|
|
25608
|
+
`Dropping invalid tag: "${key}" \u2014 value exceeds max length of ${MAX_TAG_VALUE_LENGTH}`
|
|
25609
|
+
);
|
|
25610
|
+
continue;
|
|
25611
|
+
}
|
|
25612
|
+
if (value.includes("\n")) {
|
|
25613
|
+
writeToLog(
|
|
25614
|
+
`Dropping invalid tag: "${key}" \u2014 value contains newline character`
|
|
25615
|
+
);
|
|
25616
|
+
continue;
|
|
25617
|
+
}
|
|
25618
|
+
valid.push([key, value]);
|
|
25619
|
+
}
|
|
25620
|
+
if (valid.length === 0) {
|
|
25621
|
+
return null;
|
|
25622
|
+
}
|
|
25623
|
+
if (valid.length > MAX_TAG_ENTRIES) {
|
|
25624
|
+
const dropped = valid.length - MAX_TAG_ENTRIES;
|
|
25625
|
+
writeToLog(
|
|
25626
|
+
`Dropping ${dropped} tag(s) \u2014 exceeds maximum of ${MAX_TAG_ENTRIES} entries per event`
|
|
25627
|
+
);
|
|
25628
|
+
valid.length = MAX_TAG_ENTRIES;
|
|
25629
|
+
}
|
|
25630
|
+
return Object.fromEntries(valid);
|
|
25631
|
+
}
|
|
25632
|
+
var IdentityCache = class {
|
|
25633
|
+
constructor(maxSize = 1e3) {
|
|
25634
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
25635
|
+
this.maxSize = maxSize;
|
|
25636
|
+
}
|
|
25637
|
+
get(sessionId) {
|
|
25638
|
+
const entry = this.cache.get(sessionId);
|
|
25639
|
+
if (entry) {
|
|
25640
|
+
entry.timestamp = Date.now();
|
|
25641
|
+
this.cache.delete(sessionId);
|
|
25642
|
+
this.cache.set(sessionId, entry);
|
|
25643
|
+
return entry.identity;
|
|
25644
|
+
}
|
|
25645
|
+
return void 0;
|
|
25646
|
+
}
|
|
25647
|
+
set(sessionId, identity) {
|
|
25648
|
+
this.cache.delete(sessionId);
|
|
25649
|
+
if (this.cache.size >= this.maxSize) {
|
|
25650
|
+
const oldestKey = this.cache.keys().next().value;
|
|
25651
|
+
if (oldestKey !== void 0) {
|
|
25652
|
+
this.cache.delete(oldestKey);
|
|
25653
|
+
}
|
|
25654
|
+
}
|
|
25655
|
+
this.cache.set(sessionId, { identity, timestamp: Date.now() });
|
|
25656
|
+
}
|
|
25657
|
+
has(sessionId) {
|
|
25658
|
+
return this.cache.has(sessionId);
|
|
25659
|
+
}
|
|
25660
|
+
size() {
|
|
25661
|
+
return this.cache.size;
|
|
25662
|
+
}
|
|
25663
|
+
};
|
|
25664
|
+
var _globalIdentityCache = new IdentityCache(1e3);
|
|
25665
|
+
var _serverTracking = /* @__PURE__ */ new WeakMap();
|
|
25666
|
+
function getServerTrackingData(server) {
|
|
25667
|
+
return _serverTracking.get(server);
|
|
25668
|
+
}
|
|
25669
|
+
function setServerTrackingData(server, data) {
|
|
25670
|
+
_serverTracking.set(server, data);
|
|
25671
|
+
}
|
|
25672
|
+
function areIdentitiesEqual(a, b) {
|
|
25673
|
+
if (a.userId !== b.userId) return false;
|
|
25674
|
+
if (a.userName !== b.userName) return false;
|
|
25675
|
+
const aData = a.userData || {};
|
|
25676
|
+
const bData = b.userData || {};
|
|
25677
|
+
const aKeys = Object.keys(aData);
|
|
25678
|
+
const bKeys = Object.keys(bData);
|
|
25679
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
25680
|
+
for (const key of aKeys) {
|
|
25681
|
+
if (!(key in bData)) return false;
|
|
25682
|
+
if (JSON.stringify(aData[key]) !== JSON.stringify(bData[key])) return false;
|
|
25683
|
+
}
|
|
25684
|
+
return true;
|
|
25685
|
+
}
|
|
25686
|
+
function mergeIdentities(previous, next) {
|
|
25687
|
+
if (!previous) {
|
|
25688
|
+
return next;
|
|
25689
|
+
}
|
|
25690
|
+
return {
|
|
25691
|
+
userId: next.userId,
|
|
25692
|
+
userName: next.userName,
|
|
25693
|
+
userData: {
|
|
25694
|
+
...previous.userData || {},
|
|
25695
|
+
...next.userData || {}
|
|
25696
|
+
}
|
|
25697
|
+
};
|
|
25698
|
+
}
|
|
25699
|
+
async function handleIdentify(server, data, request, extra) {
|
|
25700
|
+
if (!data.options.identify) {
|
|
25701
|
+
return;
|
|
25702
|
+
}
|
|
25703
|
+
const sessionId = data.sessionId;
|
|
25704
|
+
let identifyEvent = {
|
|
25705
|
+
sessionId,
|
|
25706
|
+
resourceName: request.params?.name || "Unknown",
|
|
25707
|
+
eventType: PublishEventRequestEventTypeEnum.mcpcatIdentify,
|
|
25708
|
+
parameters: {
|
|
25709
|
+
request,
|
|
25710
|
+
extra
|
|
25711
|
+
},
|
|
25712
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
25713
|
+
redactionFn: data.options.redactSensitiveInformation
|
|
25714
|
+
};
|
|
25715
|
+
try {
|
|
25716
|
+
const identityResult = await data.options.identify(request, extra);
|
|
25717
|
+
if (identityResult) {
|
|
25718
|
+
const currentSessionId = data.sessionId;
|
|
25719
|
+
const previousIdentity = _globalIdentityCache.get(currentSessionId);
|
|
25720
|
+
const mergedIdentity = mergeIdentities(previousIdentity, identityResult);
|
|
25721
|
+
const hasChanged = !previousIdentity || !areIdentitiesEqual(previousIdentity, mergedIdentity);
|
|
25722
|
+
_globalIdentityCache.set(currentSessionId, mergedIdentity);
|
|
25723
|
+
data.identifiedSessions.set(data.sessionId, mergedIdentity);
|
|
25724
|
+
if (hasChanged) {
|
|
25725
|
+
writeToLog(
|
|
25726
|
+
`Identified session ${currentSessionId} with identity: ${JSON.stringify(mergedIdentity)}`
|
|
25727
|
+
);
|
|
25728
|
+
publishEvent(server, identifyEvent);
|
|
25729
|
+
}
|
|
25730
|
+
} else {
|
|
25731
|
+
writeToLog(
|
|
25732
|
+
`Warning: Supplied identify function returned null for session ${sessionId}`
|
|
25733
|
+
);
|
|
25734
|
+
}
|
|
25735
|
+
} catch (error2) {
|
|
25736
|
+
writeToLog(
|
|
25737
|
+
`Error: User supplied identify function threw an error while identifying session ${sessionId} - ${error2}`
|
|
25738
|
+
);
|
|
25739
|
+
}
|
|
25740
|
+
}
|
|
25741
|
+
async function resolveEventTags(data, request, extra) {
|
|
25742
|
+
if (!data.options.eventTags) return null;
|
|
25743
|
+
try {
|
|
25744
|
+
const raw = await data.options.eventTags(request, extra) ?? null;
|
|
25745
|
+
if (!raw) return null;
|
|
25746
|
+
return validateTags(raw);
|
|
25747
|
+
} catch (e) {
|
|
25748
|
+
writeToLog(`eventTags callback error: ${e}`);
|
|
25749
|
+
return null;
|
|
25750
|
+
}
|
|
25751
|
+
}
|
|
25752
|
+
async function resolveEventProperties(data, request, extra) {
|
|
25753
|
+
if (!data.options.eventProperties) return null;
|
|
25754
|
+
try {
|
|
25755
|
+
return await data.options.eventProperties(request, extra) ?? null;
|
|
25756
|
+
} catch (e) {
|
|
25757
|
+
writeToLog(`eventProperties callback error: ${e}`);
|
|
25758
|
+
return null;
|
|
25759
|
+
}
|
|
25760
|
+
}
|
|
25761
|
+
function addContextParameterToTool(tool, customContextDescription) {
|
|
25762
|
+
const modifiedTool = { ...tool };
|
|
25763
|
+
const toolName = tool.name || "unknown";
|
|
25764
|
+
const schema = modifiedTool.inputSchema;
|
|
25765
|
+
if (schema?.properties?.context) {
|
|
25766
|
+
writeToLog(
|
|
25767
|
+
`WARN: Tool "${toolName}" already has 'context' parameter. Skipping context injection.`
|
|
25768
|
+
);
|
|
25769
|
+
return modifiedTool;
|
|
25770
|
+
}
|
|
25771
|
+
if (schema?.oneOf || schema?.allOf || schema?.anyOf) {
|
|
25772
|
+
writeToLog(
|
|
25773
|
+
`WARN: Tool "${toolName}" has complex schema (oneOf/allOf/anyOf). Skipping context injection.`
|
|
25774
|
+
);
|
|
25775
|
+
return modifiedTool;
|
|
25776
|
+
}
|
|
25777
|
+
if (!modifiedTool.inputSchema) {
|
|
25778
|
+
modifiedTool.inputSchema = {
|
|
25779
|
+
type: "object",
|
|
25780
|
+
properties: {},
|
|
25781
|
+
required: []
|
|
25782
|
+
};
|
|
25783
|
+
}
|
|
25784
|
+
const contextDescription = customContextDescription || DEFAULT_CONTEXT_PARAMETER_DESCRIPTION;
|
|
25785
|
+
modifiedTool.inputSchema = JSON.parse(
|
|
25786
|
+
JSON.stringify(modifiedTool.inputSchema)
|
|
25787
|
+
);
|
|
25788
|
+
if (!modifiedTool.inputSchema.properties) {
|
|
25789
|
+
modifiedTool.inputSchema.properties = {};
|
|
25790
|
+
}
|
|
25791
|
+
if (modifiedTool.inputSchema.additionalProperties === false) {
|
|
25792
|
+
delete modifiedTool.inputSchema.additionalProperties;
|
|
25793
|
+
}
|
|
25794
|
+
modifiedTool.inputSchema.properties.context = {
|
|
25795
|
+
type: "string",
|
|
25796
|
+
description: contextDescription
|
|
25797
|
+
};
|
|
25798
|
+
if (Array.isArray(modifiedTool.inputSchema.required)) {
|
|
25799
|
+
if (!modifiedTool.inputSchema.required.includes("context")) {
|
|
25800
|
+
modifiedTool.inputSchema.required.push("context");
|
|
25801
|
+
}
|
|
25802
|
+
} else {
|
|
25803
|
+
modifiedTool.inputSchema.required = ["context"];
|
|
25804
|
+
}
|
|
25805
|
+
return modifiedTool;
|
|
25806
|
+
}
|
|
25807
|
+
function addContextParameterToTools(tools, customContextDescription) {
|
|
25808
|
+
return tools.map((tool) => {
|
|
25809
|
+
if (tool.name === "get_more_tools") {
|
|
25810
|
+
return tool;
|
|
25811
|
+
}
|
|
25812
|
+
return addContextParameterToTool(tool, customContextDescription);
|
|
25813
|
+
});
|
|
25814
|
+
}
|
|
25815
|
+
var GET_MORE_TOOLS_NAME = "get_more_tools";
|
|
25816
|
+
function getReportMissingToolDescriptor() {
|
|
25817
|
+
return {
|
|
25818
|
+
name: GET_MORE_TOOLS_NAME,
|
|
25819
|
+
description: "Check for additional tools whenever your task might benefit from specialized capabilities - even if existing tools could work as a fallback.",
|
|
25820
|
+
inputSchema: {
|
|
25821
|
+
type: "object",
|
|
25822
|
+
properties: {
|
|
25823
|
+
context: {
|
|
25824
|
+
type: "string",
|
|
25825
|
+
description: "A description of your goal and what kind of tool would help accomplish it."
|
|
25826
|
+
}
|
|
25827
|
+
},
|
|
25828
|
+
required: ["context"]
|
|
25829
|
+
}
|
|
25830
|
+
};
|
|
25831
|
+
}
|
|
25832
|
+
function handleReportMissing(args) {
|
|
25833
|
+
writeToLog(`Missing tool reported: ${JSON.stringify(args)}`);
|
|
25834
|
+
return {
|
|
25835
|
+
content: [
|
|
25836
|
+
{
|
|
25837
|
+
type: "text",
|
|
25838
|
+
text: `Unfortunately, we have shown you the full tool list. We have noted your feedback and will work to improve the tool list in the future.`
|
|
25839
|
+
}
|
|
25840
|
+
]
|
|
25841
|
+
};
|
|
25842
|
+
}
|
|
25843
|
+
function setupMCPCatTools(server) {
|
|
25844
|
+
const handlers = server._requestHandlers;
|
|
25845
|
+
const originalListToolsHandler = handlers.get("tools/list");
|
|
25846
|
+
const originalCallToolHandler = handlers.get("tools/call");
|
|
25847
|
+
if (!originalListToolsHandler || !originalCallToolHandler) {
|
|
25848
|
+
writeToLog(
|
|
25849
|
+
"Warning: Original tool handlers not found. Your tools may not be setup before MCPCat .track()."
|
|
25850
|
+
);
|
|
25851
|
+
return;
|
|
25852
|
+
}
|
|
25853
|
+
try {
|
|
25854
|
+
server.setRequestHandler(ListToolsRequestSchema, async (request, extra) => {
|
|
25855
|
+
let tools = [];
|
|
25856
|
+
const data = getServerTrackingData(server);
|
|
25857
|
+
let event = {
|
|
25858
|
+
sessionId: getServerSessionId(server, extra),
|
|
25859
|
+
parameters: {
|
|
25860
|
+
request,
|
|
25861
|
+
extra
|
|
25862
|
+
},
|
|
25863
|
+
eventType: PublishEventRequestEventTypeEnum.mcpToolsList,
|
|
25864
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
25865
|
+
redactionFn: data?.options.redactSensitiveInformation
|
|
25866
|
+
};
|
|
25867
|
+
try {
|
|
25868
|
+
const originalResponse = await originalListToolsHandler(
|
|
25869
|
+
request,
|
|
25870
|
+
extra
|
|
25871
|
+
);
|
|
25872
|
+
tools = originalResponse.tools || [];
|
|
25873
|
+
} catch (error2) {
|
|
25874
|
+
writeToLog(
|
|
25875
|
+
`Warning: Original list tools handler failed, this suggests an error MCPCat did not cause - ${error2}`
|
|
25876
|
+
);
|
|
25877
|
+
event.error = { message: getMCPCompatibleErrorMessage(error2) };
|
|
25878
|
+
event.isError = true;
|
|
25879
|
+
event.duration = event.timestamp && (/* @__PURE__ */ new Date()).getTime() - event.timestamp.getTime() || 0;
|
|
25880
|
+
publishEvent(server, event);
|
|
25881
|
+
throw error2;
|
|
25882
|
+
}
|
|
25883
|
+
if (!data) {
|
|
25884
|
+
writeToLog(
|
|
25885
|
+
"Warning: MCPCat is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls."
|
|
25886
|
+
);
|
|
25887
|
+
return { tools };
|
|
25888
|
+
}
|
|
25889
|
+
if (tools.length === 0) {
|
|
25890
|
+
writeToLog(
|
|
25891
|
+
"Warning: No tools found in the original list. This is likely due to the tools not being registered before MCPCat.track()."
|
|
25892
|
+
);
|
|
25893
|
+
event.error = { message: "No tools were sent to MCP client." };
|
|
25894
|
+
event.isError = true;
|
|
25895
|
+
event.duration = event.timestamp && (/* @__PURE__ */ new Date()).getTime() - event.timestamp.getTime() || 0;
|
|
25896
|
+
publishEvent(server, event);
|
|
25897
|
+
return { tools };
|
|
25898
|
+
}
|
|
25899
|
+
if (data.options.enableToolCallContext) {
|
|
25900
|
+
tools = addContextParameterToTools(
|
|
25901
|
+
tools,
|
|
25902
|
+
data.options.customContextDescription
|
|
25903
|
+
);
|
|
25904
|
+
}
|
|
25905
|
+
if (data.options.enableReportMissing) {
|
|
25906
|
+
const alreadyPresent = tools.some(
|
|
25907
|
+
(t) => t?.name === GET_MORE_TOOLS_NAME
|
|
25908
|
+
);
|
|
25909
|
+
if (!alreadyPresent) {
|
|
25910
|
+
tools.push(getReportMissingToolDescriptor());
|
|
25911
|
+
}
|
|
25912
|
+
}
|
|
25913
|
+
event.response = { tools };
|
|
25914
|
+
event.isError = false;
|
|
25915
|
+
event.duration = event.timestamp && (/* @__PURE__ */ new Date()).getTime() - event.timestamp.getTime() || 0;
|
|
25916
|
+
publishEvent(server, event);
|
|
25917
|
+
return { tools };
|
|
25918
|
+
});
|
|
25919
|
+
} catch (error2) {
|
|
25920
|
+
writeToLog(`Warning: Failed to override list tools handler - ${error2}`);
|
|
25921
|
+
}
|
|
25922
|
+
}
|
|
25923
|
+
var fsModule2 = null;
|
|
25924
|
+
var fsInitAttempted = false;
|
|
25925
|
+
function getFsSync() {
|
|
25926
|
+
if (!fsInitAttempted) {
|
|
25927
|
+
fsInitAttempted = true;
|
|
25928
|
+
try {
|
|
25929
|
+
const require2 = createRequire2(import.meta.url);
|
|
25930
|
+
fsModule2 = require2("fs");
|
|
25931
|
+
} catch {
|
|
25932
|
+
fsModule2 = null;
|
|
25933
|
+
}
|
|
25934
|
+
}
|
|
25935
|
+
return fsModule2;
|
|
25936
|
+
}
|
|
25937
|
+
var MAX_EXCEPTION_CHAIN_DEPTH = 10;
|
|
25938
|
+
var MAX_STACK_FRAMES2 = 50;
|
|
25939
|
+
function captureException(error2, contextStack) {
|
|
25940
|
+
if (isCallToolResult(error2)) {
|
|
25941
|
+
return captureCallToolResultError(error2, contextStack);
|
|
25942
|
+
}
|
|
25943
|
+
if (!(error2 instanceof Error)) {
|
|
25944
|
+
return {
|
|
25945
|
+
message: stringifyNonError(error2),
|
|
25946
|
+
type: void 0,
|
|
25947
|
+
platform: "javascript"
|
|
25948
|
+
};
|
|
25949
|
+
}
|
|
25950
|
+
const errorData = {
|
|
25951
|
+
message: error2.message || "",
|
|
25952
|
+
type: error2.name || error2.constructor?.name || void 0,
|
|
25953
|
+
platform: "javascript"
|
|
25954
|
+
};
|
|
25955
|
+
if (error2.stack) {
|
|
25956
|
+
errorData.stack = error2.stack;
|
|
25957
|
+
errorData.frames = parseV8StackTrace(error2.stack);
|
|
25958
|
+
}
|
|
25959
|
+
const chainedErrors = unwrapErrorCauses(error2);
|
|
25960
|
+
if (chainedErrors.length > 0) {
|
|
25961
|
+
errorData.chained_errors = chainedErrors;
|
|
25962
|
+
}
|
|
25963
|
+
return errorData;
|
|
25964
|
+
}
|
|
25965
|
+
function parseV8StackTrace(stackTrace) {
|
|
25966
|
+
const frames = [];
|
|
25967
|
+
const lines = stackTrace.split("\n");
|
|
25968
|
+
for (const line of lines) {
|
|
25969
|
+
if (!line.trim().startsWith("at ")) {
|
|
25970
|
+
continue;
|
|
25971
|
+
}
|
|
25972
|
+
const frame = parseV8StackFrame(line.trim());
|
|
25973
|
+
if (frame) {
|
|
25974
|
+
addContextToFrame(frame);
|
|
25975
|
+
frames.push(frame);
|
|
25976
|
+
}
|
|
25977
|
+
if (frames.length >= MAX_STACK_FRAMES2) {
|
|
25978
|
+
break;
|
|
25979
|
+
}
|
|
25980
|
+
}
|
|
25981
|
+
return frames;
|
|
25982
|
+
}
|
|
25983
|
+
function addContextToFrame(frame) {
|
|
25984
|
+
if (!frame.in_app || !frame.abs_path || !frame.lineno) {
|
|
25985
|
+
return frame;
|
|
25986
|
+
}
|
|
25987
|
+
const fs = getFsSync();
|
|
25988
|
+
if (!fs) {
|
|
25989
|
+
return frame;
|
|
25990
|
+
}
|
|
25991
|
+
try {
|
|
25992
|
+
const source = fs.readFileSync(frame.abs_path, "utf8");
|
|
25993
|
+
const lines = source.split("\n");
|
|
25994
|
+
const lineIndex = frame.lineno - 1;
|
|
25995
|
+
if (lineIndex >= 0 && lineIndex < lines.length) {
|
|
25996
|
+
frame.context_line = lines[lineIndex];
|
|
25997
|
+
}
|
|
25998
|
+
} catch {
|
|
25999
|
+
}
|
|
26000
|
+
return frame;
|
|
26001
|
+
}
|
|
26002
|
+
function parseLocation(location) {
|
|
26003
|
+
if (location === "native") {
|
|
26004
|
+
return { filename: "native", abs_path: "native" };
|
|
26005
|
+
}
|
|
26006
|
+
if (location === "unknown location") {
|
|
26007
|
+
return { filename: "<unknown>", abs_path: "<unknown>" };
|
|
26008
|
+
}
|
|
26009
|
+
if (location.startsWith("eval at ")) {
|
|
26010
|
+
return parseEvalOrigin(location);
|
|
26011
|
+
}
|
|
26012
|
+
const match = location.match(/^(.+):(\d+):(\d+)$/);
|
|
26013
|
+
if (match) {
|
|
26014
|
+
const [, filename, lineStr, colStr] = match;
|
|
26015
|
+
return {
|
|
26016
|
+
filename: makeRelativePath(filename),
|
|
26017
|
+
abs_path: filename,
|
|
26018
|
+
lineno: parseInt(lineStr, 10),
|
|
26019
|
+
colno: parseInt(colStr, 10)
|
|
26020
|
+
};
|
|
26021
|
+
}
|
|
26022
|
+
return null;
|
|
26023
|
+
}
|
|
26024
|
+
function parseEvalOrigin(evalLocation) {
|
|
26025
|
+
let evalChainPart = evalLocation;
|
|
26026
|
+
const commaIndex = findCommaAfterBalancedParens(evalLocation);
|
|
26027
|
+
if (commaIndex !== -1) {
|
|
26028
|
+
evalChainPart = evalLocation.substring(0, commaIndex);
|
|
26029
|
+
}
|
|
26030
|
+
const match = evalChainPart.match(/^eval at (.+?) \((.+)\)$/);
|
|
26031
|
+
if (!match) {
|
|
26032
|
+
return null;
|
|
26033
|
+
}
|
|
26034
|
+
const innerLocation = match[2];
|
|
26035
|
+
if (innerLocation.startsWith("eval at ")) {
|
|
26036
|
+
return parseEvalOrigin(innerLocation);
|
|
26037
|
+
}
|
|
26038
|
+
const locationMatch = innerLocation.match(/^(.+):(\d+):(\d+)$/);
|
|
26039
|
+
if (locationMatch) {
|
|
26040
|
+
const [, filename, lineStr, colStr] = locationMatch;
|
|
26041
|
+
return {
|
|
26042
|
+
filename: makeRelativePath(filename),
|
|
26043
|
+
abs_path: filename,
|
|
26044
|
+
lineno: parseInt(lineStr, 10),
|
|
26045
|
+
colno: parseInt(colStr, 10)
|
|
26046
|
+
};
|
|
26047
|
+
}
|
|
26048
|
+
return null;
|
|
26049
|
+
}
|
|
26050
|
+
function findCommaAfterBalancedParens(str) {
|
|
26051
|
+
let depth = 0;
|
|
26052
|
+
let foundOpenParen = false;
|
|
26053
|
+
for (let i = 0; i < str.length; i++) {
|
|
26054
|
+
if (str[i] === "(") {
|
|
26055
|
+
depth++;
|
|
26056
|
+
foundOpenParen = true;
|
|
26057
|
+
} else if (str[i] === ")") {
|
|
26058
|
+
depth--;
|
|
26059
|
+
if (depth === 0 && foundOpenParen) {
|
|
26060
|
+
for (let j = i + 1; j < str.length; j++) {
|
|
26061
|
+
if (str[j] === ",") {
|
|
26062
|
+
return j;
|
|
26063
|
+
} else if (str[j] !== " ") {
|
|
26064
|
+
return -1;
|
|
26065
|
+
}
|
|
26066
|
+
}
|
|
26067
|
+
return -1;
|
|
26068
|
+
}
|
|
26069
|
+
}
|
|
26070
|
+
}
|
|
26071
|
+
return -1;
|
|
26072
|
+
}
|
|
26073
|
+
function parseV8StackFrame(line) {
|
|
26074
|
+
const withoutAt = line.substring(3);
|
|
26075
|
+
const matchWithFunction = withoutAt.match(/^(.+?)\s+\((.+)\)$/);
|
|
26076
|
+
if (matchWithFunction) {
|
|
26077
|
+
const [, functionName, location] = matchWithFunction;
|
|
26078
|
+
const parsedLocation2 = parseLocation(location);
|
|
26079
|
+
if (parsedLocation2) {
|
|
26080
|
+
return {
|
|
26081
|
+
function: functionName.trim(),
|
|
26082
|
+
filename: parsedLocation2.filename,
|
|
26083
|
+
abs_path: parsedLocation2.abs_path,
|
|
26084
|
+
lineno: parsedLocation2.lineno,
|
|
26085
|
+
colno: parsedLocation2.colno,
|
|
26086
|
+
in_app: isInApp(parsedLocation2.abs_path)
|
|
26087
|
+
};
|
|
26088
|
+
}
|
|
26089
|
+
}
|
|
26090
|
+
const parsedLocation = parseLocation(withoutAt);
|
|
26091
|
+
if (parsedLocation) {
|
|
26092
|
+
return {
|
|
26093
|
+
function: "<anonymous>",
|
|
26094
|
+
filename: parsedLocation.filename,
|
|
26095
|
+
abs_path: parsedLocation.abs_path,
|
|
26096
|
+
lineno: parsedLocation.lineno,
|
|
26097
|
+
colno: parsedLocation.colno,
|
|
26098
|
+
in_app: isInApp(parsedLocation.abs_path)
|
|
26099
|
+
};
|
|
26100
|
+
}
|
|
26101
|
+
return {
|
|
26102
|
+
function: withoutAt,
|
|
26103
|
+
filename: "<unknown>",
|
|
26104
|
+
in_app: false
|
|
26105
|
+
};
|
|
26106
|
+
}
|
|
26107
|
+
function isInApp(filename) {
|
|
26108
|
+
if (filename.includes("/node_modules/") || filename.includes("\\node_modules\\")) {
|
|
26109
|
+
return false;
|
|
26110
|
+
}
|
|
26111
|
+
if (filename.startsWith("node:")) {
|
|
26112
|
+
return false;
|
|
26113
|
+
}
|
|
26114
|
+
if (filename === "native" || filename === "<unknown>") {
|
|
26115
|
+
return false;
|
|
26116
|
+
}
|
|
26117
|
+
return true;
|
|
26118
|
+
}
|
|
26119
|
+
function normalizeUrl(filename) {
|
|
26120
|
+
if (filename.startsWith("file://")) {
|
|
26121
|
+
let result = filename.substring(7);
|
|
26122
|
+
if (!result.startsWith("/") && !result.match(/^[A-Za-z]:/)) {
|
|
26123
|
+
result = "/" + result;
|
|
26124
|
+
}
|
|
26125
|
+
return result;
|
|
26126
|
+
}
|
|
26127
|
+
return filename;
|
|
26128
|
+
}
|
|
26129
|
+
function normalizeNodeInternals(filename) {
|
|
26130
|
+
if (filename.startsWith("node:internal")) {
|
|
26131
|
+
return "node:internal";
|
|
26132
|
+
}
|
|
26133
|
+
if (filename.startsWith("node:")) {
|
|
26134
|
+
const parts = filename.split("/");
|
|
26135
|
+
return parts[0];
|
|
26136
|
+
}
|
|
26137
|
+
return filename;
|
|
26138
|
+
}
|
|
26139
|
+
function stripSystemPrefixes(path) {
|
|
26140
|
+
path = path.replace(/^\/Users\/[^/]+\//, "~/");
|
|
26141
|
+
path = path.replace(/^\/home\/[^/]+\//, "~/");
|
|
26142
|
+
path = path.replace(/^[A-Za-z]:[\\\/]Users[\\\/][^\\\/]+[\\\/]/, "~/");
|
|
26143
|
+
return path;
|
|
26144
|
+
}
|
|
26145
|
+
function normalizeNodeModules(path) {
|
|
26146
|
+
const unixIndex = path.lastIndexOf("/node_modules/");
|
|
26147
|
+
const winIndex = path.lastIndexOf("\\node_modules\\");
|
|
26148
|
+
if (unixIndex !== -1) {
|
|
26149
|
+
return path.substring(unixIndex + 1);
|
|
26150
|
+
}
|
|
26151
|
+
if (winIndex !== -1) {
|
|
26152
|
+
return path.substring(winIndex + 1).replace(/\\/g, "/");
|
|
26153
|
+
}
|
|
26154
|
+
return path;
|
|
26155
|
+
}
|
|
26156
|
+
function stripDeploymentPaths(path) {
|
|
26157
|
+
const deploymentPrefixes = [
|
|
26158
|
+
/^\/var\/www\/[^/]+\//,
|
|
26159
|
+
// Apache/nginx: /var/www/myapp/
|
|
26160
|
+
/^\/var\/task\//,
|
|
26161
|
+
// AWS Lambda: /var/task/
|
|
26162
|
+
/^\/usr\/src\/app\//,
|
|
26163
|
+
// Docker: /usr/src/app/
|
|
26164
|
+
/^\/app\//,
|
|
26165
|
+
// Heroku, Docker, generic: /app/
|
|
26166
|
+
/^\/opt\/[^/]+\//,
|
|
26167
|
+
// Optional software: /opt/myapp/
|
|
26168
|
+
/^\/srv\/[^/]+\//
|
|
26169
|
+
// Service data: /srv/myapp/
|
|
26170
|
+
];
|
|
26171
|
+
for (const prefix of deploymentPrefixes) {
|
|
26172
|
+
path = path.replace(prefix, "");
|
|
26173
|
+
}
|
|
26174
|
+
return path;
|
|
26175
|
+
}
|
|
26176
|
+
function findProjectPath(path) {
|
|
26177
|
+
const primaryMarkers = ["/src/", "/lib/", "/dist/", "/build/"];
|
|
26178
|
+
const secondaryMarkers = [
|
|
26179
|
+
"/app/",
|
|
26180
|
+
"/components/",
|
|
26181
|
+
"/pages/",
|
|
26182
|
+
"/api/",
|
|
26183
|
+
"/utils/",
|
|
26184
|
+
"/services/",
|
|
26185
|
+
"/modules/"
|
|
26186
|
+
];
|
|
26187
|
+
for (const marker of primaryMarkers) {
|
|
26188
|
+
const index = path.lastIndexOf(marker);
|
|
26189
|
+
if (index !== -1) {
|
|
26190
|
+
return path.substring(index + 1);
|
|
26191
|
+
}
|
|
26192
|
+
}
|
|
26193
|
+
for (const marker of secondaryMarkers) {
|
|
26194
|
+
const index = path.lastIndexOf(marker);
|
|
26195
|
+
if (index !== -1) {
|
|
26196
|
+
return path.substring(index + 1);
|
|
26197
|
+
}
|
|
26198
|
+
}
|
|
26199
|
+
return path;
|
|
26200
|
+
}
|
|
26201
|
+
function makeRelativePath(filename) {
|
|
26202
|
+
let result = filename;
|
|
26203
|
+
result = normalizeUrl(result);
|
|
26204
|
+
if (!result.startsWith("/") && !result.match(/^[A-Za-z]:\\/)) {
|
|
26205
|
+
if (result.startsWith("node:")) {
|
|
26206
|
+
return normalizeNodeInternals(result);
|
|
26207
|
+
}
|
|
26208
|
+
return result;
|
|
26209
|
+
}
|
|
26210
|
+
result = result.replace(/\\/g, "/");
|
|
26211
|
+
if (result.startsWith("node:")) {
|
|
26212
|
+
return normalizeNodeInternals(result);
|
|
26213
|
+
}
|
|
26214
|
+
if (result.includes("/node_modules/")) {
|
|
26215
|
+
return normalizeNodeModules(result);
|
|
26216
|
+
}
|
|
26217
|
+
result = stripSystemPrefixes(result);
|
|
26218
|
+
result = stripDeploymentPaths(result);
|
|
26219
|
+
let cwd = null;
|
|
26220
|
+
try {
|
|
26221
|
+
if (typeof process !== "undefined" && typeof process.cwd === "function") {
|
|
26222
|
+
cwd = process.cwd();
|
|
26223
|
+
}
|
|
26224
|
+
} catch {
|
|
26225
|
+
}
|
|
26226
|
+
if (cwd && result.startsWith(cwd)) {
|
|
26227
|
+
result = result.substring(cwd.length + 1);
|
|
26228
|
+
}
|
|
26229
|
+
if (result.startsWith("/") || result.match(/^[A-Za-z]:[/]/)) {
|
|
26230
|
+
result = findProjectPath(result);
|
|
26231
|
+
} else if (result.startsWith("~")) {
|
|
26232
|
+
const withoutTilde = result.substring(2);
|
|
26233
|
+
const projectPath = findProjectPath("/" + withoutTilde);
|
|
26234
|
+
if (projectPath !== "/" + withoutTilde) {
|
|
26235
|
+
result = projectPath;
|
|
26236
|
+
}
|
|
26237
|
+
}
|
|
26238
|
+
if (result.startsWith("/")) {
|
|
26239
|
+
result = result.substring(1);
|
|
26240
|
+
}
|
|
26241
|
+
return result;
|
|
26242
|
+
}
|
|
26243
|
+
function unwrapErrorCauses(error2) {
|
|
26244
|
+
const chainedErrors = [];
|
|
26245
|
+
const seenErrors = /* @__PURE__ */ new Set();
|
|
26246
|
+
let currentError = error2.cause;
|
|
26247
|
+
let depth = 0;
|
|
26248
|
+
while (currentError && depth < MAX_EXCEPTION_CHAIN_DEPTH) {
|
|
26249
|
+
if (!(currentError instanceof Error)) {
|
|
26250
|
+
chainedErrors.push({
|
|
26251
|
+
message: stringifyNonError(currentError),
|
|
26252
|
+
type: void 0
|
|
26253
|
+
});
|
|
26254
|
+
break;
|
|
26255
|
+
}
|
|
26256
|
+
if (seenErrors.has(currentError)) {
|
|
26257
|
+
break;
|
|
26258
|
+
}
|
|
26259
|
+
seenErrors.add(currentError);
|
|
26260
|
+
const chainedErrorData = {
|
|
26261
|
+
message: currentError.message || "",
|
|
26262
|
+
type: currentError.name || currentError.constructor?.name || "Error"
|
|
26263
|
+
};
|
|
26264
|
+
if (currentError.stack) {
|
|
26265
|
+
chainedErrorData.stack = currentError.stack;
|
|
26266
|
+
chainedErrorData.frames = parseV8StackTrace(currentError.stack);
|
|
26267
|
+
}
|
|
26268
|
+
chainedErrors.push(chainedErrorData);
|
|
26269
|
+
currentError = currentError.cause;
|
|
26270
|
+
depth++;
|
|
26271
|
+
}
|
|
26272
|
+
return chainedErrors;
|
|
26273
|
+
}
|
|
26274
|
+
function isCallToolResult(value) {
|
|
26275
|
+
return value !== null && typeof value === "object" && "isError" in value && "content" in value && Array.isArray(value.content);
|
|
26276
|
+
}
|
|
26277
|
+
function captureCallToolResultError(result, _contextStack) {
|
|
26278
|
+
const message = result.content?.filter((c) => c.type === "text").map((c) => c.text).join(" ").trim() || "Unknown error";
|
|
26279
|
+
const errorData = {
|
|
26280
|
+
message,
|
|
26281
|
+
type: void 0,
|
|
26282
|
+
// Can't determine actual type from CallToolResult
|
|
26283
|
+
platform: "javascript"
|
|
26284
|
+
// No stack or frames - SDK stripped the original error information
|
|
26285
|
+
};
|
|
26286
|
+
return errorData;
|
|
26287
|
+
}
|
|
26288
|
+
function stringifyNonError(value) {
|
|
26289
|
+
if (value === null) {
|
|
26290
|
+
return "null";
|
|
26291
|
+
}
|
|
26292
|
+
if (value === void 0) {
|
|
26293
|
+
return "undefined";
|
|
26294
|
+
}
|
|
26295
|
+
if (typeof value === "string") {
|
|
26296
|
+
return value;
|
|
26297
|
+
}
|
|
26298
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
26299
|
+
return String(value);
|
|
26300
|
+
}
|
|
26301
|
+
try {
|
|
26302
|
+
return JSON.stringify(value);
|
|
26303
|
+
} catch {
|
|
26304
|
+
return String(value);
|
|
26305
|
+
}
|
|
26306
|
+
}
|
|
26307
|
+
function isToolResultError(result) {
|
|
26308
|
+
return result && typeof result === "object" && result.isError === true;
|
|
26309
|
+
}
|
|
26310
|
+
var listToolsTracingSetup = /* @__PURE__ */ new WeakMap();
|
|
26311
|
+
function setupListToolsTracing(highLevelServer) {
|
|
26312
|
+
const server = highLevelServer.server;
|
|
26313
|
+
if (!server._capabilities?.tools) {
|
|
26314
|
+
return;
|
|
26315
|
+
}
|
|
26316
|
+
if (listToolsTracingSetup.get(server)) {
|
|
26317
|
+
return;
|
|
26318
|
+
}
|
|
26319
|
+
const handlers = server._requestHandlers;
|
|
26320
|
+
const originalListToolsHandler = handlers.get("tools/list");
|
|
26321
|
+
if (!originalListToolsHandler) {
|
|
26322
|
+
return;
|
|
26323
|
+
}
|
|
26324
|
+
try {
|
|
26325
|
+
server.setRequestHandler(ListToolsRequestSchema, async (request, extra) => {
|
|
26326
|
+
let tools = [];
|
|
26327
|
+
const data = getServerTrackingData(server);
|
|
26328
|
+
let event = {
|
|
26329
|
+
sessionId: getServerSessionId(server, extra),
|
|
26330
|
+
parameters: {
|
|
26331
|
+
request,
|
|
26332
|
+
extra
|
|
26333
|
+
},
|
|
26334
|
+
eventType: PublishEventRequestEventTypeEnum.mcpToolsList,
|
|
26335
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
26336
|
+
redactionFn: data?.options.redactSensitiveInformation
|
|
26337
|
+
};
|
|
26338
|
+
if (data) {
|
|
26339
|
+
const resolvedTags = await resolveEventTags(data, request, extra);
|
|
26340
|
+
if (resolvedTags) event.tags = resolvedTags;
|
|
26341
|
+
const resolvedProperties = await resolveEventProperties(
|
|
26342
|
+
data,
|
|
26343
|
+
request,
|
|
26344
|
+
extra
|
|
26345
|
+
);
|
|
26346
|
+
if (resolvedProperties) event.properties = resolvedProperties;
|
|
26347
|
+
}
|
|
26348
|
+
try {
|
|
26349
|
+
const originalResponse = await originalListToolsHandler(
|
|
26350
|
+
request,
|
|
26351
|
+
extra
|
|
26352
|
+
);
|
|
26353
|
+
tools = originalResponse.tools || [];
|
|
26354
|
+
if (data?.options.enableToolCallContext) {
|
|
26355
|
+
tools = addContextParameterToTools(
|
|
26356
|
+
tools,
|
|
26357
|
+
data.options.customContextDescription
|
|
26358
|
+
);
|
|
26359
|
+
}
|
|
26360
|
+
if (data?.options.enableReportMissing) {
|
|
26361
|
+
const alreadyPresent = tools.some(
|
|
26362
|
+
(t) => t?.name === GET_MORE_TOOLS_NAME
|
|
26363
|
+
);
|
|
26364
|
+
if (!alreadyPresent) tools.push(getReportMissingToolDescriptor());
|
|
26365
|
+
}
|
|
26366
|
+
} catch (error2) {
|
|
26367
|
+
writeToLog(
|
|
26368
|
+
`Warning: Original list tools handler failed, this suggests an error MCPCat did not cause - ${error2}`
|
|
26369
|
+
);
|
|
26370
|
+
event.error = { message: getMCPCompatibleErrorMessage(error2) };
|
|
26371
|
+
event.isError = true;
|
|
26372
|
+
event.duration = event.timestamp && (/* @__PURE__ */ new Date()).getTime() - event.timestamp.getTime() || 0;
|
|
26373
|
+
publishEvent(server, event);
|
|
26374
|
+
throw error2;
|
|
26375
|
+
}
|
|
26376
|
+
if (!data) {
|
|
26377
|
+
writeToLog(
|
|
26378
|
+
"Warning: MCPCat is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls."
|
|
26379
|
+
);
|
|
26380
|
+
return { tools };
|
|
26381
|
+
}
|
|
26382
|
+
if (tools.length === 0) {
|
|
26383
|
+
writeToLog(
|
|
26384
|
+
"Warning: No tools found in the original list. This is likely due to the tools not being registered before MCPCat.track()."
|
|
26385
|
+
);
|
|
26386
|
+
event.error = { message: "No tools were sent to MCP client." };
|
|
26387
|
+
event.isError = true;
|
|
26388
|
+
event.duration = event.timestamp && (/* @__PURE__ */ new Date()).getTime() - event.timestamp.getTime() || 0;
|
|
26389
|
+
publishEvent(server, event);
|
|
26390
|
+
return { tools };
|
|
26391
|
+
}
|
|
26392
|
+
event.response = { tools };
|
|
26393
|
+
event.isError = false;
|
|
26394
|
+
event.duration = event.timestamp && (/* @__PURE__ */ new Date()).getTime() - event.timestamp.getTime() || 0;
|
|
26395
|
+
publishEvent(server, event);
|
|
26396
|
+
return { tools };
|
|
26397
|
+
});
|
|
26398
|
+
listToolsTracingSetup.set(server, true);
|
|
26399
|
+
} catch (error2) {
|
|
26400
|
+
writeToLog(`Warning: Failed to override list tools handler - ${error2}`);
|
|
26401
|
+
}
|
|
26402
|
+
}
|
|
26403
|
+
function setupInitializeTracing(highLevelServer) {
|
|
26404
|
+
const server = highLevelServer.server;
|
|
26405
|
+
const handlers = server._requestHandlers;
|
|
26406
|
+
const originalInitializeHandler = handlers.get("initialize");
|
|
26407
|
+
if (originalInitializeHandler) {
|
|
26408
|
+
server.setRequestHandler(
|
|
26409
|
+
InitializeRequestSchema,
|
|
26410
|
+
async (request, extra) => {
|
|
26411
|
+
const data = getServerTrackingData(server);
|
|
26412
|
+
if (!data) {
|
|
26413
|
+
writeToLog(
|
|
26414
|
+
"Warning: MCPCat is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls."
|
|
26415
|
+
);
|
|
26416
|
+
return await originalInitializeHandler(request, extra);
|
|
26417
|
+
}
|
|
26418
|
+
const sessionId = getServerSessionId(server, extra);
|
|
26419
|
+
await handleIdentify(server, data, request, extra);
|
|
26420
|
+
let event = {
|
|
26421
|
+
sessionId,
|
|
26422
|
+
resourceName: request.params?.name || "Unknown Tool Name",
|
|
26423
|
+
eventType: PublishEventRequestEventTypeEnum.mcpInitialize,
|
|
26424
|
+
parameters: {
|
|
26425
|
+
request,
|
|
26426
|
+
extra
|
|
26427
|
+
},
|
|
26428
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
26429
|
+
redactionFn: data.options.redactSensitiveInformation
|
|
26430
|
+
};
|
|
26431
|
+
const resolvedTags = await resolveEventTags(data, request, extra);
|
|
26432
|
+
if (resolvedTags) event.tags = resolvedTags;
|
|
26433
|
+
const resolvedProperties = await resolveEventProperties(
|
|
26434
|
+
data,
|
|
26435
|
+
request,
|
|
26436
|
+
extra
|
|
26437
|
+
);
|
|
26438
|
+
if (resolvedProperties) event.properties = resolvedProperties;
|
|
26439
|
+
const result = await originalInitializeHandler(request, extra);
|
|
26440
|
+
event.response = result;
|
|
26441
|
+
publishEvent(server, event);
|
|
26442
|
+
return result;
|
|
26443
|
+
}
|
|
26444
|
+
);
|
|
26445
|
+
}
|
|
26446
|
+
}
|
|
26447
|
+
function setupToolCallTracing(server) {
|
|
26448
|
+
try {
|
|
26449
|
+
const handlers = server._requestHandlers;
|
|
26450
|
+
const originalCallToolHandler = handlers.get("tools/call");
|
|
26451
|
+
const originalInitializeHandler = handlers.get("initialize");
|
|
26452
|
+
if (originalInitializeHandler) {
|
|
26453
|
+
server.setRequestHandler(
|
|
26454
|
+
InitializeRequestSchema,
|
|
26455
|
+
async (request, extra) => {
|
|
26456
|
+
const data = getServerTrackingData(server);
|
|
26457
|
+
if (!data) {
|
|
26458
|
+
writeToLog(
|
|
26459
|
+
"Warning: MCPCat is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls."
|
|
26460
|
+
);
|
|
26461
|
+
return await originalInitializeHandler(request, extra);
|
|
26462
|
+
}
|
|
26463
|
+
const sessionId = getServerSessionId(server, extra);
|
|
26464
|
+
await handleIdentify(server, data, request, extra);
|
|
26465
|
+
let event = {
|
|
26466
|
+
sessionId,
|
|
26467
|
+
resourceName: request.params?.name || "Unknown Tool Name",
|
|
26468
|
+
eventType: PublishEventRequestEventTypeEnum.mcpInitialize,
|
|
26469
|
+
parameters: {
|
|
26470
|
+
request,
|
|
26471
|
+
extra
|
|
26472
|
+
},
|
|
26473
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
26474
|
+
redactionFn: data.options.redactSensitiveInformation
|
|
26475
|
+
};
|
|
26476
|
+
const resolvedTags = await resolveEventTags(data, request, extra);
|
|
26477
|
+
if (resolvedTags) event.tags = resolvedTags;
|
|
26478
|
+
const resolvedProperties = await resolveEventProperties(
|
|
26479
|
+
data,
|
|
26480
|
+
request,
|
|
26481
|
+
extra
|
|
26482
|
+
);
|
|
26483
|
+
if (resolvedProperties) event.properties = resolvedProperties;
|
|
26484
|
+
const result = await originalInitializeHandler(request, extra);
|
|
26485
|
+
event.response = result;
|
|
26486
|
+
publishEvent(server, event);
|
|
26487
|
+
return result;
|
|
26488
|
+
}
|
|
26489
|
+
);
|
|
26490
|
+
}
|
|
26491
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
26492
|
+
const data = getServerTrackingData(server);
|
|
26493
|
+
if (!data) {
|
|
26494
|
+
writeToLog(
|
|
26495
|
+
"Warning: MCPCat is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls."
|
|
26496
|
+
);
|
|
26497
|
+
return await originalCallToolHandler?.(request, extra);
|
|
26498
|
+
}
|
|
26499
|
+
const sessionId = getServerSessionId(server, extra);
|
|
26500
|
+
let event = {
|
|
26501
|
+
sessionId,
|
|
26502
|
+
resourceName: request.params?.name || "Unknown Tool Name",
|
|
26503
|
+
parameters: {
|
|
26504
|
+
request,
|
|
26505
|
+
extra
|
|
26506
|
+
},
|
|
26507
|
+
eventType: PublishEventRequestEventTypeEnum.mcpToolsCall,
|
|
26508
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
26509
|
+
redactionFn: data.options.redactSensitiveInformation
|
|
26510
|
+
};
|
|
26511
|
+
try {
|
|
26512
|
+
await handleIdentify(server, data, request, extra);
|
|
26513
|
+
const resolvedTags = await resolveEventTags(data, request, extra);
|
|
26514
|
+
if (resolvedTags) event.tags = resolvedTags;
|
|
26515
|
+
const resolvedProperties = await resolveEventProperties(
|
|
26516
|
+
data,
|
|
26517
|
+
request,
|
|
26518
|
+
extra
|
|
26519
|
+
);
|
|
26520
|
+
if (resolvedProperties) event.properties = resolvedProperties;
|
|
26521
|
+
if (data.options.enableToolCallContext && request.params?.name !== "get_more_tools") {
|
|
26522
|
+
const hasContext = request.params?.arguments && typeof request.params.arguments === "object" && "context" in request.params.arguments;
|
|
26523
|
+
if (hasContext) {
|
|
26524
|
+
event.userIntent = request.params.arguments.context;
|
|
26525
|
+
}
|
|
26526
|
+
}
|
|
26527
|
+
let result;
|
|
26528
|
+
if (request.params?.name === "get_more_tools") {
|
|
26529
|
+
result = await handleReportMissing(request.params.arguments.context);
|
|
26530
|
+
event.userIntent = request.params.arguments.context;
|
|
26531
|
+
} else if (originalCallToolHandler) {
|
|
26532
|
+
result = await originalCallToolHandler(request, extra);
|
|
26533
|
+
} else {
|
|
26534
|
+
event.isError = true;
|
|
26535
|
+
event.error = {
|
|
26536
|
+
message: `Tool call handler not found for ${request.params?.name || "unknown"}`
|
|
26537
|
+
};
|
|
26538
|
+
event.duration = event.timestamp && (/* @__PURE__ */ new Date()).getTime() - event.timestamp.getTime() || void 0;
|
|
26539
|
+
publishEvent(server, event);
|
|
26540
|
+
throw new Error(`Unknown tool: ${request.params?.name || "unknown"}`);
|
|
26541
|
+
}
|
|
26542
|
+
if (isToolResultError(result)) {
|
|
26543
|
+
event.isError = true;
|
|
26544
|
+
event.error = captureException(result);
|
|
26545
|
+
}
|
|
26546
|
+
event.response = result;
|
|
26547
|
+
publishEvent(server, event);
|
|
26548
|
+
return result;
|
|
26549
|
+
} catch (error2) {
|
|
26550
|
+
event.isError = true;
|
|
26551
|
+
event.error = captureException(error2);
|
|
26552
|
+
publishEvent(server, event);
|
|
26553
|
+
throw error2;
|
|
26554
|
+
}
|
|
26555
|
+
});
|
|
26556
|
+
} catch (error2) {
|
|
26557
|
+
writeToLog(`Warning: Failed to setup tool call tracing - ${error2}`);
|
|
26558
|
+
throw error2;
|
|
26559
|
+
}
|
|
26560
|
+
}
|
|
26561
|
+
function getToolFunction(tool) {
|
|
26562
|
+
if ("handler" in tool && typeof tool.handler === "function") {
|
|
26563
|
+
return tool.handler;
|
|
26564
|
+
}
|
|
26565
|
+
if ("callback" in tool && typeof tool.callback === "function") {
|
|
26566
|
+
return tool.callback;
|
|
26567
|
+
}
|
|
26568
|
+
throw new Error("Tool has neither callback nor handler property");
|
|
26569
|
+
}
|
|
26570
|
+
function getToolFunctionKey(tool) {
|
|
26571
|
+
if ("handler" in tool && typeof tool.handler === "function") {
|
|
26572
|
+
return "handler";
|
|
26573
|
+
}
|
|
26574
|
+
return "callback";
|
|
26575
|
+
}
|
|
26576
|
+
function hasToolFunction(tool) {
|
|
26577
|
+
if (!tool || typeof tool !== "object") return false;
|
|
26578
|
+
const t = tool;
|
|
26579
|
+
return "handler" in t && typeof t.handler === "function" || "callback" in t && typeof t.callback === "function";
|
|
26580
|
+
}
|
|
26581
|
+
function createWrappedTool(originalTool, wrappedFunction) {
|
|
26582
|
+
const key = getToolFunctionKey(originalTool);
|
|
26583
|
+
return {
|
|
26584
|
+
...originalTool,
|
|
26585
|
+
[key]: wrappedFunction
|
|
26586
|
+
};
|
|
26587
|
+
}
|
|
26588
|
+
function isZ4Schema2(schema) {
|
|
26589
|
+
if (!schema || typeof schema !== "object") return false;
|
|
26590
|
+
return !!schema._zod;
|
|
26591
|
+
}
|
|
26592
|
+
function getObjectShape2(schema) {
|
|
26593
|
+
if (!schema || typeof schema !== "object") return void 0;
|
|
26594
|
+
let rawShape;
|
|
26595
|
+
if (isZ4Schema2(schema)) {
|
|
26596
|
+
const v4Schema = schema;
|
|
26597
|
+
rawShape = v4Schema._zod?.def?.shape;
|
|
26598
|
+
} else {
|
|
26599
|
+
const v3Schema = schema;
|
|
26600
|
+
rawShape = v3Schema.shape ?? v3Schema._def?.shape;
|
|
26601
|
+
}
|
|
26602
|
+
if (!rawShape) return void 0;
|
|
26603
|
+
if (typeof rawShape === "function") {
|
|
26604
|
+
try {
|
|
26605
|
+
return rawShape();
|
|
26606
|
+
} catch {
|
|
26607
|
+
return void 0;
|
|
26608
|
+
}
|
|
26609
|
+
}
|
|
26610
|
+
return rawShape;
|
|
26611
|
+
}
|
|
26612
|
+
function getLiteralValue2(schema) {
|
|
26613
|
+
if (!schema || typeof schema !== "object") return void 0;
|
|
26614
|
+
if (isZ4Schema2(schema)) {
|
|
26615
|
+
const v4Schema = schema;
|
|
26616
|
+
const def = v4Schema._zod?.def;
|
|
26617
|
+
if (def?.value !== void 0) return def.value;
|
|
26618
|
+
if (Array.isArray(def?.values) && def.values.length > 0) {
|
|
26619
|
+
return def.values[0];
|
|
26620
|
+
}
|
|
26621
|
+
} else {
|
|
26622
|
+
const v3Schema = schema;
|
|
26623
|
+
const def = v3Schema._def;
|
|
26624
|
+
if (def?.value !== void 0) return def.value;
|
|
26625
|
+
if (Array.isArray(def?.values) && def.values.length > 0) {
|
|
26626
|
+
return def.values[0];
|
|
26627
|
+
}
|
|
26628
|
+
}
|
|
26629
|
+
const directValue = schema.value;
|
|
26630
|
+
if (directValue !== void 0) return directValue;
|
|
26631
|
+
return void 0;
|
|
26632
|
+
}
|
|
26633
|
+
var wrappedCallbacks = /* @__PURE__ */ new WeakMap();
|
|
26634
|
+
var MCPCAT_PROCESSED = /* @__PURE__ */ Symbol("__mcpcat_processed__");
|
|
26635
|
+
function isToolResultError2(result) {
|
|
26636
|
+
return result && typeof result === "object" && result.isError === true;
|
|
26637
|
+
}
|
|
26638
|
+
function addTracingToToolRegistry(tools, server) {
|
|
26639
|
+
return Object.fromEntries(
|
|
26640
|
+
Object.entries(tools).map(([name, tool]) => [
|
|
26641
|
+
name,
|
|
26642
|
+
addTracingToToolCallbackInternal(tool, name, server)
|
|
26643
|
+
])
|
|
26644
|
+
);
|
|
26645
|
+
}
|
|
26646
|
+
function setupListenerToRegisteredTools(server) {
|
|
26647
|
+
try {
|
|
26648
|
+
const data = getServerTrackingData(server.server);
|
|
26649
|
+
if (!data) {
|
|
26650
|
+
writeToLog("Warning: Cannot setup listener - no tracking data found");
|
|
26651
|
+
return;
|
|
26652
|
+
}
|
|
26653
|
+
const handler = {
|
|
26654
|
+
set(target, property, value) {
|
|
26655
|
+
try {
|
|
26656
|
+
if (typeof property === "string" && value && typeof value === "object" && hasToolFunction(value)) {
|
|
26657
|
+
if (value[MCPCAT_PROCESSED]) {
|
|
26658
|
+
writeToLog(
|
|
26659
|
+
`Tool ${String(property)} already processed, skipping proxy wrapping`
|
|
26660
|
+
);
|
|
26661
|
+
return Reflect.set(target, property, value);
|
|
26662
|
+
}
|
|
26663
|
+
if (wrappedCallbacks.has(getToolFunction(value))) {
|
|
26664
|
+
writeToLog(
|
|
26665
|
+
`Tool ${String(property)} callback already wrapped, skipping proxy wrapping`
|
|
26666
|
+
);
|
|
26667
|
+
return Reflect.set(target, property, value);
|
|
26668
|
+
}
|
|
26669
|
+
value = addTracingToToolCallbackInternal(value, property, server);
|
|
26670
|
+
setupListToolsTracing(server);
|
|
26671
|
+
if (typeof value.update === "function") {
|
|
26672
|
+
const originalUpdate = value.update;
|
|
26673
|
+
value.update = function(...updateArgs) {
|
|
26674
|
+
if (updateArgs[0]) {
|
|
26675
|
+
const updateObj = updateArgs[0];
|
|
26676
|
+
if (updateObj.callback && typeof updateObj.callback === "function") {
|
|
26677
|
+
const wrappedTool = addTracingToToolCallbackInternal(
|
|
26678
|
+
{ callback: updateObj.callback },
|
|
26679
|
+
property,
|
|
26680
|
+
server
|
|
26681
|
+
);
|
|
26682
|
+
updateObj.callback = getToolFunction(wrappedTool);
|
|
26683
|
+
}
|
|
26684
|
+
}
|
|
26685
|
+
return originalUpdate.apply(this, updateArgs);
|
|
26686
|
+
};
|
|
26687
|
+
}
|
|
26688
|
+
}
|
|
26689
|
+
return Reflect.set(target, property, value);
|
|
26690
|
+
} catch (error2) {
|
|
26691
|
+
writeToLog(
|
|
26692
|
+
`Warning: Error in proxy set handler for tool ${String(property)} - ${error2}`
|
|
26693
|
+
);
|
|
26694
|
+
return Reflect.set(target, property, value);
|
|
26695
|
+
}
|
|
26696
|
+
},
|
|
26697
|
+
get(target, property) {
|
|
26698
|
+
return Reflect.get(target, property);
|
|
26699
|
+
},
|
|
26700
|
+
deleteProperty(target, property) {
|
|
26701
|
+
return Reflect.deleteProperty(target, property);
|
|
26702
|
+
},
|
|
26703
|
+
has(target, property) {
|
|
26704
|
+
return Reflect.has(target, property);
|
|
26705
|
+
}
|
|
26706
|
+
};
|
|
26707
|
+
const originalTools = server._registeredTools || {};
|
|
26708
|
+
server._registeredTools = new Proxy(originalTools, handler);
|
|
26709
|
+
writeToLog("Successfully set up listener for new tool registrations");
|
|
26710
|
+
} catch (error2) {
|
|
26711
|
+
writeToLog(
|
|
26712
|
+
`Warning: Failed to setup listener for registered tools - ${error2}`
|
|
26713
|
+
);
|
|
26714
|
+
}
|
|
26715
|
+
}
|
|
26716
|
+
function addTracingToToolCallbackInternal(tool, toolName, _server) {
|
|
26717
|
+
const originalCallback = getToolFunction(tool);
|
|
26718
|
+
if (wrappedCallbacks.has(originalCallback)) {
|
|
26719
|
+
writeToLog(`Tool ${toolName} callback already wrapped, skipping re-wrap`);
|
|
26720
|
+
return tool;
|
|
26721
|
+
}
|
|
26722
|
+
if (tool[MCPCAT_PROCESSED]) {
|
|
26723
|
+
writeToLog(`Tool ${toolName} already processed, skipping re-wrap`);
|
|
26724
|
+
return tool;
|
|
26725
|
+
}
|
|
26726
|
+
const wrappedCallback = async function(...params) {
|
|
26727
|
+
let args;
|
|
26728
|
+
let extra;
|
|
26729
|
+
if (params.length === 2) {
|
|
26730
|
+
args = params[0];
|
|
26731
|
+
extra = params[1];
|
|
26732
|
+
} else {
|
|
26733
|
+
args = void 0;
|
|
26734
|
+
extra = params[0];
|
|
26735
|
+
}
|
|
26736
|
+
const removeContextFromArgs = (args2) => {
|
|
26737
|
+
if (args2 && typeof args2 === "object" && "context" in args2) {
|
|
26738
|
+
const { context: _context, ...argsWithoutContext } = args2;
|
|
26739
|
+
return argsWithoutContext;
|
|
26740
|
+
}
|
|
26741
|
+
return args2;
|
|
26742
|
+
};
|
|
26743
|
+
const cleanedArgs = toolName === "get_more_tools" ? args : removeContextFromArgs(args);
|
|
26744
|
+
try {
|
|
26745
|
+
if (cleanedArgs === void 0) {
|
|
26746
|
+
const handler = originalCallback;
|
|
26747
|
+
return await handler(extra);
|
|
26748
|
+
} else {
|
|
26749
|
+
const handler = originalCallback;
|
|
26750
|
+
return await handler(cleanedArgs, extra);
|
|
26751
|
+
}
|
|
26752
|
+
} catch (error2) {
|
|
26753
|
+
if (error2 instanceof Error) {
|
|
26754
|
+
extra.__mcpcat_error = error2;
|
|
26755
|
+
}
|
|
26756
|
+
throw error2;
|
|
26757
|
+
}
|
|
26758
|
+
};
|
|
26759
|
+
wrappedCallbacks.set(originalCallback, true);
|
|
26760
|
+
wrappedCallbacks.set(wrappedCallback, true);
|
|
26761
|
+
const wrappedTool = createWrappedTool(tool, wrappedCallback);
|
|
26762
|
+
wrappedTool[MCPCAT_PROCESSED] = true;
|
|
26763
|
+
return wrappedTool;
|
|
26764
|
+
}
|
|
26765
|
+
function setupToolsCallHandlerWrapping(server) {
|
|
26766
|
+
const lowLevelServer = server.server;
|
|
26767
|
+
const existingHandler = lowLevelServer._requestHandlers.get("tools/call");
|
|
26768
|
+
if (existingHandler) {
|
|
26769
|
+
const wrappedHandler = createToolsCallWrapper(
|
|
26770
|
+
existingHandler,
|
|
26771
|
+
lowLevelServer
|
|
26772
|
+
);
|
|
26773
|
+
lowLevelServer._requestHandlers.set("tools/call", wrappedHandler);
|
|
26774
|
+
}
|
|
26775
|
+
const originalSetRequestHandler = lowLevelServer.setRequestHandler.bind(lowLevelServer);
|
|
26776
|
+
lowLevelServer.setRequestHandler = function(requestSchema, handler) {
|
|
26777
|
+
const shape = getObjectShape2(requestSchema);
|
|
26778
|
+
const method = shape?.method ? getLiteralValue2(shape.method) : void 0;
|
|
26779
|
+
if (method === "tools/call") {
|
|
26780
|
+
const wrappedHandler = createToolsCallWrapper(handler, lowLevelServer);
|
|
26781
|
+
return originalSetRequestHandler(requestSchema, wrappedHandler);
|
|
26782
|
+
}
|
|
26783
|
+
return originalSetRequestHandler(requestSchema, handler);
|
|
26784
|
+
};
|
|
26785
|
+
}
|
|
26786
|
+
function createToolsCallWrapper(originalHandler, server) {
|
|
26787
|
+
return async (request, extra) => {
|
|
26788
|
+
const startTime = /* @__PURE__ */ new Date();
|
|
26789
|
+
let shouldPublishEvent = false;
|
|
26790
|
+
let event = null;
|
|
26791
|
+
try {
|
|
26792
|
+
const data = getServerTrackingData(server);
|
|
26793
|
+
if (!data) {
|
|
26794
|
+
writeToLog(
|
|
26795
|
+
"Warning: MCPCat is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls."
|
|
26796
|
+
);
|
|
26797
|
+
} else {
|
|
26798
|
+
shouldPublishEvent = true;
|
|
26799
|
+
const sessionId = getServerSessionId(server, extra);
|
|
26800
|
+
event = {
|
|
26801
|
+
sessionId,
|
|
26802
|
+
resourceName: request.params?.name || "Unknown Tool",
|
|
26803
|
+
parameters: { request, extra },
|
|
26804
|
+
eventType: PublishEventRequestEventTypeEnum.mcpToolsCall,
|
|
26805
|
+
timestamp: startTime,
|
|
26806
|
+
redactionFn: data.options.redactSensitiveInformation
|
|
26807
|
+
};
|
|
26808
|
+
await handleIdentify(server, data, request, extra);
|
|
26809
|
+
event.sessionId = data.sessionId;
|
|
26810
|
+
const resolvedTags = await resolveEventTags(data, request, extra);
|
|
26811
|
+
if (resolvedTags) event.tags = resolvedTags;
|
|
26812
|
+
const resolvedProperties = await resolveEventProperties(
|
|
26813
|
+
data,
|
|
26814
|
+
request,
|
|
26815
|
+
extra
|
|
26816
|
+
);
|
|
26817
|
+
if (resolvedProperties) event.properties = resolvedProperties;
|
|
26818
|
+
if (data.options.enableToolCallContext && request.params?.arguments?.context) {
|
|
26819
|
+
event.userIntent = request.params.arguments.context;
|
|
26820
|
+
}
|
|
26821
|
+
}
|
|
26822
|
+
} catch (error2) {
|
|
26823
|
+
writeToLog(
|
|
26824
|
+
`Warning: MCPCat tracing failed for tool ${request.params?.name}, falling back to original handler - ${error2}`
|
|
26825
|
+
);
|
|
26826
|
+
}
|
|
26827
|
+
if (request?.params?.name === "get_more_tools") {
|
|
26828
|
+
try {
|
|
26829
|
+
const result = await handleReportMissing({
|
|
26830
|
+
context: request?.params?.arguments?.context
|
|
26831
|
+
});
|
|
26832
|
+
if (event && shouldPublishEvent) {
|
|
26833
|
+
event.userIntent = request?.params?.arguments?.context;
|
|
26834
|
+
event.response = result;
|
|
26835
|
+
event.duration = (/* @__PURE__ */ new Date()).getTime() - startTime.getTime();
|
|
26836
|
+
publishEvent(server, event);
|
|
26837
|
+
}
|
|
26838
|
+
return result;
|
|
26839
|
+
} catch (error2) {
|
|
26840
|
+
if (event && shouldPublishEvent) {
|
|
26841
|
+
event.isError = true;
|
|
26842
|
+
event.error = captureException(error2);
|
|
26843
|
+
event.duration = (/* @__PURE__ */ new Date()).getTime() - startTime.getTime();
|
|
26844
|
+
publishEvent(server, event);
|
|
26845
|
+
}
|
|
26846
|
+
throw error2;
|
|
26847
|
+
}
|
|
26848
|
+
}
|
|
26849
|
+
try {
|
|
26850
|
+
const result = await originalHandler(request, extra);
|
|
26851
|
+
if (event && shouldPublishEvent) {
|
|
26852
|
+
if (isToolResultError2(result)) {
|
|
26853
|
+
event.isError = true;
|
|
26854
|
+
const capturedError = extra.__mcpcat_error;
|
|
26855
|
+
if (capturedError) {
|
|
26856
|
+
event.error = captureException(capturedError);
|
|
26857
|
+
delete extra.__mcpcat_error;
|
|
26858
|
+
} else {
|
|
26859
|
+
event.error = captureException(result);
|
|
26860
|
+
}
|
|
26861
|
+
}
|
|
26862
|
+
event.response = result;
|
|
26863
|
+
event.duration = (/* @__PURE__ */ new Date()).getTime() - startTime.getTime();
|
|
26864
|
+
publishEvent(server, event);
|
|
26865
|
+
}
|
|
26866
|
+
return result;
|
|
26867
|
+
} catch (error2) {
|
|
26868
|
+
if (event && shouldPublishEvent) {
|
|
26869
|
+
event.isError = true;
|
|
26870
|
+
event.error = captureException(error2);
|
|
26871
|
+
event.duration = (/* @__PURE__ */ new Date()).getTime() - startTime.getTime();
|
|
26872
|
+
publishEvent(server, event);
|
|
26873
|
+
}
|
|
26874
|
+
throw error2;
|
|
26875
|
+
}
|
|
26876
|
+
};
|
|
26877
|
+
}
|
|
26878
|
+
function setupTracking(server) {
|
|
26879
|
+
try {
|
|
26880
|
+
const _mcpcatData = getServerTrackingData(server.server);
|
|
26881
|
+
setupToolsCallHandlerWrapping(server);
|
|
26882
|
+
setupInitializeTracing(server);
|
|
26883
|
+
server._registeredTools = addTracingToToolRegistry(
|
|
26884
|
+
server._registeredTools,
|
|
26885
|
+
server
|
|
26886
|
+
);
|
|
26887
|
+
setupListToolsTracing(server);
|
|
26888
|
+
setupListenerToRegisteredTools(server);
|
|
26889
|
+
} catch (error2) {
|
|
26890
|
+
writeToLog(`Warning: Failed to setup tool call tracing - ${error2}`);
|
|
26891
|
+
}
|
|
26892
|
+
}
|
|
26893
|
+
var TraceContext = class {
|
|
26894
|
+
getTraceId(sessionId) {
|
|
26895
|
+
if (!sessionId) {
|
|
26896
|
+
return randomBytes2(16).toString("hex");
|
|
26897
|
+
}
|
|
26898
|
+
return createHash22("sha256").update(sessionId).digest("hex").substring(0, 32);
|
|
26899
|
+
}
|
|
26900
|
+
getSpanId(eventId) {
|
|
26901
|
+
if (!eventId) {
|
|
26902
|
+
return randomBytes2(8).toString("hex");
|
|
26903
|
+
}
|
|
26904
|
+
return createHash22("sha256").update(eventId).digest("hex").substring(0, 16);
|
|
26905
|
+
}
|
|
26906
|
+
getDatadogTraceId(sessionId) {
|
|
26907
|
+
const hex = this.getTraceId(sessionId);
|
|
26908
|
+
return BigInt("0x" + hex.substring(16, 32)).toString();
|
|
26909
|
+
}
|
|
26910
|
+
getDatadogSpanId(eventId) {
|
|
26911
|
+
const hex = this.getSpanId(eventId);
|
|
26912
|
+
return BigInt("0x" + hex).toString();
|
|
26913
|
+
}
|
|
26914
|
+
};
|
|
26915
|
+
var traceContext = new TraceContext();
|
|
26916
|
+
var OTLPExporter = class {
|
|
26917
|
+
constructor(config2) {
|
|
26918
|
+
const url = config2.endpoint.replace(/\/+$/, "");
|
|
26919
|
+
this.endpoint = url.endsWith("/v1/traces") ? url : `${url}/v1/traces`;
|
|
26920
|
+
this.headers = {
|
|
26921
|
+
"Content-Type": "application/json",
|
|
26922
|
+
// Using JSON for now for easier debugging
|
|
26923
|
+
...config2.headers
|
|
26924
|
+
};
|
|
26925
|
+
}
|
|
26926
|
+
async export(event) {
|
|
26927
|
+
try {
|
|
26928
|
+
const span = this.convertToOTLPSpan(event);
|
|
26929
|
+
const otlpRequest = {
|
|
26930
|
+
resourceSpans: [
|
|
26931
|
+
{
|
|
26932
|
+
resource: {
|
|
26933
|
+
attributes: [
|
|
26934
|
+
{
|
|
26935
|
+
key: "service.name",
|
|
26936
|
+
value: { stringValue: event.serverName || "mcp-server" }
|
|
26937
|
+
},
|
|
26938
|
+
{
|
|
26939
|
+
key: "service.version",
|
|
26940
|
+
value: { stringValue: event.serverVersion || "unknown" }
|
|
26941
|
+
}
|
|
26942
|
+
]
|
|
26943
|
+
},
|
|
26944
|
+
scopeSpans: [
|
|
26945
|
+
{
|
|
26946
|
+
scope: {
|
|
26947
|
+
name: "mcpcat",
|
|
26948
|
+
version: event.mcpcatVersion || "unknown"
|
|
26949
|
+
},
|
|
26950
|
+
spans: [span]
|
|
26951
|
+
}
|
|
26952
|
+
]
|
|
26953
|
+
}
|
|
26954
|
+
]
|
|
26955
|
+
};
|
|
26956
|
+
const body = JSON.stringify(otlpRequest);
|
|
26957
|
+
const response = await fetch(this.endpoint, {
|
|
26958
|
+
method: "POST",
|
|
26959
|
+
headers: this.headers,
|
|
26960
|
+
body
|
|
26961
|
+
});
|
|
26962
|
+
if (!response.ok) {
|
|
26963
|
+
throw new Error(
|
|
26964
|
+
`OTLP export failed: ${response.status} ${response.statusText}`
|
|
26965
|
+
);
|
|
26966
|
+
}
|
|
26967
|
+
writeToLog(`Successfully exported event to OTLP: ${event.id}`);
|
|
26968
|
+
} catch (error2) {
|
|
26969
|
+
throw new Error(`OTLP export error: ${error2}`);
|
|
26970
|
+
}
|
|
26971
|
+
}
|
|
26972
|
+
convertToOTLPSpan(event) {
|
|
26973
|
+
const startTimeNanos = event.timestamp ? BigInt(event.timestamp.getTime()) * BigInt(1e6) : BigInt(Date.now()) * BigInt(1e6);
|
|
26974
|
+
const endTimeNanos = event.duration ? startTimeNanos + BigInt(event.duration) * BigInt(1e6) : startTimeNanos;
|
|
26975
|
+
return {
|
|
26976
|
+
traceId: traceContext.getTraceId(event.sessionId),
|
|
26977
|
+
spanId: traceContext.getSpanId(event.id),
|
|
26978
|
+
name: event.eventType || "mcp.event",
|
|
26979
|
+
kind: 2,
|
|
26980
|
+
// SPAN_KIND_SERVER
|
|
26981
|
+
startTimeUnixNano: startTimeNanos.toString(),
|
|
26982
|
+
endTimeUnixNano: endTimeNanos.toString(),
|
|
26983
|
+
attributes: [
|
|
26984
|
+
{
|
|
26985
|
+
key: "source",
|
|
26986
|
+
value: { stringValue: MCPCAT_SOURCE }
|
|
26987
|
+
},
|
|
26988
|
+
{
|
|
26989
|
+
key: "mcp.event_type",
|
|
26990
|
+
value: { stringValue: event.eventType || "" }
|
|
26991
|
+
},
|
|
26992
|
+
{
|
|
26993
|
+
key: "mcp.session_id",
|
|
26994
|
+
value: { stringValue: event.sessionId || "" }
|
|
26995
|
+
},
|
|
26996
|
+
{
|
|
26997
|
+
key: "mcp.project_id",
|
|
26998
|
+
value: { stringValue: event.projectId || "" }
|
|
26999
|
+
},
|
|
27000
|
+
{
|
|
27001
|
+
key: "mcp.resource_name",
|
|
27002
|
+
value: { stringValue: event.resourceName || "" }
|
|
27003
|
+
},
|
|
27004
|
+
{
|
|
27005
|
+
key: "mcp.user_intent",
|
|
27006
|
+
value: { stringValue: event.userIntent || "" }
|
|
27007
|
+
},
|
|
27008
|
+
{
|
|
27009
|
+
key: "mcp.actor_id",
|
|
27010
|
+
value: { stringValue: event.identifyActorGivenId || "" }
|
|
27011
|
+
},
|
|
27012
|
+
{
|
|
27013
|
+
key: "mcp.actor_name",
|
|
27014
|
+
value: { stringValue: event.identifyActorName || "" }
|
|
27015
|
+
},
|
|
27016
|
+
{
|
|
27017
|
+
key: "mcp.client_name",
|
|
27018
|
+
value: { stringValue: event.clientName || "" }
|
|
27019
|
+
},
|
|
27020
|
+
{
|
|
27021
|
+
key: "mcp.client_version",
|
|
27022
|
+
value: { stringValue: event.clientVersion || "" }
|
|
27023
|
+
},
|
|
27024
|
+
// Add customer-defined tags as individual attributes
|
|
27025
|
+
...Object.entries(event.tags || {}).map(([key, value]) => ({
|
|
27026
|
+
key: `mcpcat.tag.${key}`,
|
|
27027
|
+
value: { stringValue: value }
|
|
27028
|
+
})),
|
|
27029
|
+
// Add customer-defined properties as JSON
|
|
27030
|
+
...event.properties ? [
|
|
27031
|
+
{
|
|
27032
|
+
key: "mcpcat.properties",
|
|
27033
|
+
value: { stringValue: JSON.stringify(event.properties) }
|
|
27034
|
+
}
|
|
27035
|
+
] : []
|
|
27036
|
+
].filter((attr) => attr.value.stringValue),
|
|
27037
|
+
// Remove empty attributes
|
|
27038
|
+
status: {
|
|
27039
|
+
code: event.isError ? 2 : 1
|
|
27040
|
+
// ERROR : OK
|
|
27041
|
+
}
|
|
27042
|
+
};
|
|
27043
|
+
}
|
|
27044
|
+
};
|
|
27045
|
+
var DatadogExporter = class {
|
|
27046
|
+
constructor(config2) {
|
|
27047
|
+
this.config = config2;
|
|
27048
|
+
const site = config2.site.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
27049
|
+
this.logsUrl = `https://http-intake.logs.${site}/api/v2/logs`;
|
|
27050
|
+
this.metricsUrl = `https://api.${site}/api/v1/series`;
|
|
27051
|
+
}
|
|
27052
|
+
async export(event) {
|
|
27053
|
+
writeToLog("DatadogExporter: Sending event immediately to Datadog");
|
|
27054
|
+
const log = this.eventToLog(event);
|
|
27055
|
+
const metrics = this.eventToMetrics(event);
|
|
27056
|
+
writeToLog(`DatadogExporter: Metrics URL: ${this.metricsUrl}`);
|
|
27057
|
+
writeToLog(
|
|
27058
|
+
`DatadogExporter: Metrics payload: ${JSON.stringify({ series: metrics })}`
|
|
27059
|
+
);
|
|
27060
|
+
const logsPromise = fetch(this.logsUrl, {
|
|
27061
|
+
method: "POST",
|
|
27062
|
+
headers: {
|
|
27063
|
+
"DD-API-KEY": this.config.apiKey,
|
|
27064
|
+
"Content-Type": "application/json"
|
|
27065
|
+
},
|
|
27066
|
+
body: JSON.stringify([log])
|
|
27067
|
+
}).then(async (response) => {
|
|
27068
|
+
if (!response.ok) {
|
|
27069
|
+
const errorBody = await response.text();
|
|
27070
|
+
writeToLog(
|
|
27071
|
+
`Datadog logs failed - Status: ${response.status}, Body: ${errorBody}`
|
|
27072
|
+
);
|
|
27073
|
+
} else {
|
|
27074
|
+
writeToLog(`Datadog logs success - Status: ${response.status}`);
|
|
27075
|
+
}
|
|
27076
|
+
return response;
|
|
27077
|
+
}).catch((err) => {
|
|
27078
|
+
writeToLog(`Datadog logs network error: ${err}`);
|
|
27079
|
+
});
|
|
27080
|
+
const metricsPromise = fetch(this.metricsUrl, {
|
|
27081
|
+
method: "POST",
|
|
27082
|
+
headers: {
|
|
27083
|
+
"DD-API-KEY": this.config.apiKey,
|
|
27084
|
+
"Content-Type": "application/json"
|
|
27085
|
+
},
|
|
27086
|
+
body: JSON.stringify({ series: metrics })
|
|
27087
|
+
}).then(async (response) => {
|
|
27088
|
+
if (!response.ok) {
|
|
27089
|
+
const errorBody = await response.text();
|
|
27090
|
+
writeToLog(
|
|
27091
|
+
`Datadog metrics failed - Status: ${response.status}, Body: ${errorBody}`
|
|
27092
|
+
);
|
|
27093
|
+
} else {
|
|
27094
|
+
const responseBody = await response.text();
|
|
27095
|
+
writeToLog(
|
|
27096
|
+
`Datadog metrics success - Status: ${response.status}, Body: ${responseBody}`
|
|
27097
|
+
);
|
|
27098
|
+
}
|
|
27099
|
+
return response;
|
|
27100
|
+
}).catch((err) => {
|
|
27101
|
+
writeToLog(`Datadog metrics network error: ${err}`);
|
|
27102
|
+
});
|
|
27103
|
+
await Promise.all([logsPromise, metricsPromise]);
|
|
27104
|
+
}
|
|
27105
|
+
eventToLog(event) {
|
|
27106
|
+
const tags = [];
|
|
27107
|
+
if (this.config.env) tags.push(`env:${this.config.env}`);
|
|
27108
|
+
if (event.eventType)
|
|
27109
|
+
tags.push(`event_type:${event.eventType.replace(/\//g, ".")}`);
|
|
27110
|
+
if (event.resourceName) tags.push(`resource:${event.resourceName}`);
|
|
27111
|
+
if (event.isError) tags.push("error:true");
|
|
27112
|
+
tags.push(`source:${MCPCAT_SOURCE}`);
|
|
27113
|
+
if (event.tags) {
|
|
27114
|
+
for (const [key, value] of Object.entries(event.tags)) {
|
|
27115
|
+
const sanitizedKey = key.toLowerCase().replace(/[\s:,]+/g, "_");
|
|
27116
|
+
const sanitizedValue = value.replace(/,/g, "_");
|
|
27117
|
+
tags.push(`mcpcat.${sanitizedKey}:${sanitizedValue}`);
|
|
27118
|
+
}
|
|
27119
|
+
}
|
|
27120
|
+
const log = {
|
|
27121
|
+
message: `${event.eventType || "unknown"} - ${event.resourceName || "unknown"}`,
|
|
27122
|
+
service: this.config.service,
|
|
27123
|
+
ddsource: MCPCAT_SOURCE,
|
|
27124
|
+
ddtags: tags.join(","),
|
|
27125
|
+
timestamp: event.timestamp ? event.timestamp.getTime() : Date.now(),
|
|
27126
|
+
status: event.isError ? "error" : "info",
|
|
27127
|
+
dd: {
|
|
27128
|
+
trace_id: traceContext.getDatadogTraceId(event.sessionId),
|
|
27129
|
+
span_id: traceContext.getDatadogSpanId(event.id)
|
|
27130
|
+
},
|
|
27131
|
+
mcp: {
|
|
27132
|
+
session_id: event.sessionId,
|
|
27133
|
+
event_id: event.id,
|
|
27134
|
+
event_type: event.eventType,
|
|
27135
|
+
resource: event.resourceName,
|
|
27136
|
+
duration_ms: event.duration,
|
|
27137
|
+
user_intent: event.userIntent,
|
|
27138
|
+
actor_id: event.identifyActorGivenId,
|
|
27139
|
+
actor_name: event.identifyActorName,
|
|
27140
|
+
client_name: event.clientName,
|
|
27141
|
+
client_version: event.clientVersion,
|
|
27142
|
+
server_name: event.serverName,
|
|
27143
|
+
server_version: event.serverVersion,
|
|
27144
|
+
is_error: event.isError,
|
|
27145
|
+
error: event.error,
|
|
27146
|
+
tags: event.tags,
|
|
27147
|
+
properties: event.properties
|
|
27148
|
+
}
|
|
27149
|
+
};
|
|
27150
|
+
if (event.isError && event.error) {
|
|
27151
|
+
log.error = {
|
|
27152
|
+
message: typeof event.error === "string" ? event.error : JSON.stringify(event.error)
|
|
27153
|
+
};
|
|
27154
|
+
}
|
|
27155
|
+
return log;
|
|
27156
|
+
}
|
|
27157
|
+
eventToMetrics(event) {
|
|
27158
|
+
const metrics = [];
|
|
27159
|
+
const timestamp = Math.floor(
|
|
27160
|
+
(event.timestamp?.getTime() || Date.now()) / 1e3
|
|
27161
|
+
);
|
|
27162
|
+
const tags = [`service:${this.config.service}`];
|
|
27163
|
+
if (this.config.env) tags.push(`env:${this.config.env}`);
|
|
27164
|
+
if (event.eventType)
|
|
27165
|
+
tags.push(`event_type:${event.eventType.replace(/\//g, ".")}`);
|
|
27166
|
+
if (event.resourceName) tags.push(`resource:${event.resourceName}`);
|
|
27167
|
+
metrics.push({
|
|
27168
|
+
metric: "mcp.events.count",
|
|
27169
|
+
type: "count",
|
|
27170
|
+
points: [[timestamp, 1]],
|
|
27171
|
+
tags
|
|
27172
|
+
});
|
|
27173
|
+
if (event.duration) {
|
|
27174
|
+
metrics.push({
|
|
27175
|
+
metric: "mcp.event.duration",
|
|
27176
|
+
type: "gauge",
|
|
27177
|
+
points: [[timestamp, event.duration]],
|
|
27178
|
+
tags
|
|
27179
|
+
});
|
|
27180
|
+
}
|
|
27181
|
+
if (event.isError) {
|
|
27182
|
+
metrics.push({
|
|
27183
|
+
metric: "mcp.errors.count",
|
|
27184
|
+
type: "count",
|
|
27185
|
+
points: [[timestamp, 1]],
|
|
27186
|
+
tags
|
|
27187
|
+
});
|
|
27188
|
+
}
|
|
27189
|
+
return metrics;
|
|
27190
|
+
}
|
|
27191
|
+
};
|
|
27192
|
+
var SentryExporter = class {
|
|
27193
|
+
constructor(config2) {
|
|
27194
|
+
this.config = config2;
|
|
27195
|
+
this.parsedDSN = this.parseDSN(config2.dsn);
|
|
27196
|
+
this.endpoint = `${this.parsedDSN.protocol}://${this.parsedDSN.host}${this.parsedDSN.port ? `:${this.parsedDSN.port}` : ""}${this.parsedDSN.path}/api/${this.parsedDSN.projectId}/envelope/`;
|
|
27197
|
+
this.authHeader = `Sentry sentry_version=7, sentry_client=mcpcat/1.0.0, sentry_key=${this.parsedDSN.publicKey}`;
|
|
27198
|
+
writeToLog(`SentryExporter: Initialized with endpoint ${this.endpoint}`);
|
|
27199
|
+
}
|
|
27200
|
+
parseDSN(dsn) {
|
|
27201
|
+
const regex = /^(https?):\/\/([a-f0-9]+)@([\w.-]+)(:\d+)?(\/.*)?\/(\d+)$/;
|
|
27202
|
+
const match = dsn.match(regex);
|
|
27203
|
+
if (!match) {
|
|
27204
|
+
throw new Error(`Invalid Sentry DSN: ${dsn}`);
|
|
27205
|
+
}
|
|
27206
|
+
return {
|
|
27207
|
+
protocol: match[1],
|
|
27208
|
+
publicKey: match[2],
|
|
27209
|
+
host: match[3],
|
|
27210
|
+
port: match[4]?.substring(1),
|
|
27211
|
+
// Remove leading ':'
|
|
27212
|
+
path: match[5] || "",
|
|
27213
|
+
projectId: match[6]
|
|
27214
|
+
};
|
|
27215
|
+
}
|
|
27216
|
+
async export(event) {
|
|
27217
|
+
try {
|
|
27218
|
+
const log = this.eventToLog(event);
|
|
27219
|
+
const logEnvelope = this.createLogEnvelope(log);
|
|
27220
|
+
writeToLog(`SentryExporter: Sending log for event ${event.id} to Sentry`);
|
|
27221
|
+
const logResponse = await fetch(this.endpoint, {
|
|
27222
|
+
method: "POST",
|
|
27223
|
+
headers: {
|
|
27224
|
+
"X-Sentry-Auth": this.authHeader,
|
|
27225
|
+
"Content-Type": "application/x-sentry-envelope"
|
|
27226
|
+
},
|
|
27227
|
+
body: logEnvelope
|
|
27228
|
+
});
|
|
27229
|
+
if (!logResponse.ok) {
|
|
27230
|
+
const errorBody = await logResponse.text();
|
|
27231
|
+
writeToLog(
|
|
27232
|
+
`Sentry log export failed - Status: ${logResponse.status}, Body: ${errorBody}`
|
|
27233
|
+
);
|
|
27234
|
+
} else {
|
|
27235
|
+
writeToLog(`Sentry log export success - Event: ${event.id}`);
|
|
27236
|
+
}
|
|
27237
|
+
if (this.config.enableTracing) {
|
|
27238
|
+
const transaction = this.eventToTransaction(event);
|
|
27239
|
+
const transactionEnvelope = this.createTransactionEnvelope(transaction);
|
|
27240
|
+
writeToLog(
|
|
27241
|
+
`SentryExporter: Sending transaction ${transaction.event_id} to Sentry`
|
|
27242
|
+
);
|
|
27243
|
+
const transactionResponse = await fetch(this.endpoint, {
|
|
27244
|
+
method: "POST",
|
|
27245
|
+
headers: {
|
|
27246
|
+
"X-Sentry-Auth": this.authHeader,
|
|
27247
|
+
"Content-Type": "application/x-sentry-envelope"
|
|
27248
|
+
},
|
|
27249
|
+
body: transactionEnvelope
|
|
27250
|
+
});
|
|
27251
|
+
if (!transactionResponse.ok) {
|
|
27252
|
+
const errorBody = await transactionResponse.text();
|
|
27253
|
+
writeToLog(
|
|
27254
|
+
`Sentry transaction export failed - Status: ${transactionResponse.status}, Body: ${errorBody}`
|
|
27255
|
+
);
|
|
27256
|
+
} else {
|
|
27257
|
+
writeToLog(`Sentry transaction export success - Event: ${event.id}`);
|
|
27258
|
+
}
|
|
27259
|
+
}
|
|
27260
|
+
if (event.isError) {
|
|
27261
|
+
const errorEvent = this.config.enableTracing ? this.eventToErrorEvent(event, this.eventToTransaction(event)) : this.eventToErrorEvent(event);
|
|
27262
|
+
const errorEnvelope = this.createErrorEnvelope(errorEvent);
|
|
27263
|
+
writeToLog(
|
|
27264
|
+
`SentryExporter: Sending error event ${errorEvent.event_id} to Sentry for Issue creation`
|
|
27265
|
+
);
|
|
27266
|
+
const errorResponse = await fetch(this.endpoint, {
|
|
27267
|
+
method: "POST",
|
|
27268
|
+
headers: {
|
|
27269
|
+
"X-Sentry-Auth": this.authHeader,
|
|
27270
|
+
"Content-Type": "application/x-sentry-envelope"
|
|
27271
|
+
},
|
|
27272
|
+
body: errorEnvelope
|
|
27273
|
+
});
|
|
27274
|
+
if (!errorResponse.ok) {
|
|
27275
|
+
const errorBody = await errorResponse.text();
|
|
27276
|
+
writeToLog(
|
|
27277
|
+
`Sentry error export failed - Status: ${errorResponse.status}, Body: ${errorBody}`
|
|
27278
|
+
);
|
|
27279
|
+
} else {
|
|
27280
|
+
writeToLog(`Sentry error export success - Event: ${event.id}`);
|
|
27281
|
+
}
|
|
27282
|
+
}
|
|
27283
|
+
} catch (error2) {
|
|
27284
|
+
writeToLog(`Sentry export error: ${error2}`);
|
|
27285
|
+
}
|
|
27286
|
+
}
|
|
27287
|
+
eventToLog(event) {
|
|
27288
|
+
const timestamp = event.timestamp ? new Date(event.timestamp).getTime() / 1e3 : Date.now() / 1e3;
|
|
27289
|
+
const traceId = traceContext.getTraceId(event.sessionId);
|
|
27290
|
+
const eventId = traceContext.getSpanId(event.id) + traceContext.getSpanId(event.id);
|
|
27291
|
+
const message = event.resourceName ? `MCP ${event.eventType || "event"}: ${event.resourceName}` : `MCP ${event.eventType || "event"}`;
|
|
27292
|
+
return {
|
|
27293
|
+
timestamp,
|
|
27294
|
+
trace_id: traceId,
|
|
27295
|
+
event_id: eventId,
|
|
27296
|
+
level: event.isError ? "error" : "info",
|
|
27297
|
+
body: message,
|
|
27298
|
+
attributes: this.buildLogAttributes(event)
|
|
27299
|
+
};
|
|
27300
|
+
}
|
|
27301
|
+
buildLogAttributes(event) {
|
|
27302
|
+
const attributes = {};
|
|
27303
|
+
if (event.eventType) {
|
|
27304
|
+
attributes.eventType = { value: event.eventType, type: "string" };
|
|
27305
|
+
}
|
|
27306
|
+
if (event.resourceName) {
|
|
27307
|
+
attributes.resourceName = { value: event.resourceName, type: "string" };
|
|
27308
|
+
}
|
|
27309
|
+
if (event.serverName) {
|
|
27310
|
+
attributes.serverName = { value: event.serverName, type: "string" };
|
|
27311
|
+
}
|
|
27312
|
+
if (event.clientName) {
|
|
27313
|
+
attributes.clientName = { value: event.clientName, type: "string" };
|
|
27314
|
+
}
|
|
27315
|
+
if (event.sessionId) {
|
|
27316
|
+
attributes.sessionId = { value: event.sessionId, type: "string" };
|
|
27317
|
+
}
|
|
27318
|
+
if (event.projectId) {
|
|
27319
|
+
attributes.projectId = { value: event.projectId, type: "string" };
|
|
27320
|
+
}
|
|
27321
|
+
if (event.duration !== void 0) {
|
|
27322
|
+
attributes.duration_ms = { value: event.duration, type: "double" };
|
|
27323
|
+
}
|
|
27324
|
+
if (event.identifyActorGivenId) {
|
|
27325
|
+
attributes.actorId = {
|
|
27326
|
+
value: event.identifyActorGivenId,
|
|
27327
|
+
type: "string"
|
|
27328
|
+
};
|
|
27329
|
+
}
|
|
27330
|
+
if (event.identifyActorName) {
|
|
27331
|
+
attributes.actorName = { value: event.identifyActorName, type: "string" };
|
|
27332
|
+
}
|
|
27333
|
+
if (event.userIntent) {
|
|
27334
|
+
attributes.userIntent = { value: event.userIntent, type: "string" };
|
|
27335
|
+
}
|
|
27336
|
+
if (event.serverVersion) {
|
|
27337
|
+
attributes.serverVersion = { value: event.serverVersion, type: "string" };
|
|
27338
|
+
}
|
|
27339
|
+
if (event.clientVersion) {
|
|
27340
|
+
attributes.clientVersion = { value: event.clientVersion, type: "string" };
|
|
27341
|
+
}
|
|
27342
|
+
if (event.isError !== void 0) {
|
|
27343
|
+
attributes.isError = { value: event.isError, type: "boolean" };
|
|
27344
|
+
}
|
|
27345
|
+
return attributes;
|
|
27346
|
+
}
|
|
27347
|
+
createLogEnvelope(log) {
|
|
27348
|
+
const envelopeHeader = {
|
|
27349
|
+
event_id: log.event_id,
|
|
27350
|
+
sent_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
27351
|
+
};
|
|
27352
|
+
const itemHeader = {
|
|
27353
|
+
type: "log",
|
|
27354
|
+
item_count: 1,
|
|
27355
|
+
// MANDATORY - must match number of logs
|
|
27356
|
+
content_type: "application/vnd.sentry.items.log+json"
|
|
27357
|
+
// MANDATORY - exact string
|
|
27358
|
+
};
|
|
27359
|
+
const payload = {
|
|
27360
|
+
items: [log]
|
|
27361
|
+
// Changed from 'logs' to 'items'
|
|
27362
|
+
};
|
|
27363
|
+
return [
|
|
27364
|
+
JSON.stringify(envelopeHeader),
|
|
27365
|
+
JSON.stringify(itemHeader),
|
|
27366
|
+
JSON.stringify(payload)
|
|
27367
|
+
].join("\n") + "\n";
|
|
27368
|
+
}
|
|
27369
|
+
eventToTransaction(event) {
|
|
27370
|
+
const endTimestamp = event.timestamp ? new Date(event.timestamp).getTime() / 1e3 : Date.now() / 1e3;
|
|
27371
|
+
const startTimestamp = event.duration ? endTimestamp - event.duration / 1e3 : endTimestamp;
|
|
27372
|
+
const traceId = traceContext.getTraceId(event.sessionId);
|
|
27373
|
+
const spanId = traceContext.getSpanId(event.id);
|
|
27374
|
+
const transactionName = event.resourceName ? `${event.eventType || "mcp"} - ${event.resourceName}` : event.eventType || "mcp.event";
|
|
27375
|
+
const transaction = {
|
|
27376
|
+
type: "transaction",
|
|
27377
|
+
event_id: traceContext.getSpanId(event.id) + traceContext.getSpanId(),
|
|
27378
|
+
timestamp: endTimestamp,
|
|
27379
|
+
start_timestamp: startTimestamp,
|
|
27380
|
+
transaction: transactionName,
|
|
27381
|
+
contexts: this.buildContexts(event, {
|
|
27382
|
+
trace_id: traceId,
|
|
27383
|
+
span_id: spanId,
|
|
27384
|
+
op: event.eventType || "mcp.event",
|
|
27385
|
+
status: event.isError ? "internal_error" : "ok"
|
|
27386
|
+
}),
|
|
27387
|
+
tags: this.buildTags(event),
|
|
27388
|
+
extra: this.buildExtra(event)
|
|
27389
|
+
};
|
|
27390
|
+
return transaction;
|
|
27391
|
+
}
|
|
27392
|
+
buildTags(event) {
|
|
27393
|
+
const tags = {
|
|
27394
|
+
source: MCPCAT_SOURCE
|
|
27395
|
+
};
|
|
27396
|
+
if (this.config.environment) tags.environment = this.config.environment;
|
|
27397
|
+
if (this.config.release) tags.release = this.config.release;
|
|
27398
|
+
if (event.eventType) tags.event_type = event.eventType;
|
|
27399
|
+
if (event.resourceName) tags.resource = event.resourceName;
|
|
27400
|
+
if (event.serverName) tags.server_name = event.serverName;
|
|
27401
|
+
if (event.clientName) tags.client_name = event.clientName;
|
|
27402
|
+
if (event.identifyActorGivenId) tags.actor_id = event.identifyActorGivenId;
|
|
27403
|
+
if (event.tags) {
|
|
27404
|
+
for (const [key, value] of Object.entries(event.tags)) {
|
|
27405
|
+
tags[`mcpcat.${key}`] = value;
|
|
27406
|
+
}
|
|
27407
|
+
}
|
|
27408
|
+
return tags;
|
|
27409
|
+
}
|
|
27410
|
+
buildExtra(event) {
|
|
27411
|
+
const extra = {};
|
|
27412
|
+
if (event.sessionId) extra.session_id = event.sessionId;
|
|
27413
|
+
if (event.projectId) extra.project_id = event.projectId;
|
|
27414
|
+
if (event.userIntent) extra.user_intent = event.userIntent;
|
|
27415
|
+
if (event.identifyActorName) extra.actor_name = event.identifyActorName;
|
|
27416
|
+
if (event.serverVersion) extra.server_version = event.serverVersion;
|
|
27417
|
+
if (event.clientVersion) extra.client_version = event.clientVersion;
|
|
27418
|
+
if (event.duration !== void 0) extra.duration_ms = event.duration;
|
|
27419
|
+
if (event.error) extra.error = event.error;
|
|
27420
|
+
return extra;
|
|
27421
|
+
}
|
|
27422
|
+
buildContexts(event, traceCtx) {
|
|
27423
|
+
const contexts = {
|
|
27424
|
+
trace: traceCtx
|
|
27425
|
+
};
|
|
27426
|
+
if (event.properties) {
|
|
27427
|
+
contexts.mcpcat = event.properties;
|
|
27428
|
+
}
|
|
27429
|
+
return contexts;
|
|
27430
|
+
}
|
|
27431
|
+
eventToErrorEvent(event, transaction) {
|
|
27432
|
+
let errorMessage = "Unknown error";
|
|
27433
|
+
let errorType = "ToolCallError";
|
|
27434
|
+
if (event.error) {
|
|
27435
|
+
if (typeof event.error === "string") {
|
|
27436
|
+
errorMessage = event.error;
|
|
27437
|
+
} else if (typeof event.error === "object" && event.error !== null) {
|
|
27438
|
+
if ("message" in event.error) {
|
|
27439
|
+
errorMessage = String(event.error.message);
|
|
27440
|
+
} else {
|
|
27441
|
+
errorMessage = JSON.stringify(event.error);
|
|
27442
|
+
}
|
|
27443
|
+
if ("type" in event.error) {
|
|
27444
|
+
errorType = String(event.error.type);
|
|
27445
|
+
}
|
|
27446
|
+
}
|
|
27447
|
+
}
|
|
27448
|
+
const traceId = transaction ? transaction.contexts.trace.trace_id : traceContext.getTraceId(event.sessionId);
|
|
27449
|
+
const spanId = traceContext.getSpanId(event.id);
|
|
27450
|
+
const timestamp = transaction ? transaction.timestamp : event.timestamp ? new Date(event.timestamp).getTime() / 1e3 : Date.now() / 1e3;
|
|
27451
|
+
const errorEvent = {
|
|
27452
|
+
type: "event",
|
|
27453
|
+
event_id: traceContext.getSpanId(event.id) + traceContext.getSpanId(),
|
|
27454
|
+
timestamp,
|
|
27455
|
+
level: "error",
|
|
27456
|
+
exception: {
|
|
27457
|
+
values: [
|
|
27458
|
+
{
|
|
27459
|
+
type: errorType,
|
|
27460
|
+
value: errorMessage,
|
|
27461
|
+
mechanism: {
|
|
27462
|
+
type: "mcp_tool_call",
|
|
27463
|
+
handled: false
|
|
27464
|
+
}
|
|
27465
|
+
}
|
|
27466
|
+
]
|
|
27467
|
+
},
|
|
27468
|
+
contexts: {
|
|
27469
|
+
...this.buildContexts(event, {
|
|
27470
|
+
trace_id: traceId,
|
|
27471
|
+
span_id: spanId,
|
|
27472
|
+
parent_span_id: transaction?.contexts.trace.span_id,
|
|
27473
|
+
op: transaction?.contexts.trace.op || event.eventType || "mcp.event"
|
|
27474
|
+
}),
|
|
27475
|
+
mcp: {
|
|
27476
|
+
resource_name: event.resourceName,
|
|
27477
|
+
session_id: event.sessionId,
|
|
27478
|
+
event_type: event.eventType,
|
|
27479
|
+
user_intent: event.userIntent
|
|
27480
|
+
}
|
|
27481
|
+
},
|
|
27482
|
+
tags: this.buildTags(event),
|
|
27483
|
+
extra: this.buildExtra(event),
|
|
27484
|
+
transaction: transaction?.transaction || (event.resourceName ? `${event.eventType || "mcp"} - ${event.resourceName}` : event.eventType || "mcp.event")
|
|
27485
|
+
// Generate transaction name if not available
|
|
27486
|
+
};
|
|
27487
|
+
return errorEvent;
|
|
27488
|
+
}
|
|
27489
|
+
createTransactionEnvelope(transaction) {
|
|
27490
|
+
const envelopeHeader = {
|
|
27491
|
+
event_id: transaction.event_id,
|
|
27492
|
+
sent_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
27493
|
+
};
|
|
27494
|
+
const itemHeader = {
|
|
27495
|
+
type: "transaction"
|
|
27496
|
+
};
|
|
27497
|
+
return [
|
|
27498
|
+
JSON.stringify(envelopeHeader),
|
|
27499
|
+
JSON.stringify(itemHeader),
|
|
27500
|
+
JSON.stringify(transaction)
|
|
27501
|
+
].join("\n");
|
|
27502
|
+
}
|
|
27503
|
+
createErrorEnvelope(errorEvent) {
|
|
27504
|
+
const envelopeHeader = {
|
|
27505
|
+
event_id: errorEvent.event_id,
|
|
27506
|
+
sent_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
27507
|
+
};
|
|
27508
|
+
const itemHeader = {
|
|
27509
|
+
type: "event",
|
|
27510
|
+
content_type: "application/json"
|
|
27511
|
+
};
|
|
27512
|
+
return [
|
|
27513
|
+
JSON.stringify(envelopeHeader),
|
|
27514
|
+
JSON.stringify(itemHeader),
|
|
27515
|
+
JSON.stringify(errorEvent)
|
|
27516
|
+
].join("\n");
|
|
27517
|
+
}
|
|
27518
|
+
};
|
|
27519
|
+
function toUUIDv7(prefixedId) {
|
|
27520
|
+
const ksuidStr = prefixedId.replace(/^[a-z]+_/, "");
|
|
27521
|
+
let timestampMs;
|
|
27522
|
+
try {
|
|
27523
|
+
const ksuid2 = ksuid_default.parse(ksuidStr);
|
|
27524
|
+
timestampMs = ksuid2.date.getTime();
|
|
27525
|
+
} catch {
|
|
27526
|
+
timestampMs = Date.now();
|
|
27527
|
+
}
|
|
27528
|
+
const hash = createHash3("sha256").update(prefixedId).digest();
|
|
27529
|
+
const buf = Buffer.alloc(16);
|
|
27530
|
+
buf.writeUIntBE(timestampMs, 0, 6);
|
|
27531
|
+
buf[6] = 112 | hash[0] & 15;
|
|
27532
|
+
buf[7] = hash[1];
|
|
27533
|
+
buf[8] = 128 | hash[2] & 63;
|
|
27534
|
+
buf[9] = hash[3];
|
|
27535
|
+
buf[10] = hash[4];
|
|
27536
|
+
buf[11] = hash[5];
|
|
27537
|
+
buf[12] = hash[6];
|
|
27538
|
+
buf[13] = hash[7];
|
|
27539
|
+
buf[14] = hash[8];
|
|
27540
|
+
buf[15] = hash[9];
|
|
27541
|
+
const hex = buf.toString("hex");
|
|
27542
|
+
return [
|
|
27543
|
+
hex.substring(0, 8),
|
|
27544
|
+
hex.substring(8, 12),
|
|
27545
|
+
hex.substring(12, 16),
|
|
27546
|
+
hex.substring(16, 20),
|
|
27547
|
+
hex.substring(20, 32)
|
|
27548
|
+
].join("-");
|
|
27549
|
+
}
|
|
27550
|
+
function getDistinctId(event) {
|
|
27551
|
+
return event.identifyActorGivenId || event.sessionId || "anonymous";
|
|
27552
|
+
}
|
|
27553
|
+
function getTimestamp(event) {
|
|
27554
|
+
return event.timestamp ? event.timestamp.toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
27555
|
+
}
|
|
27556
|
+
var PostHogExporter = class {
|
|
27557
|
+
constructor(config2) {
|
|
27558
|
+
this.config = config2;
|
|
27559
|
+
const host = (config2.host || "https://us.i.posthog.com").replace(/\/$/, "");
|
|
27560
|
+
this.batchUrl = `${host}/batch`;
|
|
27561
|
+
this.apiKey = config2.apiKey;
|
|
27562
|
+
writeToLog(`PostHogExporter: Initialized with endpoint ${this.batchUrl}`);
|
|
27563
|
+
}
|
|
27564
|
+
async export(event) {
|
|
27565
|
+
try {
|
|
27566
|
+
const batch = [];
|
|
27567
|
+
batch.push(this.buildCaptureEvent(event));
|
|
27568
|
+
if (event.isError && event.error) {
|
|
27569
|
+
batch.push(this.buildExceptionEvent(event));
|
|
27570
|
+
}
|
|
27571
|
+
if (this.config.enableAITracing && event.eventType === PublishEventRequestEventTypeEnum.mcpToolsCall) {
|
|
27572
|
+
batch.push(this.buildAISpanEvent(event));
|
|
27573
|
+
}
|
|
27574
|
+
writeToLog(
|
|
27575
|
+
`PostHogExporter: Sending ${batch.length} event(s) for ${event.id}`
|
|
27576
|
+
);
|
|
27577
|
+
const response = await fetch(this.batchUrl, {
|
|
27578
|
+
method: "POST",
|
|
27579
|
+
headers: {
|
|
27580
|
+
"Content-Type": "application/json"
|
|
27581
|
+
},
|
|
27582
|
+
body: JSON.stringify({
|
|
27583
|
+
api_key: this.apiKey,
|
|
27584
|
+
batch
|
|
27585
|
+
})
|
|
27586
|
+
});
|
|
27587
|
+
if (!response.ok) {
|
|
27588
|
+
const errorBody = await response.text();
|
|
27589
|
+
writeToLog(
|
|
27590
|
+
`PostHog export failed - Status: ${response.status}, Body: ${errorBody}`
|
|
27591
|
+
);
|
|
27592
|
+
} else {
|
|
27593
|
+
writeToLog(`PostHog export success - Event: ${event.id}`);
|
|
27594
|
+
}
|
|
27595
|
+
} catch (error2) {
|
|
27596
|
+
writeToLog(`PostHog export error: ${error2}`);
|
|
27597
|
+
}
|
|
27598
|
+
}
|
|
27599
|
+
buildCaptureEvent(event) {
|
|
27600
|
+
const distinctId = getDistinctId(event);
|
|
27601
|
+
const eventName = this.mapEventType(event.eventType);
|
|
27602
|
+
const timestamp = getTimestamp(event);
|
|
27603
|
+
const properties = {
|
|
27604
|
+
$session_id: toUUIDv7(event.sessionId),
|
|
27605
|
+
source: MCPCAT_SOURCE
|
|
27606
|
+
};
|
|
27607
|
+
if (event.resourceName) {
|
|
27608
|
+
properties.resource_name = event.resourceName;
|
|
27609
|
+
if (event.eventType === PublishEventRequestEventTypeEnum.mcpToolsCall) {
|
|
27610
|
+
properties.tool_name = event.resourceName;
|
|
27611
|
+
}
|
|
27612
|
+
}
|
|
27613
|
+
if (event.duration !== void 0) {
|
|
27614
|
+
properties.duration_ms = event.duration;
|
|
27615
|
+
}
|
|
27616
|
+
if (event.serverName) properties.server_name = event.serverName;
|
|
27617
|
+
if (event.serverVersion) properties.server_version = event.serverVersion;
|
|
27618
|
+
if (event.clientName) properties.client_name = event.clientName;
|
|
27619
|
+
if (event.clientVersion) properties.client_version = event.clientVersion;
|
|
27620
|
+
if (event.projectId) properties.project_id = event.projectId;
|
|
27621
|
+
if (event.userIntent) properties.user_intent = event.userIntent;
|
|
27622
|
+
if (event.isError !== void 0) properties.is_error = event.isError;
|
|
27623
|
+
if (event.parameters !== void 0) {
|
|
27624
|
+
properties.parameters = event.parameters;
|
|
27625
|
+
}
|
|
27626
|
+
if (event.response !== void 0) {
|
|
27627
|
+
properties.response = event.response;
|
|
27628
|
+
}
|
|
27629
|
+
const $set = {};
|
|
27630
|
+
if (event.identifyActorName) $set.name = event.identifyActorName;
|
|
27631
|
+
if (event.identifyActorData) {
|
|
27632
|
+
Object.assign($set, event.identifyActorData);
|
|
27633
|
+
}
|
|
27634
|
+
if (Object.keys($set).length > 0) {
|
|
27635
|
+
properties.$set = $set;
|
|
27636
|
+
}
|
|
27637
|
+
if (event.tags) {
|
|
27638
|
+
for (const [key, value] of Object.entries(event.tags)) {
|
|
27639
|
+
properties[key] = value;
|
|
27640
|
+
}
|
|
27641
|
+
}
|
|
27642
|
+
if (event.properties) {
|
|
27643
|
+
for (const [key, value] of Object.entries(event.properties)) {
|
|
27644
|
+
properties[key] = value;
|
|
27645
|
+
}
|
|
27646
|
+
}
|
|
27647
|
+
return {
|
|
27648
|
+
event: eventName,
|
|
27649
|
+
distinct_id: distinctId,
|
|
27650
|
+
properties,
|
|
27651
|
+
timestamp,
|
|
27652
|
+
type: "capture"
|
|
27653
|
+
};
|
|
27654
|
+
}
|
|
27655
|
+
buildExceptionEvent(event) {
|
|
27656
|
+
const distinctId = getDistinctId(event);
|
|
27657
|
+
const timestamp = getTimestamp(event);
|
|
27658
|
+
const properties = {
|
|
27659
|
+
$exception_source: "backend",
|
|
27660
|
+
$session_id: toUUIDv7(event.sessionId)
|
|
27661
|
+
};
|
|
27662
|
+
if (event.error) {
|
|
27663
|
+
if (event.error.message) {
|
|
27664
|
+
properties.$exception_message = event.error.message;
|
|
27665
|
+
}
|
|
27666
|
+
if (event.error.type) {
|
|
27667
|
+
properties.$exception_type = event.error.type;
|
|
27668
|
+
}
|
|
27669
|
+
if (event.error.stack) {
|
|
27670
|
+
properties.$exception_stacktrace = event.error.stack;
|
|
27671
|
+
}
|
|
27672
|
+
}
|
|
27673
|
+
if (event.resourceName) {
|
|
27674
|
+
properties.resource_name = event.resourceName;
|
|
27675
|
+
if (event.eventType === PublishEventRequestEventTypeEnum.mcpToolsCall) {
|
|
27676
|
+
properties.tool_name = event.resourceName;
|
|
27677
|
+
}
|
|
27678
|
+
}
|
|
27679
|
+
if (event.serverName) properties.server_name = event.serverName;
|
|
27680
|
+
if (event.serverVersion) properties.server_version = event.serverVersion;
|
|
27681
|
+
if (event.clientName) properties.client_name = event.clientName;
|
|
27682
|
+
if (event.clientVersion) properties.client_version = event.clientVersion;
|
|
27683
|
+
return {
|
|
27684
|
+
event: "$exception",
|
|
27685
|
+
distinct_id: distinctId,
|
|
27686
|
+
properties,
|
|
27687
|
+
timestamp,
|
|
27688
|
+
type: "capture"
|
|
27689
|
+
};
|
|
27690
|
+
}
|
|
27691
|
+
buildAISpanEvent(event) {
|
|
27692
|
+
const distinctId = getDistinctId(event);
|
|
27693
|
+
const timestamp = getTimestamp(event);
|
|
27694
|
+
const properties = {
|
|
27695
|
+
$ai_session_id: `mcpcat_${event.sessionId}`,
|
|
27696
|
+
$ai_trace_id: toUUIDv7(event.sessionId),
|
|
27697
|
+
$ai_span_id: toUUIDv7(event.id),
|
|
27698
|
+
$ai_span_name: event.resourceName || "unknown_tool",
|
|
27699
|
+
$ai_is_error: event.isError || false,
|
|
27700
|
+
$session_id: toUUIDv7(event.sessionId),
|
|
27701
|
+
source: MCPCAT_SOURCE
|
|
27702
|
+
};
|
|
27703
|
+
if (event.duration !== void 0) {
|
|
27704
|
+
properties.$ai_latency = event.duration / 1e3;
|
|
27705
|
+
}
|
|
27706
|
+
if (event.isError && event.error) {
|
|
27707
|
+
properties.$ai_error = event.error;
|
|
27708
|
+
}
|
|
27709
|
+
if (event.parameters !== void 0) {
|
|
27710
|
+
properties.$ai_input_state = event.parameters;
|
|
27711
|
+
}
|
|
27712
|
+
if (event.response !== void 0) {
|
|
27713
|
+
properties.$ai_output_state = event.response;
|
|
27714
|
+
}
|
|
27715
|
+
if (event.serverName) properties.server_name = event.serverName;
|
|
27716
|
+
if (event.clientName) properties.client_name = event.clientName;
|
|
27717
|
+
if (event.tags) {
|
|
27718
|
+
for (const [key, value] of Object.entries(event.tags)) {
|
|
27719
|
+
properties[key] = value;
|
|
27720
|
+
}
|
|
27721
|
+
}
|
|
27722
|
+
if (event.properties) {
|
|
27723
|
+
for (const [key, value] of Object.entries(event.properties)) {
|
|
27724
|
+
properties[key] = value;
|
|
27725
|
+
}
|
|
27726
|
+
}
|
|
27727
|
+
return {
|
|
27728
|
+
event: "$ai_span",
|
|
27729
|
+
distinct_id: distinctId,
|
|
27730
|
+
properties,
|
|
27731
|
+
timestamp,
|
|
27732
|
+
type: "capture"
|
|
27733
|
+
};
|
|
27734
|
+
}
|
|
27735
|
+
mapEventType(eventType) {
|
|
27736
|
+
const mapping = {
|
|
27737
|
+
[PublishEventRequestEventTypeEnum.mcpToolsCall]: "mcp_tool_call",
|
|
27738
|
+
[PublishEventRequestEventTypeEnum.mcpToolsList]: "mcp_tools_list",
|
|
27739
|
+
[PublishEventRequestEventTypeEnum.mcpInitialize]: "mcp_initialize",
|
|
27740
|
+
[PublishEventRequestEventTypeEnum.mcpResourcesRead]: "mcp_resource_read",
|
|
27741
|
+
[PublishEventRequestEventTypeEnum.mcpResourcesList]: "mcp_resources_list",
|
|
27742
|
+
[PublishEventRequestEventTypeEnum.mcpPromptsGet]: "mcp_prompt_get",
|
|
27743
|
+
[PublishEventRequestEventTypeEnum.mcpPromptsList]: "mcp_prompts_list"
|
|
27744
|
+
};
|
|
27745
|
+
return mapping[eventType] || `mcp_${eventType.replace(/^mcp:/, "").replace(/\//g, "_")}`;
|
|
27746
|
+
}
|
|
27747
|
+
};
|
|
27748
|
+
var TelemetryManager = class {
|
|
27749
|
+
constructor(exporterConfigs) {
|
|
27750
|
+
this.exporters = /* @__PURE__ */ new Map();
|
|
27751
|
+
if (!exporterConfigs) return;
|
|
27752
|
+
for (const [name, config2] of Object.entries(exporterConfigs)) {
|
|
27753
|
+
try {
|
|
27754
|
+
const exporter = this.createExporter(name, config2);
|
|
27755
|
+
if (exporter) {
|
|
27756
|
+
this.exporters.set(name, exporter);
|
|
27757
|
+
writeToLog(`Initialized telemetry exporter: ${name}`);
|
|
27758
|
+
}
|
|
27759
|
+
} catch (error2) {
|
|
27760
|
+
writeToLog(`Failed to initialize exporter ${name}: ${error2}`);
|
|
27761
|
+
}
|
|
27762
|
+
}
|
|
27763
|
+
}
|
|
27764
|
+
createExporter(name, config2) {
|
|
27765
|
+
switch (config2.type) {
|
|
27766
|
+
case "otlp":
|
|
27767
|
+
return new OTLPExporter(config2);
|
|
27768
|
+
case "datadog":
|
|
27769
|
+
return new DatadogExporter(config2);
|
|
27770
|
+
case "sentry":
|
|
27771
|
+
return new SentryExporter(config2);
|
|
27772
|
+
case "posthog":
|
|
27773
|
+
return new PostHogExporter(config2);
|
|
27774
|
+
default:
|
|
27775
|
+
writeToLog(`Unknown exporter type: ${config2.type}`);
|
|
27776
|
+
return null;
|
|
27777
|
+
}
|
|
27778
|
+
}
|
|
27779
|
+
async export(event) {
|
|
27780
|
+
if (this.exporters.size === 0) return;
|
|
27781
|
+
for (const [name, exporter] of this.exporters) {
|
|
27782
|
+
exporter.export(event).catch((error2) => {
|
|
27783
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
27784
|
+
writeToLog(`Telemetry export failed for ${name}: ${errorMessage}`);
|
|
27785
|
+
});
|
|
27786
|
+
}
|
|
27787
|
+
}
|
|
27788
|
+
getExporterCount() {
|
|
27789
|
+
return this.exporters.size;
|
|
27790
|
+
}
|
|
27791
|
+
};
|
|
27792
|
+
function track(server, projectId, options = {}) {
|
|
27793
|
+
try {
|
|
27794
|
+
const validatedServer = isCompatibleServerType(server);
|
|
27795
|
+
const apiBaseUrl = options.apiBaseUrl || process.env.MCPCAT_API_URL;
|
|
27796
|
+
if (apiBaseUrl) {
|
|
27797
|
+
eventQueue.configure(apiBaseUrl);
|
|
27798
|
+
}
|
|
27799
|
+
const lowLevelServer = isHighLevelServer(validatedServer) ? validatedServer.server : validatedServer;
|
|
27800
|
+
const existingData = getServerTrackingData(lowLevelServer);
|
|
27801
|
+
if (existingData) {
|
|
27802
|
+
writeToLog(
|
|
27803
|
+
"[SESSION DEBUG] track() - Server already being tracked, skipping initialization"
|
|
27804
|
+
);
|
|
27805
|
+
return validatedServer;
|
|
27806
|
+
}
|
|
27807
|
+
if (options.exporters) {
|
|
27808
|
+
const telemetryManager = new TelemetryManager(options.exporters);
|
|
27809
|
+
setTelemetryManager(telemetryManager);
|
|
27810
|
+
writeToLog(
|
|
27811
|
+
`Initialized telemetry with ${Object.keys(options.exporters).length} exporters`
|
|
27812
|
+
);
|
|
27813
|
+
}
|
|
27814
|
+
if (!projectId && !options.exporters) {
|
|
27815
|
+
writeToLog(
|
|
27816
|
+
"Warning: No projectId provided and no exporters configured. Events will not be sent anywhere."
|
|
27817
|
+
);
|
|
27818
|
+
}
|
|
27819
|
+
const sessionInfo = getSessionInfo(lowLevelServer, void 0);
|
|
27820
|
+
const mcpcatData = {
|
|
27821
|
+
projectId: projectId || "",
|
|
27822
|
+
// Use empty string for null projectId
|
|
27823
|
+
sessionId: newSessionId(),
|
|
27824
|
+
lastActivity: /* @__PURE__ */ new Date(),
|
|
27825
|
+
identifiedSessions: /* @__PURE__ */ new Map(),
|
|
27826
|
+
sessionInfo,
|
|
27827
|
+
options: {
|
|
27828
|
+
enableReportMissing: options.enableReportMissing ?? true,
|
|
27829
|
+
enableTracing: options.enableTracing ?? true,
|
|
27830
|
+
enableToolCallContext: options.enableToolCallContext ?? true,
|
|
27831
|
+
customContextDescription: options.customContextDescription,
|
|
27832
|
+
identify: options.identify,
|
|
27833
|
+
redactSensitiveInformation: options.redactSensitiveInformation,
|
|
27834
|
+
eventTags: options.eventTags,
|
|
27835
|
+
eventProperties: options.eventProperties
|
|
27836
|
+
},
|
|
27837
|
+
sessionSource: "mcpcat"
|
|
27838
|
+
// Initially MCPCat-generated, will change to "mcp" if MCP sessionId is provided in requests
|
|
27839
|
+
};
|
|
27840
|
+
setServerTrackingData(lowLevelServer, mcpcatData);
|
|
27841
|
+
if (isHighLevelServer(validatedServer)) {
|
|
27842
|
+
const highLevelServer = validatedServer;
|
|
27843
|
+
setupTracking(highLevelServer);
|
|
27844
|
+
} else {
|
|
27845
|
+
if (mcpcatData.options.enableReportMissing) {
|
|
27846
|
+
try {
|
|
27847
|
+
setupMCPCatTools(lowLevelServer);
|
|
27848
|
+
} catch (error2) {
|
|
27849
|
+
writeToLog(`Warning: Failed to setup report missing tool - ${error2}`);
|
|
27850
|
+
}
|
|
27851
|
+
}
|
|
27852
|
+
if (mcpcatData.options.enableTracing) {
|
|
27853
|
+
try {
|
|
27854
|
+
setupToolCallTracing(lowLevelServer);
|
|
27855
|
+
} catch (error2) {
|
|
27856
|
+
writeToLog(`Warning: Failed to setup tool call tracing - ${error2}`);
|
|
27857
|
+
}
|
|
27858
|
+
}
|
|
27859
|
+
}
|
|
27860
|
+
return validatedServer;
|
|
27861
|
+
} catch (error2) {
|
|
27862
|
+
writeToLog(`Warning: Failed to track server - ${error2}`);
|
|
27863
|
+
return server;
|
|
27864
|
+
}
|
|
27865
|
+
}
|
|
27866
|
+
|
|
27867
|
+
// ../../src/mcp/mcpcat.ts
|
|
27868
|
+
var EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
|
|
27869
|
+
var SSN_RE = /\b\d{3}[-\s]\d{2}[-\s]\d{4}\b/g;
|
|
27870
|
+
var CC_CANDIDATE_RE = /\b(?:\d[ -]?){13,19}\b/g;
|
|
27871
|
+
var PHONE_INTL_RE = /\+\d[\d\s().-]{5,16}\d/g;
|
|
27872
|
+
var PHONE_NANP_RE = /\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b/g;
|
|
27873
|
+
function isLuhnValid(digits) {
|
|
27874
|
+
if (digits.length < 13 || digits.length > 19) return false;
|
|
27875
|
+
let sum = 0;
|
|
27876
|
+
let double = false;
|
|
27877
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
27878
|
+
let n = digits.charCodeAt(i) - 48;
|
|
27879
|
+
if (n < 0 || n > 9) return false;
|
|
27880
|
+
if (double) {
|
|
27881
|
+
n *= 2;
|
|
27882
|
+
if (n > 9) n -= 9;
|
|
27883
|
+
}
|
|
27884
|
+
sum += n;
|
|
27885
|
+
double = !double;
|
|
27886
|
+
}
|
|
27887
|
+
return sum % 10 === 0;
|
|
27888
|
+
}
|
|
27889
|
+
function redactPII(text) {
|
|
27890
|
+
return text.replace(EMAIL_RE, "[redacted-email]").replace(SSN_RE, "[redacted-ssn]").replace(
|
|
27891
|
+
CC_CANDIDATE_RE,
|
|
27892
|
+
(m) => isLuhnValid(m.replace(/\D/g, "")) ? "[redacted-cc]" : m
|
|
27893
|
+
).replace(PHONE_INTL_RE, "[redacted-phone]").replace(PHONE_NANP_RE, "[redacted-phone]");
|
|
27894
|
+
}
|
|
27895
|
+
function trackWithMcpcat(server) {
|
|
27896
|
+
const projectId = process.env.MCPCAT_PROJECT_ID?.trim();
|
|
27897
|
+
if (!projectId) return;
|
|
27898
|
+
track(server, projectId, {
|
|
27899
|
+
enableToolCallContext: false,
|
|
27900
|
+
enableReportMissing: false,
|
|
27901
|
+
// RedactFunction is typed async; redactPII is sync, so wrap it.
|
|
27902
|
+
redactSensitiveInformation: (text) => Promise.resolve(redactPII(text))
|
|
27903
|
+
});
|
|
27904
|
+
}
|
|
27905
|
+
|
|
24085
27906
|
// ../../src/mcp/server.ts
|
|
24086
27907
|
var READ_ONLY_TOOL_ANNOTATIONS = {
|
|
24087
27908
|
readOnlyHint: true,
|
|
@@ -24497,6 +28318,10 @@ function createMcpServer() {
|
|
|
24497
28318
|
server.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
24498
28319
|
prompts: []
|
|
24499
28320
|
}));
|
|
28321
|
+
server.server.registerCapabilities({
|
|
28322
|
+
extensions: { "io.modelcontextprotocol/ui": {} }
|
|
28323
|
+
});
|
|
28324
|
+
trackWithMcpcat(server);
|
|
24500
28325
|
return server;
|
|
24501
28326
|
}
|
|
24502
28327
|
|