@brizz/sdk 0.1.21 → 0.1.22
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/index.cjs +919 -191
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +892 -161
- package/dist/index.js.map +1 -1
- package/dist/preload.cjs +626 -18
- package/dist/preload.cjs.map +1 -1
- package/dist/preload.js +626 -18
- package/dist/preload.js.map +1 -1
- package/package.json +5 -1
package/dist/preload.js
CHANGED
|
@@ -241,6 +241,618 @@ import { PineconeInstrumentation } from "@traceloop/instrumentation-pinecone";
|
|
|
241
241
|
import { QdrantInstrumentation } from "@traceloop/instrumentation-qdrant";
|
|
242
242
|
import { TogetherInstrumentation } from "@traceloop/instrumentation-together";
|
|
243
243
|
import { VertexAIInstrumentation } from "@traceloop/instrumentation-vertexai";
|
|
244
|
+
|
|
245
|
+
// src/internal/instrumentation/mcp/instrumentation.ts
|
|
246
|
+
import { MCPInstrumentation as BaseMCPInstrumentation } from "@arizeai/openinference-instrumentation-mcp";
|
|
247
|
+
import { trace as trace2 } from "@opentelemetry/api";
|
|
248
|
+
import { InstrumentationNodeModuleDefinition } from "@opentelemetry/instrumentation";
|
|
249
|
+
|
|
250
|
+
// src/internal/instrumentation/mcp/patches/protocol.ts
|
|
251
|
+
import { context as context2, propagation, SpanKind, trace } from "@opentelemetry/api";
|
|
252
|
+
|
|
253
|
+
// src/internal/instrumentation/mcp/session.ts
|
|
254
|
+
import { context } from "@opentelemetry/api";
|
|
255
|
+
|
|
256
|
+
// src/internal/semantic-conventions.ts
|
|
257
|
+
import { createContextKey } from "@opentelemetry/api";
|
|
258
|
+
var BRIZZ = "brizz";
|
|
259
|
+
var PROPERTIES = "properties";
|
|
260
|
+
var SESSION_ID = "session.id";
|
|
261
|
+
var PROPERTIES_CONTEXT_KEY = createContextKey(PROPERTIES);
|
|
262
|
+
var SESSION_OBJECT_CONTEXT_KEY = createContextKey("brizz.session.object");
|
|
263
|
+
|
|
264
|
+
// src/internal/instrumentation/mcp/session.ts
|
|
265
|
+
function stampAndPropagateSession(span, sessionId, baseContext = context.active()) {
|
|
266
|
+
if (!sessionId) {
|
|
267
|
+
return { context: baseContext, sessionId: null };
|
|
268
|
+
}
|
|
269
|
+
if (span.isRecording()) {
|
|
270
|
+
try {
|
|
271
|
+
span.setAttribute(`${BRIZZ}.${SESSION_ID}`, sessionId);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
logger.warn(
|
|
274
|
+
`Brizz MCP: failed to stamp session id on span: ${String(error)}`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
const prev = baseContext.getValue(PROPERTIES_CONTEXT_KEY);
|
|
280
|
+
const merged = prev ? { ...prev, [SESSION_ID]: sessionId } : { [SESSION_ID]: sessionId };
|
|
281
|
+
return {
|
|
282
|
+
context: baseContext.setValue(PROPERTIES_CONTEXT_KEY, merged),
|
|
283
|
+
sessionId
|
|
284
|
+
};
|
|
285
|
+
} catch (error) {
|
|
286
|
+
logger.warn(`Brizz MCP: failed to attach session context: ${String(error)}`);
|
|
287
|
+
return { context: baseContext, sessionId };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/internal/instrumentation/mcp/patches/attributes.ts
|
|
292
|
+
import { SpanStatusCode } from "@opentelemetry/api";
|
|
293
|
+
|
|
294
|
+
// src/internal/instrumentation/mcp/semantic-conventions.ts
|
|
295
|
+
var MCP_TOOL_NAME = "mcp.tool.name";
|
|
296
|
+
var MCP_TOOL_ARGUMENTS = "mcp.tool.arguments";
|
|
297
|
+
var MCP_TOOL_RESULT = "mcp.tool.result";
|
|
298
|
+
var MCP_COMPONENT_TYPE = "mcp.component.type";
|
|
299
|
+
var MCP_COMPONENT_TOOL = "tool";
|
|
300
|
+
var MCP_METHOD_NAME = "mcp.method.name";
|
|
301
|
+
var MCP_REQUEST_ID = "mcp.request.id";
|
|
302
|
+
var MCP_SESSION_ID = "mcp.session.id";
|
|
303
|
+
var MCP_PROTOCOL_VERSION = "mcp.protocol.version";
|
|
304
|
+
var MCP_RESOURCE_URI = "mcp.resource.uri";
|
|
305
|
+
var RPC_SYSTEM = "rpc.system";
|
|
306
|
+
var RPC_SYSTEM_MCP = "mcp";
|
|
307
|
+
var RPC_RESPONSE_STATUS_CODE = "rpc.response.status_code";
|
|
308
|
+
var GEN_AI_TOOL_NAME = "gen_ai.tool.name";
|
|
309
|
+
var GEN_AI_PROMPT_NAME = "gen_ai.prompt.name";
|
|
310
|
+
var GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
|
|
311
|
+
var GEN_AI_OPERATION_EXECUTE_TOOL = "execute_tool";
|
|
312
|
+
var NETWORK_TRANSPORT = "network.transport";
|
|
313
|
+
var ERROR_TYPE = "error.type";
|
|
314
|
+
var ERROR_TYPE_TOOL = "tool_error";
|
|
315
|
+
var JSONRPC_REQUEST_ID = "jsonrpc.request.id";
|
|
316
|
+
var SPAN_NAME_TOOLS_CALL = "tools/call";
|
|
317
|
+
var MAX_ATTRIBUTE_LENGTH = 32 * 1024;
|
|
318
|
+
var TRUNCATION_SUFFIX = "\u2026(truncated)";
|
|
319
|
+
var METHOD_TOOLS_CALL = "tools/call";
|
|
320
|
+
var METHOD_RESOURCES_READ = "resources/read";
|
|
321
|
+
var METHOD_PROMPTS_GET = "prompts/get";
|
|
322
|
+
var METHOD_INITIALIZE = "initialize";
|
|
323
|
+
|
|
324
|
+
// src/internal/instrumentation/mcp/patches/attributes.ts
|
|
325
|
+
function deriveSpanName(method, params) {
|
|
326
|
+
try {
|
|
327
|
+
if (method === METHOD_TOOLS_CALL) {
|
|
328
|
+
const name = typeof params?.["name"] === "string" ? params["name"] : "";
|
|
329
|
+
return name ? `${SPAN_NAME_TOOLS_CALL} ${name}` : SPAN_NAME_TOOLS_CALL;
|
|
330
|
+
}
|
|
331
|
+
if (method === METHOD_RESOURCES_READ) {
|
|
332
|
+
const uri = typeof params?.["uri"] === "string" ? params["uri"] : "";
|
|
333
|
+
return uri ? `${METHOD_RESOURCES_READ} ${uri}` : METHOD_RESOURCES_READ;
|
|
334
|
+
}
|
|
335
|
+
if (method === METHOD_PROMPTS_GET) {
|
|
336
|
+
const name = typeof params?.["name"] === "string" ? params["name"] : "";
|
|
337
|
+
return name ? `${METHOD_PROMPTS_GET} ${name}` : METHOD_PROMPTS_GET;
|
|
338
|
+
}
|
|
339
|
+
return method;
|
|
340
|
+
} catch {
|
|
341
|
+
return method || "mcp";
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function applyBaseAttributes(span, request) {
|
|
345
|
+
span.setAttribute(RPC_SYSTEM, RPC_SYSTEM_MCP);
|
|
346
|
+
if (request.method) {
|
|
347
|
+
span.setAttribute(MCP_METHOD_NAME, request.method);
|
|
348
|
+
}
|
|
349
|
+
if (request.id !== void 0 && request.id !== null) {
|
|
350
|
+
const id = String(request.id);
|
|
351
|
+
span.setAttribute(MCP_REQUEST_ID, id);
|
|
352
|
+
span.setAttribute(JSONRPC_REQUEST_ID, id);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function applyClientRequestAttributes(span, request, transportName) {
|
|
356
|
+
applyBaseAttributes(span, request);
|
|
357
|
+
applyMethodSpecificRequestAttributes(span, request);
|
|
358
|
+
if (transportName) {
|
|
359
|
+
const transport = normalizeTransport(transportName);
|
|
360
|
+
if (transport) {
|
|
361
|
+
span.setAttribute(NETWORK_TRANSPORT, transport);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function applyServerRequestAttributes(span, request, protocol) {
|
|
366
|
+
applyBaseAttributes(span, request);
|
|
367
|
+
applyMethodSpecificRequestAttributes(span, request);
|
|
368
|
+
if (request.method === METHOD_TOOLS_CALL) {
|
|
369
|
+
const args = request.params?.["arguments"];
|
|
370
|
+
if (args !== void 0) {
|
|
371
|
+
span.setAttribute(MCP_TOOL_ARGUMENTS, serializeForAttribute(args));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
const sessionId = protocol.sessionId ?? protocol._transport?.sessionId;
|
|
375
|
+
if (sessionId) {
|
|
376
|
+
span.setAttribute(MCP_SESSION_ID, String(sessionId));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function applyMethodSpecificRequestAttributes(span, request) {
|
|
380
|
+
const params = request.params ?? {};
|
|
381
|
+
switch (request.method) {
|
|
382
|
+
case METHOD_TOOLS_CALL: {
|
|
383
|
+
const name = typeof params["name"] === "string" ? params["name"] : "";
|
|
384
|
+
if (name) {
|
|
385
|
+
span.setAttribute(MCP_TOOL_NAME, name);
|
|
386
|
+
span.setAttribute(GEN_AI_TOOL_NAME, name);
|
|
387
|
+
}
|
|
388
|
+
span.setAttribute(MCP_COMPONENT_TYPE, MCP_COMPONENT_TOOL);
|
|
389
|
+
span.setAttribute(GEN_AI_OPERATION_NAME, GEN_AI_OPERATION_EXECUTE_TOOL);
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
case METHOD_RESOURCES_READ: {
|
|
393
|
+
const uri = typeof params["uri"] === "string" ? params["uri"] : "";
|
|
394
|
+
if (uri) {
|
|
395
|
+
span.setAttribute(MCP_RESOURCE_URI, uri);
|
|
396
|
+
}
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
case METHOD_PROMPTS_GET: {
|
|
400
|
+
const name = typeof params["name"] === "string" ? params["name"] : "";
|
|
401
|
+
if (name) {
|
|
402
|
+
span.setAttribute(GEN_AI_PROMPT_NAME, name);
|
|
403
|
+
}
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
default:
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function applyResultAttributes(span, method, result) {
|
|
411
|
+
if (method === METHOD_INITIALIZE && result && typeof result === "object") {
|
|
412
|
+
const protocolVersion = result["protocolVersion"];
|
|
413
|
+
if (typeof protocolVersion === "string") {
|
|
414
|
+
span.setAttribute(MCP_PROTOCOL_VERSION, protocolVersion);
|
|
415
|
+
}
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (method !== METHOD_TOOLS_CALL) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const obj = result && typeof result === "object" ? result : null;
|
|
422
|
+
const content = obj?.["content"] ?? result;
|
|
423
|
+
span.setAttribute(MCP_TOOL_RESULT, serializeForAttribute(content));
|
|
424
|
+
if (obj && obj["isError"] === true) {
|
|
425
|
+
span.setAttribute(ERROR_TYPE, ERROR_TYPE_TOOL);
|
|
426
|
+
const message = extractToolErrorMessage(obj);
|
|
427
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function applyErrorAttributes(span, err) {
|
|
431
|
+
const error = err;
|
|
432
|
+
const code = error?.code;
|
|
433
|
+
if (typeof code === "number") {
|
|
434
|
+
span.setAttribute(RPC_RESPONSE_STATUS_CODE, code);
|
|
435
|
+
span.setAttribute(ERROR_TYPE, String(code));
|
|
436
|
+
} else if (error?.name === "AbortError") {
|
|
437
|
+
span.setAttribute(ERROR_TYPE, "cancelled");
|
|
438
|
+
} else if (error?.name === "TimeoutError") {
|
|
439
|
+
span.setAttribute(ERROR_TYPE, "timeout");
|
|
440
|
+
} else {
|
|
441
|
+
span.setAttribute(
|
|
442
|
+
ERROR_TYPE,
|
|
443
|
+
error?.constructor?.name || error?.name || "Error"
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
try {
|
|
447
|
+
span.recordException(error);
|
|
448
|
+
} catch {
|
|
449
|
+
}
|
|
450
|
+
span.setStatus({
|
|
451
|
+
code: SpanStatusCode.ERROR,
|
|
452
|
+
message: typeof error?.message === "string" ? error.message : void 0
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
function serializeForAttribute(value) {
|
|
456
|
+
const raw = rawSerialize(value);
|
|
457
|
+
if (raw.length <= MAX_ATTRIBUTE_LENGTH) {
|
|
458
|
+
return raw;
|
|
459
|
+
}
|
|
460
|
+
return raw.slice(0, MAX_ATTRIBUTE_LENGTH - TRUNCATION_SUFFIX.length) + TRUNCATION_SUFFIX;
|
|
461
|
+
}
|
|
462
|
+
function rawSerialize(value) {
|
|
463
|
+
if (value === null || value === void 0) {
|
|
464
|
+
return "";
|
|
465
|
+
}
|
|
466
|
+
if (typeof value === "string") {
|
|
467
|
+
return value;
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
return JSON.stringify(value);
|
|
471
|
+
} catch {
|
|
472
|
+
try {
|
|
473
|
+
if (value === null || value === void 0) {
|
|
474
|
+
return "";
|
|
475
|
+
}
|
|
476
|
+
const tag = Object.prototype.toString.call(value);
|
|
477
|
+
return typeof value.toString === "function" ? (
|
|
478
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
479
|
+
String(value)
|
|
480
|
+
) : tag;
|
|
481
|
+
} catch {
|
|
482
|
+
return "";
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function extractToolErrorMessage(result) {
|
|
487
|
+
const content = result["content"];
|
|
488
|
+
if (Array.isArray(content)) {
|
|
489
|
+
for (const item of content) {
|
|
490
|
+
if (item && typeof item === "object") {
|
|
491
|
+
const text = item["text"];
|
|
492
|
+
if (typeof text === "string") {
|
|
493
|
+
return text;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return void 0;
|
|
499
|
+
}
|
|
500
|
+
function normalizeTransport(ctorName) {
|
|
501
|
+
const name = ctorName.toLowerCase();
|
|
502
|
+
if (name.includes("stdio")) {
|
|
503
|
+
return "stdio";
|
|
504
|
+
}
|
|
505
|
+
if (name.includes("sse")) {
|
|
506
|
+
return "sse";
|
|
507
|
+
}
|
|
508
|
+
if (name.includes("streamablehttp") || name.includes("http")) {
|
|
509
|
+
return "http";
|
|
510
|
+
}
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/internal/instrumentation/mcp/patches/protocol.ts
|
|
515
|
+
var PATCHED_FLAG = /* @__PURE__ */ Symbol("brizz.mcp.protocol-patched");
|
|
516
|
+
function patchProtocolPrototype(prototype, tracer) {
|
|
517
|
+
if (!prototype || typeof prototype !== "object") {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
const proto = prototype;
|
|
521
|
+
if (proto[PATCHED_FLAG]) {
|
|
522
|
+
logger.debug("Brizz MCP: Protocol.prototype already patched, skipping");
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
const originalRequest = proto["request"];
|
|
526
|
+
const originalOnRequest = proto["_onrequest"];
|
|
527
|
+
if (typeof originalRequest === "function") {
|
|
528
|
+
proto["request"] = wrapRequest(originalRequest, tracer);
|
|
529
|
+
} else {
|
|
530
|
+
logger.debug(
|
|
531
|
+
"Brizz MCP: Protocol.prototype.request missing \u2014 skipping CLIENT patch"
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
if (typeof originalOnRequest === "function") {
|
|
535
|
+
proto["_onrequest"] = wrapOnRequest(
|
|
536
|
+
originalOnRequest,
|
|
537
|
+
tracer
|
|
538
|
+
);
|
|
539
|
+
} else {
|
|
540
|
+
logger.debug(
|
|
541
|
+
"Brizz MCP: Protocol.prototype._onrequest missing \u2014 skipping SERVER patch"
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
proto[PATCHED_FLAG] = true;
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
function wrapRequest(original, tracer) {
|
|
548
|
+
return function wrappedRequest(...args) {
|
|
549
|
+
const request = args[0];
|
|
550
|
+
if (!request || typeof request !== "object" || !request.method) {
|
|
551
|
+
return original.apply(this, args);
|
|
552
|
+
}
|
|
553
|
+
const span = safeStartClientSpan(tracer, request, this);
|
|
554
|
+
if (!span) {
|
|
555
|
+
return original.apply(this, args);
|
|
556
|
+
}
|
|
557
|
+
return executeAroundSpan(span, request.method, () => {
|
|
558
|
+
const ctx = trace.setSpan(context2.active(), span);
|
|
559
|
+
return context2.with(ctx, () => original.apply(this, args));
|
|
560
|
+
});
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
function wrapOnRequest(original, tracer) {
|
|
564
|
+
return function wrappedOnRequest(...args) {
|
|
565
|
+
const request = args[0];
|
|
566
|
+
if (!request || typeof request !== "object" || !request.method) {
|
|
567
|
+
return original.apply(this, args);
|
|
568
|
+
}
|
|
569
|
+
const handlers = this._requestHandlers;
|
|
570
|
+
if (!handlers || typeof handlers.get !== "function") {
|
|
571
|
+
return original.apply(this, args);
|
|
572
|
+
}
|
|
573
|
+
const method = request.method;
|
|
574
|
+
const handler = handlers.get(method) ?? this.fallbackRequestHandler;
|
|
575
|
+
if (!handler) {
|
|
576
|
+
return original.apply(this, args);
|
|
577
|
+
}
|
|
578
|
+
const started = safeStartServerSpan(tracer, request, this);
|
|
579
|
+
if (!started) {
|
|
580
|
+
return original.apply(this, args);
|
|
581
|
+
}
|
|
582
|
+
const { span, spanCtx } = started;
|
|
583
|
+
const wrappedHandler = (req, extra) => context2.with(spanCtx, () => executeHandler(span, method, handler, req, extra));
|
|
584
|
+
const hadEntry = handlers.has(method);
|
|
585
|
+
const prev = handlers.get(method);
|
|
586
|
+
handlers.set(method, wrappedHandler);
|
|
587
|
+
const usedFallback = !hadEntry && this.fallbackRequestHandler === handler;
|
|
588
|
+
const fallbackPrev = usedFallback ? this.fallbackRequestHandler : void 0;
|
|
589
|
+
if (usedFallback) {
|
|
590
|
+
this.fallbackRequestHandler = wrappedHandler;
|
|
591
|
+
}
|
|
592
|
+
try {
|
|
593
|
+
return original.apply(this, args);
|
|
594
|
+
} finally {
|
|
595
|
+
if (hadEntry) {
|
|
596
|
+
handlers.set(method, prev);
|
|
597
|
+
} else {
|
|
598
|
+
handlers.delete(method);
|
|
599
|
+
}
|
|
600
|
+
if (usedFallback) {
|
|
601
|
+
this.fallbackRequestHandler = fallbackPrev;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function executeAroundSpan(span, method, run) {
|
|
607
|
+
let result;
|
|
608
|
+
try {
|
|
609
|
+
result = run();
|
|
610
|
+
} catch (error) {
|
|
611
|
+
safeApplyErrorAttributes(span, error);
|
|
612
|
+
safeEnd(span);
|
|
613
|
+
throw error;
|
|
614
|
+
}
|
|
615
|
+
if (!isThenable(result)) {
|
|
616
|
+
safeApplyResultAttributes(span, method, result);
|
|
617
|
+
safeEnd(span);
|
|
618
|
+
return result;
|
|
619
|
+
}
|
|
620
|
+
return result.then(
|
|
621
|
+
(value) => {
|
|
622
|
+
safeApplyResultAttributes(span, method, value);
|
|
623
|
+
safeEnd(span);
|
|
624
|
+
return value;
|
|
625
|
+
},
|
|
626
|
+
(error) => {
|
|
627
|
+
safeApplyErrorAttributes(span, error);
|
|
628
|
+
safeEnd(span);
|
|
629
|
+
throw error;
|
|
630
|
+
}
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
function executeHandler(span, method, handler, req, extra) {
|
|
634
|
+
return executeAroundSpan(span, method, () => handler(req, extra));
|
|
635
|
+
}
|
|
636
|
+
function safeStartClientSpan(tracer, request, protocol) {
|
|
637
|
+
try {
|
|
638
|
+
const spanName = deriveSpanName(request.method, request.params);
|
|
639
|
+
const span = tracer.startSpan(spanName, { kind: SpanKind.CLIENT });
|
|
640
|
+
applyClientRequestAttributes(
|
|
641
|
+
span,
|
|
642
|
+
request,
|
|
643
|
+
protocol._transport?.constructor?.name
|
|
644
|
+
);
|
|
645
|
+
return span;
|
|
646
|
+
} catch (error) {
|
|
647
|
+
logger.debug(`Brizz MCP: failed to open CLIENT span: ${String(error)}`);
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function safeStartServerSpan(tracer, request, protocol) {
|
|
652
|
+
try {
|
|
653
|
+
const parentCtx = extractParentContext(request);
|
|
654
|
+
const spanName = deriveSpanName(request.method, request.params);
|
|
655
|
+
const span = tracer.startSpan(
|
|
656
|
+
spanName,
|
|
657
|
+
{ kind: SpanKind.SERVER },
|
|
658
|
+
parentCtx
|
|
659
|
+
);
|
|
660
|
+
applyServerRequestAttributes(span, request, protocol);
|
|
661
|
+
const sessionId = protocol.sessionId ?? protocol._transport?.sessionId;
|
|
662
|
+
const { context: sessCtx } = stampAndPropagateSession(span, sessionId, parentCtx);
|
|
663
|
+
return { span, spanCtx: trace.setSpan(sessCtx, span) };
|
|
664
|
+
} catch (error) {
|
|
665
|
+
logger.debug(`Brizz MCP: failed to open SERVER span: ${String(error)}`);
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
function extractParentContext(request) {
|
|
670
|
+
try {
|
|
671
|
+
const meta = request.params?._meta;
|
|
672
|
+
if (meta && typeof meta === "object") {
|
|
673
|
+
return propagation.extract(context2.active(), meta);
|
|
674
|
+
}
|
|
675
|
+
} catch (error) {
|
|
676
|
+
logger.debug(
|
|
677
|
+
`Brizz MCP: failed to extract parent context from _meta: ${String(error)}`
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
return context2.active();
|
|
681
|
+
}
|
|
682
|
+
function isThenable(value) {
|
|
683
|
+
return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
684
|
+
}
|
|
685
|
+
function safeApplyResultAttributes(span, method, value) {
|
|
686
|
+
try {
|
|
687
|
+
applyResultAttributes(span, method, value);
|
|
688
|
+
} catch (error) {
|
|
689
|
+
logger.debug(
|
|
690
|
+
`Brizz MCP: failed to apply result attributes: ${String(error)}`
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
function safeApplyErrorAttributes(span, err) {
|
|
695
|
+
try {
|
|
696
|
+
applyErrorAttributes(span, err);
|
|
697
|
+
} catch (error) {
|
|
698
|
+
logger.debug(
|
|
699
|
+
`Brizz MCP: failed to apply error attributes: ${String(error)}`
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function safeEnd(span) {
|
|
704
|
+
try {
|
|
705
|
+
span.end();
|
|
706
|
+
} catch (error) {
|
|
707
|
+
logger.debug(`Brizz MCP: failed to end span: ${String(error)}`);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/internal/version.ts
|
|
712
|
+
function getSDKVersion() {
|
|
713
|
+
return "0.1.22";
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// src/internal/instrumentation/mcp/version.ts
|
|
717
|
+
var INSTRUMENTATION_NAME = "@brizz/sdk/mcp";
|
|
718
|
+
var INSTRUMENTATION_VERSION = getSDKVersion();
|
|
719
|
+
|
|
720
|
+
// src/internal/instrumentation/mcp/instrumentation.ts
|
|
721
|
+
var PROTOCOL_MODULE_NAME = "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
722
|
+
var PROTOCOL_SUPPORTED_VERSIONS = [">=1.0.0 <2"];
|
|
723
|
+
var MCPInstrumentation = class extends BaseMCPInstrumentation {
|
|
724
|
+
/**
|
|
725
|
+
* Dedicated Brizz-named tracer for our SERVER + CLIENT spans.
|
|
726
|
+
*
|
|
727
|
+
* Why a separate tracer from the parent class's one: Arize's inherited
|
|
728
|
+
* transport patches don't emit spans (they only inject propagation
|
|
729
|
+
* headers), so using our own tracer here keeps Brizz spans attributed to
|
|
730
|
+
* `@brizz/sdk/mcp` in the dashboard. The parent's `tracer` is a
|
|
731
|
+
* `protected get` (no setter), so fighting it with assignment is the
|
|
732
|
+
* wrong tool.
|
|
733
|
+
*/
|
|
734
|
+
brizzTracer;
|
|
735
|
+
constructor(_config) {
|
|
736
|
+
super({ instrumentationConfig: _config?.instrumentationConfig });
|
|
737
|
+
this.brizzTracer = trace2.getTracer(INSTRUMENTATION_NAME, INSTRUMENTATION_VERSION);
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Extend `super.init()` with our protocol-layer module definition.
|
|
741
|
+
*
|
|
742
|
+
* Arize's `init()` returns definitions for the six transport modules
|
|
743
|
+
* (SSE client/server, stdio client/server, streamable-HTTP client/server)
|
|
744
|
+
* whose `send`/`start` methods get patched for W3C trace-context
|
|
745
|
+
* injection. We append one more: `@modelcontextprotocol/sdk/shared/protocol.js`
|
|
746
|
+
* where our patches open SERVER/CLIENT spans around the handler + outgoing
|
|
747
|
+
* request. If `super.init()` throws (unlikely but possible across Arize
|
|
748
|
+
* versions), we gracefully degrade to protocol-only instrumentation.
|
|
749
|
+
*
|
|
750
|
+
* The cast at the end satisfies the parent's strongly-typed generic
|
|
751
|
+
* without leaking the cast into call sites.
|
|
752
|
+
*/
|
|
753
|
+
init() {
|
|
754
|
+
let base;
|
|
755
|
+
try {
|
|
756
|
+
base = super.init() ?? [];
|
|
757
|
+
} catch (error) {
|
|
758
|
+
logger.warn(
|
|
759
|
+
`Brizz MCP: base Arize init() failed \u2014 transport context propagation disabled: ${String(error)}`
|
|
760
|
+
);
|
|
761
|
+
base = [];
|
|
762
|
+
}
|
|
763
|
+
const baseArr = Array.isArray(base) ? base : [base];
|
|
764
|
+
const brizzDef = new InstrumentationNodeModuleDefinition(
|
|
765
|
+
PROTOCOL_MODULE_NAME,
|
|
766
|
+
PROTOCOL_SUPPORTED_VERSIONS,
|
|
767
|
+
(module3) => {
|
|
768
|
+
this.patchProtocolModule(module3);
|
|
769
|
+
return module3;
|
|
770
|
+
},
|
|
771
|
+
(module3) => {
|
|
772
|
+
this.unpatchProtocolModule(module3);
|
|
773
|
+
return module3;
|
|
774
|
+
}
|
|
775
|
+
);
|
|
776
|
+
return [...baseArr, brizzDef];
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Manually instrument MCP modules for Next.js/Webpack where the
|
|
780
|
+
* auto-instrumentation module-load hook doesn't fire.
|
|
781
|
+
*
|
|
782
|
+
* Forwards the six transport module fields to the inherited Arize
|
|
783
|
+
* `manuallyInstrument(...)` (context propagation) and applies our
|
|
784
|
+
* protocol patch if `protocolModule` is provided (SERVER/CLIENT spans).
|
|
785
|
+
* Both legs are try/catch-guarded — a failure in one shouldn't prevent
|
|
786
|
+
* the other from taking effect.
|
|
787
|
+
*/
|
|
788
|
+
manuallyInstrument(modules) {
|
|
789
|
+
const {
|
|
790
|
+
clientSSEModule,
|
|
791
|
+
serverSSEModule,
|
|
792
|
+
clientStdioModule,
|
|
793
|
+
serverStdioModule,
|
|
794
|
+
clientStreamableHTTPModule,
|
|
795
|
+
serverStreamableHTTPModule,
|
|
796
|
+
protocolModule
|
|
797
|
+
} = modules;
|
|
798
|
+
try {
|
|
799
|
+
super.manuallyInstrument({
|
|
800
|
+
clientSSEModule,
|
|
801
|
+
serverSSEModule,
|
|
802
|
+
clientStdioModule,
|
|
803
|
+
serverStdioModule,
|
|
804
|
+
clientStreamableHTTPModule,
|
|
805
|
+
serverStreamableHTTPModule
|
|
806
|
+
});
|
|
807
|
+
} catch (error) {
|
|
808
|
+
logger.warn(`Brizz MCP: Arize manuallyInstrument(...) failed: ${String(error)}`);
|
|
809
|
+
}
|
|
810
|
+
if (protocolModule) {
|
|
811
|
+
try {
|
|
812
|
+
this.patchProtocolModule(protocolModule);
|
|
813
|
+
} catch (error) {
|
|
814
|
+
logger.warn(
|
|
815
|
+
`Brizz MCP: failed to manually patch Protocol module: ${String(error)}`
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Apply the SERVER + CLIENT patch to a loaded `protocol.js` module. Shared
|
|
822
|
+
* by both the automatic module-load callback in `init()` and the manual
|
|
823
|
+
* `manuallyInstrument(...)` path above so there's exactly one place that
|
|
824
|
+
* calls `patchProtocolPrototype`.
|
|
825
|
+
*/
|
|
826
|
+
patchProtocolModule(module3) {
|
|
827
|
+
const proto = module3?.Protocol?.prototype;
|
|
828
|
+
if (!proto) {
|
|
829
|
+
logger.debug(
|
|
830
|
+
"Brizz MCP: module does not expose Protocol.prototype \u2014 skipping protocol patches"
|
|
831
|
+
);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const ok = patchProtocolPrototype(proto, this.brizzTracer);
|
|
835
|
+
if (ok) {
|
|
836
|
+
logger.debug("Brizz MCP: patched Protocol.prototype for SERVER+CLIENT spans");
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Unpatch is intentionally a no-op.
|
|
841
|
+
*
|
|
842
|
+
* `patchProtocolPrototype` wraps methods in place and sets a PATCHED_FLAG
|
|
843
|
+
* Symbol on the prototype to prevent double-patching. Restoring the
|
|
844
|
+
* originals would require us to hold references across module unloads,
|
|
845
|
+
* which isn't a pattern we need — instrumentation rarely gets torn down
|
|
846
|
+
* at runtime, and a process reload is the canonical way to detach.
|
|
847
|
+
*/
|
|
848
|
+
unpatchProtocolModule(_module) {
|
|
849
|
+
logger.debug(
|
|
850
|
+
"Brizz MCP: unpatch is a no-op \u2014 reload the process to cleanly detach"
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
// src/internal/instrumentation/registry.ts
|
|
244
856
|
var InstrumentationRegistry = class _InstrumentationRegistry {
|
|
245
857
|
static instance;
|
|
246
858
|
manualModules = null;
|
|
@@ -345,6 +957,14 @@ var InstrumentationRegistry = class _InstrumentationRegistry {
|
|
|
345
957
|
}
|
|
346
958
|
})();
|
|
347
959
|
}
|
|
960
|
+
if (this.manualModules?.mcp) {
|
|
961
|
+
try {
|
|
962
|
+
new MCPInstrumentation({ exceptionLogger }).manuallyInstrument(this.manualModules.mcp);
|
|
963
|
+
logger.debug("Manual instrumentation enabled for MCP");
|
|
964
|
+
} catch (error) {
|
|
965
|
+
logger.error(`Failed to apply MCP instrumentation: ${String(error)}`);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
348
968
|
}
|
|
349
969
|
};
|
|
350
970
|
|
|
@@ -356,13 +976,8 @@ import {
|
|
|
356
976
|
LoggerProvider
|
|
357
977
|
} from "@opentelemetry/sdk-logs";
|
|
358
978
|
|
|
359
|
-
// src/internal/version.ts
|
|
360
|
-
function getSDKVersion() {
|
|
361
|
-
return "0.1.21";
|
|
362
|
-
}
|
|
363
|
-
|
|
364
979
|
// src/internal/log/processors/log-processor.ts
|
|
365
|
-
import { context } from "@opentelemetry/api";
|
|
980
|
+
import { context as context3 } from "@opentelemetry/api";
|
|
366
981
|
import { BatchLogRecordProcessor, SimpleLogRecordProcessor } from "@opentelemetry/sdk-logs";
|
|
367
982
|
|
|
368
983
|
// src/internal/masking/patterns.ts
|
|
@@ -989,13 +1604,6 @@ function maskAttributes(attributes, rules, outputOriginalValue = false) {
|
|
|
989
1604
|
return maskedAttributes;
|
|
990
1605
|
}
|
|
991
1606
|
|
|
992
|
-
// src/internal/semantic-conventions.ts
|
|
993
|
-
import { createContextKey } from "@opentelemetry/api";
|
|
994
|
-
var BRIZZ = "brizz";
|
|
995
|
-
var PROPERTIES = "properties";
|
|
996
|
-
var PROPERTIES_CONTEXT_KEY = createContextKey(PROPERTIES);
|
|
997
|
-
var SESSION_OBJECT_CONTEXT_KEY = createContextKey("brizz.session.object");
|
|
998
|
-
|
|
999
1607
|
// src/internal/log/processors/log-processor.ts
|
|
1000
1608
|
var DEFAULT_LOG_MASKING_RULES = [
|
|
1001
1609
|
{
|
|
@@ -1015,7 +1623,7 @@ var BrizzSimpleLogRecordProcessor = class extends SimpleLogRecordProcessor {
|
|
|
1015
1623
|
if (maskingConfig) {
|
|
1016
1624
|
maskLog(logRecord, maskingConfig);
|
|
1017
1625
|
}
|
|
1018
|
-
const associationProperties =
|
|
1626
|
+
const associationProperties = context3.active().getValue(PROPERTIES_CONTEXT_KEY);
|
|
1019
1627
|
if (associationProperties) {
|
|
1020
1628
|
for (const [key, value] of Object.entries(associationProperties)) {
|
|
1021
1629
|
logRecord.setAttribute(`${BRIZZ}.${key}`, value);
|
|
@@ -1035,7 +1643,7 @@ var BrizzBatchLogRecordProcessor = class extends BatchLogRecordProcessor {
|
|
|
1035
1643
|
if (maskingConfig) {
|
|
1036
1644
|
maskLog(logRecord, maskingConfig);
|
|
1037
1645
|
}
|
|
1038
|
-
const associationProperties =
|
|
1646
|
+
const associationProperties = context3.active().getValue(PROPERTIES_CONTEXT_KEY);
|
|
1039
1647
|
if (associationProperties) {
|
|
1040
1648
|
for (const [key, value] of Object.entries(associationProperties)) {
|
|
1041
1649
|
logRecord.setAttribute(`${BRIZZ}.${key}`, value);
|
|
@@ -1422,13 +2030,13 @@ var BrizzSpanExporter = class {
|
|
|
1422
2030
|
};
|
|
1423
2031
|
|
|
1424
2032
|
// src/internal/trace/processors/span-processor.ts
|
|
1425
|
-
import { context as
|
|
2033
|
+
import { context as context4 } from "@opentelemetry/api";
|
|
1426
2034
|
import {
|
|
1427
2035
|
BatchSpanProcessor,
|
|
1428
2036
|
SimpleSpanProcessor
|
|
1429
2037
|
} from "@opentelemetry/sdk-trace-base";
|
|
1430
2038
|
function applyContextAttributes(span) {
|
|
1431
|
-
const sessionProperties =
|
|
2039
|
+
const sessionProperties = context4.active().getValue(PROPERTIES_CONTEXT_KEY);
|
|
1432
2040
|
if (sessionProperties) {
|
|
1433
2041
|
for (const [key, value] of Object.entries(sessionProperties)) {
|
|
1434
2042
|
span.setAttribute(`${BRIZZ}.${key}`, value);
|
|
@@ -1625,7 +2233,7 @@ function getSpanProcessor() {
|
|
|
1625
2233
|
}
|
|
1626
2234
|
|
|
1627
2235
|
// src/internal/trace/session.ts
|
|
1628
|
-
import { context as
|
|
2236
|
+
import { context as context5, trace as trace3, SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
|
|
1629
2237
|
|
|
1630
2238
|
// src/internal/sdk.ts
|
|
1631
2239
|
var _Brizz = class __Brizz {
|