@savvly/mcp-server 1.0.20 → 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 CHANGED
@@ -2231,8 +2231,8 @@ var require_resolve = __commonJS({
2231
2231
  }
2232
2232
  return count;
2233
2233
  }
2234
- function getFullPath(resolver, id = "", normalize) {
2235
- if (normalize !== false)
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 normalize(uri, options) {
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 = (maxLength, params) => inst.check(_maxLength(maxLength, params));
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(maxLength, message) {
14458
+ max(maxLength2, message) {
14459
14459
  return this._addCheck({
14460
14460
  kind: "max",
14461
- value: maxLength,
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(maxLength, message) {
15325
+ max(maxLength2, message) {
15326
15326
  return new _ZodArray({
15327
15327
  ...this._def,
15328
- maxLength: { value: maxLength, message: errorUtil.toString(message) }
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.20";
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";
@@ -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,
@@ -24500,6 +28321,7 @@ function createMcpServer() {
24500
28321
  server.server.registerCapabilities({
24501
28322
  extensions: { "io.modelcontextprotocol/ui": {} }
24502
28323
  });
28324
+ trackWithMcpcat(server);
24503
28325
  return server;
24504
28326
  }
24505
28327