@frontmcp/observability 1.0.4 → 1.1.0

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/esm/index.mjs CHANGED
@@ -319,186 +319,142 @@ var init_otlp_sink = __esm({
319
319
  });
320
320
 
321
321
  // libs/observability/src/plugin/observability.plugin.ts
322
+ import { trace as trace5 } from "@opentelemetry/api";
322
323
  import {
324
+ AgentCallHook,
323
325
  DynamicPlugin,
324
- Plugin,
325
- ProviderScope,
326
+ FlowHooksOf,
326
327
  FRONTMCP_CONTEXT,
327
- ToolHook,
328
- ResourceHook,
329
328
  HttpHook,
330
- ListToolsHook,
331
329
  ListResourcesHook,
332
330
  ListResourceTemplatesHook,
333
- AgentCallHook,
334
- FlowHooksOf
331
+ ListToolsHook,
332
+ Plugin,
333
+ ProviderScope,
334
+ ResourceHook,
335
+ ToolHook
335
336
  } from "@frontmcp/sdk";
336
- import { trace as trace5 } from "@opentelemetry/api";
337
-
338
- // libs/observability/src/otel/otel.tokens.ts
339
- var OTEL_TRACER = /* @__PURE__ */ Symbol.for("frontmcp:observability:otel-tracer");
340
- var OTEL_CONFIG = /* @__PURE__ */ Symbol.for("frontmcp:observability:otel-config");
341
337
 
342
- // libs/observability/src/request-log/request-log.tokens.ts
343
- var REQUEST_LOG_COLLECTOR = /* @__PURE__ */ Symbol.for("frontmcp:observability:request-log-collector");
344
-
345
- // libs/observability/src/request-log/request-log.collector.ts
346
- var RequestLogCollector = class {
347
- constructor(context, options) {
348
- this.entries = [];
349
- this.hooksTriggered = /* @__PURE__ */ new Set();
350
- this.authenticated = false;
351
- this.status = "ok";
352
- this.finalized = false;
353
- this.requestId = context.requestId;
354
- this.traceId = context.traceId;
355
- this.sessionIdHash = context.sessionIdHash;
356
- this.scopeId = context.scopeId;
357
- this.startTime = /* @__PURE__ */ new Date();
358
- this.maxEntries = options?.maxEntries ?? 500;
359
- this.onComplete = options?.onRequestComplete;
360
- }
361
- /**
362
- * Add a structured log entry to this request's log.
363
- * Called by StructuredLogTransport for each log record that
364
- * matches this request's requestId.
365
- */
366
- addEntry(entry) {
367
- if (this.finalized || this.entries.length >= this.maxEntries) return;
368
- const logEntry = {
369
- timestamp: entry.timestamp,
370
- level: entry.level,
371
- message: entry.message
372
- };
373
- if (entry.flow_name) {
374
- logEntry.stage = entry.flow_name;
375
- }
376
- if (entry.elapsed_ms !== void 0) {
377
- logEntry.elapsed_ms = entry.elapsed_ms;
378
- }
379
- if (entry.attributes && Object.keys(entry.attributes).length > 0) {
380
- logEntry.attributes = entry.attributes;
381
- }
382
- this.entries.push(logEntry);
338
+ // libs/observability/src/logging/sinks/stdout.sink.ts
339
+ var StdoutSink = class {
340
+ constructor(options) {
341
+ this.stream = options?.stream ?? process.stdout;
342
+ this.pretty = options?.pretty ?? false;
383
343
  }
384
- /**
385
- * Record a hook stage that was triggered during this request.
386
- */
387
- addHook(stage) {
388
- this.hooksTriggered.add(stage);
344
+ write(entry) {
345
+ const line = this.pretty ? JSON.stringify(entry, null, 2) : JSON.stringify(entry);
346
+ this.stream.write(line + "\n");
389
347
  }
390
- /**
391
- * Set HTTP request metadata.
392
- */
393
- setHttpInfo(method, path) {
394
- this.httpMethod = method;
395
- this.httpPath = path;
348
+ };
349
+
350
+ // libs/observability/src/logging/sinks/console.sink.ts
351
+ var ConsoleSink = class {
352
+ write(entry) {
353
+ const method = levelToConsoleMethod(entry.level);
354
+ const formatted = formatEntry(entry);
355
+ method(formatted);
396
356
  }
397
- /**
398
- * Set the MCP JSON-RPC method being invoked.
399
- */
400
- setRpcMethod(method) {
401
- this.rpcMethod = method;
357
+ };
358
+ function formatEntry(entry) {
359
+ const useAnsi = typeof process !== "undefined" && !!process.stdout?.isTTY;
360
+ const ts = entry.timestamp.slice(11, 23);
361
+ const level = entry.level.toUpperCase().padEnd(7);
362
+ const traceShort = entry.trace_id ? entry.trace_id.slice(0, 8) : "";
363
+ const reqShort = entry.request_id ? entry.request_id.slice(0, 8) : "";
364
+ const parts = [];
365
+ const DIM2 = useAnsi ? "\x1B[2m" : "";
366
+ const BOLD2 = useAnsi ? "\x1B[1m" : "";
367
+ const RESET2 = useAnsi ? "\x1B[0m" : "";
368
+ const levelColor = useAnsi ? LEVEL_COLORS[entry.level] ?? "" : "";
369
+ parts.push(`${DIM2}[${ts}]${RESET2}`);
370
+ parts.push(`${BOLD2}${levelColor}${level}${RESET2}`);
371
+ if (traceShort || reqShort) {
372
+ parts.push(`${DIM2}[${traceShort}${reqShort ? ":" + reqShort : ""}]${RESET2}`);
402
373
  }
403
- /**
404
- * Set the tool name being invoked.
405
- */
406
- setToolName(name) {
407
- this.toolName = name;
374
+ if (entry.prefix) parts.push(`${DIM2}[${entry.prefix}]${RESET2}`);
375
+ parts.push(entry.message);
376
+ if (entry.attributes && Object.keys(entry.attributes).length > 0) {
377
+ const attrs = Object.entries(entry.attributes).map(([k, v]) => `${k}=${typeof v === "string" ? v : JSON.stringify(v)}`).join(" ");
378
+ parts.push(`${DIM2}{ ${attrs} }${RESET2}`);
408
379
  }
409
- /**
410
- * Set the resource URI being read.
411
- */
412
- setResourceUri(uri) {
413
- this.resourceUri = uri;
380
+ if (entry.error) {
381
+ parts.push(`[${entry.error.type}: ${entry.error.message}]`);
414
382
  }
415
- /**
416
- * Set the prompt name being invoked.
417
- */
418
- setPromptName(name) {
419
- this.promptName = name;
383
+ if (entry.elapsed_ms !== void 0) {
384
+ parts.push(`${DIM2}(${entry.elapsed_ms}ms)${RESET2}`);
420
385
  }
421
- /**
422
- * Set authentication info.
423
- */
424
- setAuthInfo(type, authenticated) {
425
- this.authType = type;
426
- this.authenticated = authenticated;
386
+ return parts.join(" ");
387
+ }
388
+ var LEVEL_COLORS = {
389
+ debug: "\x1B[34m",
390
+ verbose: "\x1B[90m",
391
+ info: "\x1B[32m",
392
+ warn: "\x1B[33m",
393
+ error: "\x1B[31m"
394
+ };
395
+ function levelToConsoleMethod(level) {
396
+ switch (level) {
397
+ case "debug":
398
+ case "verbose":
399
+ return console.debug;
400
+ case "info":
401
+ return console.info;
402
+ case "warn":
403
+ return console.warn;
404
+ case "error":
405
+ return console.error;
406
+ default:
407
+ return console.log;
427
408
  }
428
- /**
429
- * Set request status.
430
- */
431
- setStatus(status, statusCode) {
432
- this.status = status;
433
- this.statusCode = statusCode;
409
+ }
410
+
411
+ // libs/observability/src/logging/sinks/callback.sink.ts
412
+ var CallbackSink = class {
413
+ constructor(fn) {
414
+ this.fn = fn;
434
415
  }
435
- /**
436
- * Set error details.
437
- */
438
- setError(error) {
439
- this.error = error;
440
- this.status = "error";
416
+ write(entry) {
417
+ this.fn(entry);
441
418
  }
442
- /**
443
- * Finalize and produce the complete RequestLog.
444
- * Fires the onRequestComplete callback if configured.
445
- */
446
- async finalize() {
447
- if (this.finalized) {
448
- return this.finalizedLog;
419
+ };
420
+
421
+ // libs/observability/src/logging/sink.factory.ts
422
+ function createSink(config) {
423
+ switch (config.type) {
424
+ case "stdout":
425
+ return new StdoutSink({ stream: config.stream, pretty: config.pretty });
426
+ case "console":
427
+ return new ConsoleSink();
428
+ case "winston": {
429
+ const { WinstonSink: WinstonSink2 } = (init_winston_sink(), __toCommonJS(winston_sink_exports));
430
+ return new WinstonSink2(config.logger);
449
431
  }
450
- this.finalized = true;
451
- const log = this.toRequestLog();
452
- this.finalizedLog = log;
453
- if (this.onComplete) {
454
- try {
455
- await this.onComplete(log);
456
- } catch {
457
- }
432
+ case "pino": {
433
+ const { PinoSink: PinoSink2 } = (init_pino_sink(), __toCommonJS(pino_sink_exports));
434
+ return new PinoSink2(config.logger);
458
435
  }
459
- return log;
460
- }
461
- /**
462
- * Build the RequestLog object from accumulated state.
463
- */
464
- toRequestLog() {
465
- const endTime = /* @__PURE__ */ new Date();
466
- return {
467
- request_id: this.requestId,
468
- trace_id: this.traceId,
469
- session_id_hash: this.sessionIdHash,
470
- scope_id: this.scopeId,
471
- start_time: this.startTime.toISOString(),
472
- end_time: endTime.toISOString(),
473
- duration_ms: endTime.getTime() - this.startTime.getTime(),
474
- http_method: this.httpMethod,
475
- http_path: this.httpPath,
476
- rpc_method: this.rpcMethod,
477
- tool_name: this.toolName,
478
- resource_uri: this.resourceUri,
479
- prompt_name: this.promptName,
480
- auth_type: this.authType,
481
- authenticated: this.authenticated,
482
- status: this.status,
483
- status_code: this.statusCode,
484
- error: this.error,
485
- hooks_triggered: Array.from(this.hooksTriggered),
486
- entries: [...this.entries]
487
- };
488
- }
489
- /**
490
- * Check if the collector has been finalized.
491
- */
492
- isFinalized() {
493
- return this.finalized;
436
+ case "callback":
437
+ return new CallbackSink(config.fn);
438
+ case "otlp": {
439
+ const { OtlpSink: OtlpSink2 } = (init_otlp_sink(), __toCommonJS(otlp_sink_exports));
440
+ return new OtlpSink2({
441
+ endpoint: config.endpoint ?? (typeof process !== "undefined" ? process.env?.["OTEL_EXPORTER_OTLP_ENDPOINT"] : void 0) ?? "http://localhost:4318",
442
+ headers: config.headers,
443
+ batchSize: config.batchSize,
444
+ flushIntervalMs: config.flushIntervalMs,
445
+ serviceName: config.serviceName
446
+ });
447
+ }
448
+ default:
449
+ throw new Error(`Unknown sink type: ${config.type}`);
494
450
  }
495
- /**
496
- * Get the number of accumulated entries.
497
- */
498
- getEntryCount() {
499
- return this.entries.length;
451
+ }
452
+ function createSinks(configs) {
453
+ if (configs && configs.length > 0) {
454
+ return configs.map(createSink);
500
455
  }
501
- };
456
+ return [];
457
+ }
502
458
 
503
459
  // libs/observability/src/logging/structured-log-transport.ts
504
460
  import { LogTransportInterface, LogLevelName, LogTransport } from "@frontmcp/sdk";
@@ -642,126 +598,170 @@ StructuredLogTransport = __decorateClass([
642
598
  })
643
599
  ], StructuredLogTransport);
644
600
 
645
- // libs/observability/src/logging/sinks/stdout.sink.ts
646
- var StdoutSink = class {
647
- constructor(options) {
648
- this.stream = options?.stream ?? process.stdout;
649
- this.pretty = options?.pretty ?? false;
601
+ // libs/observability/src/otel/otel.tokens.ts
602
+ var OTEL_TRACER = /* @__PURE__ */ Symbol.for("frontmcp:observability:otel-tracer");
603
+ var OTEL_CONFIG = /* @__PURE__ */ Symbol.for("frontmcp:observability:otel-config");
604
+
605
+ // libs/observability/src/request-log/request-log.collector.ts
606
+ var RequestLogCollector = class {
607
+ constructor(context, options) {
608
+ this.entries = [];
609
+ this.hooksTriggered = /* @__PURE__ */ new Set();
610
+ this.authenticated = false;
611
+ this.status = "ok";
612
+ this.finalized = false;
613
+ this.requestId = context.requestId;
614
+ this.traceId = context.traceId;
615
+ this.sessionIdHash = context.sessionIdHash;
616
+ this.scopeId = context.scopeId;
617
+ this.startTime = /* @__PURE__ */ new Date();
618
+ this.maxEntries = options?.maxEntries ?? 500;
619
+ this.onComplete = options?.onRequestComplete;
650
620
  }
651
- write(entry) {
652
- const line = this.pretty ? JSON.stringify(entry, null, 2) : JSON.stringify(entry);
653
- this.stream.write(line + "\n");
621
+ /**
622
+ * Add a structured log entry to this request's log.
623
+ * Called by StructuredLogTransport for each log record that
624
+ * matches this request's requestId.
625
+ */
626
+ addEntry(entry) {
627
+ if (this.finalized || this.entries.length >= this.maxEntries) return;
628
+ const logEntry = {
629
+ timestamp: entry.timestamp,
630
+ level: entry.level,
631
+ message: entry.message
632
+ };
633
+ if (entry.flow_name) {
634
+ logEntry.stage = entry.flow_name;
635
+ }
636
+ if (entry.elapsed_ms !== void 0) {
637
+ logEntry.elapsed_ms = entry.elapsed_ms;
638
+ }
639
+ if (entry.attributes && Object.keys(entry.attributes).length > 0) {
640
+ logEntry.attributes = entry.attributes;
641
+ }
642
+ this.entries.push(logEntry);
654
643
  }
655
- };
656
-
657
- // libs/observability/src/logging/sinks/console.sink.ts
658
- var ConsoleSink = class {
659
- write(entry) {
660
- const method = levelToConsoleMethod(entry.level);
661
- const formatted = formatEntry(entry);
662
- method(formatted);
644
+ /**
645
+ * Record a hook stage that was triggered during this request.
646
+ */
647
+ addHook(stage) {
648
+ this.hooksTriggered.add(stage);
663
649
  }
664
- };
665
- function formatEntry(entry) {
666
- const useAnsi = typeof process !== "undefined" && !!process.stdout?.isTTY;
667
- const ts = entry.timestamp.slice(11, 23);
668
- const level = entry.level.toUpperCase().padEnd(7);
669
- const traceShort = entry.trace_id ? entry.trace_id.slice(0, 8) : "";
670
- const reqShort = entry.request_id ? entry.request_id.slice(0, 8) : "";
671
- const parts = [];
672
- const DIM2 = useAnsi ? "\x1B[2m" : "";
673
- const BOLD2 = useAnsi ? "\x1B[1m" : "";
674
- const RESET2 = useAnsi ? "\x1B[0m" : "";
675
- const levelColor = useAnsi ? LEVEL_COLORS[entry.level] ?? "" : "";
676
- parts.push(`${DIM2}[${ts}]${RESET2}`);
677
- parts.push(`${BOLD2}${levelColor}${level}${RESET2}`);
678
- if (traceShort || reqShort) {
679
- parts.push(`${DIM2}[${traceShort}${reqShort ? ":" + reqShort : ""}]${RESET2}`);
650
+ /**
651
+ * Set HTTP request metadata.
652
+ */
653
+ setHttpInfo(method, path) {
654
+ this.httpMethod = method;
655
+ this.httpPath = path;
680
656
  }
681
- if (entry.prefix) parts.push(`${DIM2}[${entry.prefix}]${RESET2}`);
682
- parts.push(entry.message);
683
- if (entry.attributes && Object.keys(entry.attributes).length > 0) {
684
- const attrs = Object.entries(entry.attributes).map(([k, v]) => `${k}=${typeof v === "string" ? v : JSON.stringify(v)}`).join(" ");
685
- parts.push(`${DIM2}{ ${attrs} }${RESET2}`);
657
+ /**
658
+ * Set the MCP JSON-RPC method being invoked.
659
+ */
660
+ setRpcMethod(method) {
661
+ this.rpcMethod = method;
686
662
  }
687
- if (entry.error) {
688
- parts.push(`[${entry.error.type}: ${entry.error.message}]`);
663
+ /**
664
+ * Set the tool name being invoked.
665
+ */
666
+ setToolName(name) {
667
+ this.toolName = name;
689
668
  }
690
- if (entry.elapsed_ms !== void 0) {
691
- parts.push(`${DIM2}(${entry.elapsed_ms}ms)${RESET2}`);
669
+ /**
670
+ * Set the resource URI being read.
671
+ */
672
+ setResourceUri(uri) {
673
+ this.resourceUri = uri;
692
674
  }
693
- return parts.join(" ");
694
- }
695
- var LEVEL_COLORS = {
696
- debug: "\x1B[34m",
697
- verbose: "\x1B[90m",
698
- info: "\x1B[32m",
699
- warn: "\x1B[33m",
700
- error: "\x1B[31m"
701
- };
702
- function levelToConsoleMethod(level) {
703
- switch (level) {
704
- case "debug":
705
- case "verbose":
706
- return console.debug;
707
- case "info":
708
- return console.info;
709
- case "warn":
710
- return console.warn;
711
- case "error":
712
- return console.error;
713
- default:
714
- return console.log;
675
+ /**
676
+ * Set the prompt name being invoked.
677
+ */
678
+ setPromptName(name) {
679
+ this.promptName = name;
715
680
  }
716
- }
717
-
718
- // libs/observability/src/logging/sinks/callback.sink.ts
719
- var CallbackSink = class {
720
- constructor(fn) {
721
- this.fn = fn;
681
+ /**
682
+ * Set authentication info.
683
+ */
684
+ setAuthInfo(type, authenticated) {
685
+ this.authType = type;
686
+ this.authenticated = authenticated;
722
687
  }
723
- write(entry) {
724
- this.fn(entry);
688
+ /**
689
+ * Set request status.
690
+ */
691
+ setStatus(status, statusCode) {
692
+ this.status = status;
693
+ this.statusCode = statusCode;
725
694
  }
726
- };
727
-
728
- // libs/observability/src/logging/sink.factory.ts
729
- function createSink(config) {
730
- switch (config.type) {
731
- case "stdout":
732
- return new StdoutSink({ stream: config.stream, pretty: config.pretty });
733
- case "console":
734
- return new ConsoleSink();
735
- case "winston": {
736
- const { WinstonSink: WinstonSink2 } = (init_winston_sink(), __toCommonJS(winston_sink_exports));
737
- return new WinstonSink2(config.logger);
738
- }
739
- case "pino": {
740
- const { PinoSink: PinoSink2 } = (init_pino_sink(), __toCommonJS(pino_sink_exports));
741
- return new PinoSink2(config.logger);
695
+ /**
696
+ * Set error details.
697
+ */
698
+ setError(error) {
699
+ this.error = error;
700
+ this.status = "error";
701
+ }
702
+ /**
703
+ * Finalize and produce the complete RequestLog.
704
+ * Fires the onRequestComplete callback if configured.
705
+ */
706
+ async finalize() {
707
+ if (this.finalized) {
708
+ return this.finalizedLog;
742
709
  }
743
- case "callback":
744
- return new CallbackSink(config.fn);
745
- case "otlp": {
746
- const { OtlpSink: OtlpSink2 } = (init_otlp_sink(), __toCommonJS(otlp_sink_exports));
747
- return new OtlpSink2({
748
- endpoint: config.endpoint ?? (typeof process !== "undefined" ? process.env?.["OTEL_EXPORTER_OTLP_ENDPOINT"] : void 0) ?? "http://localhost:4318",
749
- headers: config.headers,
750
- batchSize: config.batchSize,
751
- flushIntervalMs: config.flushIntervalMs,
752
- serviceName: config.serviceName
753
- });
710
+ this.finalized = true;
711
+ const log = this.toRequestLog();
712
+ this.finalizedLog = log;
713
+ if (this.onComplete) {
714
+ try {
715
+ await this.onComplete(log);
716
+ } catch {
717
+ }
754
718
  }
755
- default:
756
- throw new Error(`Unknown sink type: ${config.type}`);
719
+ return log;
720
+ }
721
+ /**
722
+ * Build the RequestLog object from accumulated state.
723
+ */
724
+ toRequestLog() {
725
+ const endTime = /* @__PURE__ */ new Date();
726
+ return {
727
+ request_id: this.requestId,
728
+ trace_id: this.traceId,
729
+ session_id_hash: this.sessionIdHash,
730
+ scope_id: this.scopeId,
731
+ start_time: this.startTime.toISOString(),
732
+ end_time: endTime.toISOString(),
733
+ duration_ms: endTime.getTime() - this.startTime.getTime(),
734
+ http_method: this.httpMethod,
735
+ http_path: this.httpPath,
736
+ rpc_method: this.rpcMethod,
737
+ tool_name: this.toolName,
738
+ resource_uri: this.resourceUri,
739
+ prompt_name: this.promptName,
740
+ auth_type: this.authType,
741
+ authenticated: this.authenticated,
742
+ status: this.status,
743
+ status_code: this.statusCode,
744
+ error: this.error,
745
+ hooks_triggered: Array.from(this.hooksTriggered),
746
+ entries: [...this.entries]
747
+ };
757
748
  }
758
- }
759
- function createSinks(configs) {
760
- if (configs && configs.length > 0) {
761
- return configs.map(createSink);
749
+ /**
750
+ * Check if the collector has been finalized.
751
+ */
752
+ isFinalized() {
753
+ return this.finalized;
762
754
  }
763
- return [];
764
- }
755
+ /**
756
+ * Get the number of accumulated entries.
757
+ */
758
+ getEntryCount() {
759
+ return this.entries.length;
760
+ }
761
+ };
762
+
763
+ // libs/observability/src/request-log/request-log.tokens.ts
764
+ var REQUEST_LOG_COLLECTOR = /* @__PURE__ */ Symbol.for("frontmcp:observability:request-log-collector");
765
765
 
766
766
  // libs/observability/src/telemetry/telemetry.accessor.ts
767
767
  import {
@@ -800,15 +800,12 @@ function createOTelContextFromTrace(tc) {
800
800
  }
801
801
 
802
802
  // libs/observability/src/plugin/observability.hooks.ts
803
- import { sha256Hex } from "@frontmcp/utils";
804
803
  import {
804
+ context as otelContext3,
805
805
  SpanKind as SpanKind11,
806
- trace as trace3,
807
- context as otelContext3
806
+ trace as trace3
808
807
  } from "@opentelemetry/api";
809
-
810
- // libs/observability/src/otel/spans/http-server.span.ts
811
- import { SpanKind as SpanKind2 } from "@opentelemetry/api";
808
+ import { sha256Hex } from "@frontmcp/utils";
812
809
 
813
810
  // libs/observability/src/otel/otel.types.ts
814
811
  var McpAttributes = {
@@ -923,6 +920,9 @@ var EnduserAttributes = {
923
920
  SCOPE: "enduser.scope"
924
921
  };
925
922
 
923
+ // libs/observability/src/otel/spans/auth.span.ts
924
+ import { SpanKind as SpanKind2 } from "@opentelemetry/api";
925
+
926
926
  // libs/observability/src/otel/spans/span.utils.ts
927
927
  import {
928
928
  SpanKind,
@@ -969,7 +969,43 @@ async function withSpan(tracer, options, fn) {
969
969
  });
970
970
  }
971
971
 
972
+ // libs/observability/src/otel/spans/auth.span.ts
973
+ function startAuthSpan(tracer, options) {
974
+ return startSpan(tracer, {
975
+ name: `auth ${options.flowName}`,
976
+ kind: SpanKind2.INTERNAL,
977
+ attributes: {
978
+ [FrontMcpAttributes.FLOW_NAME]: options.flowName
979
+ },
980
+ parentContext: options.parentContext
981
+ });
982
+ }
983
+ function setAuthMode(span, mode) {
984
+ span.setAttribute(FrontMcpAttributes.AUTH_MODE, mode);
985
+ }
986
+ function setAuthResult(span, result) {
987
+ span.setAttribute(FrontMcpAttributes.AUTH_RESULT, result);
988
+ }
989
+
990
+ // libs/observability/src/otel/spans/fetch.span.ts
991
+ import { SpanKind as SpanKind3 } from "@opentelemetry/api";
992
+ function startFetchSpan(tracer, options) {
993
+ return startSpan(tracer, {
994
+ name: options.method.toUpperCase(),
995
+ kind: SpanKind3.CLIENT,
996
+ attributes: {
997
+ [HttpAttributes.METHOD]: options.method.toUpperCase(),
998
+ [HttpAttributes.URL_FULL]: options.url
999
+ },
1000
+ parentContext: options.parentContext
1001
+ });
1002
+ }
1003
+ function setFetchResponseStatus(span, statusCode) {
1004
+ span.setAttribute(HttpAttributes.STATUS_CODE, statusCode);
1005
+ }
1006
+
972
1007
  // libs/observability/src/otel/spans/http-server.span.ts
1008
+ import { SpanKind as SpanKind4 } from "@opentelemetry/api";
973
1009
  function startHttpServerSpan(tracer, options) {
974
1010
  const attributes = {
975
1011
  [HttpAttributes.METHOD]: options.method.toUpperCase(),
@@ -992,7 +1028,7 @@ function startHttpServerSpan(tracer, options) {
992
1028
  }
993
1029
  return startSpan(tracer, {
994
1030
  name: `${options.method.toUpperCase()} ${options.path}`,
995
- kind: SpanKind2.SERVER,
1031
+ kind: SpanKind4.SERVER,
996
1032
  attributes,
997
1033
  parentContext: options.parentContext
998
1034
  });
@@ -1001,8 +1037,43 @@ function setHttpResponseStatus(span, statusCode) {
1001
1037
  span.setAttribute(HttpAttributes.STATUS_CODE, statusCode);
1002
1038
  }
1003
1039
 
1040
+ // libs/observability/src/otel/spans/prompt.span.ts
1041
+ import { SpanKind as SpanKind5 } from "@opentelemetry/api";
1042
+ function startPromptSpan(tracer, options) {
1043
+ return startSpan(tracer, {
1044
+ name: `prompt ${options.name}`,
1045
+ kind: SpanKind5.INTERNAL,
1046
+ attributes: {
1047
+ [FrontMcpAttributes.PROMPT_NAME]: options.name,
1048
+ [McpAttributes.COMPONENT_TYPE]: "prompt",
1049
+ [McpAttributes.COMPONENT_KEY]: `prompt:${options.name}`
1050
+ },
1051
+ parentContext: options.parentContext
1052
+ });
1053
+ }
1054
+
1055
+ // libs/observability/src/otel/spans/resource.span.ts
1056
+ import { SpanKind as SpanKind6 } from "@opentelemetry/api";
1057
+ function startResourceSpan(tracer, options) {
1058
+ const attributes = {
1059
+ [FrontMcpAttributes.RESOURCE_URI]: options.uri,
1060
+ [McpAttributes.RESOURCE_URI]: options.uri,
1061
+ [McpAttributes.COMPONENT_TYPE]: "resource",
1062
+ [McpAttributes.COMPONENT_KEY]: `resource:${options.uri}`
1063
+ };
1064
+ if (options.name) {
1065
+ attributes[FrontMcpAttributes.RESOURCE_NAME] = options.name;
1066
+ }
1067
+ return startSpan(tracer, {
1068
+ name: `resource ${options.uri}`,
1069
+ kind: SpanKind6.INTERNAL,
1070
+ attributes,
1071
+ parentContext: options.parentContext
1072
+ });
1073
+ }
1074
+
1004
1075
  // libs/observability/src/otel/spans/rpc.span.ts
1005
- import { SpanKind as SpanKind3 } from "@opentelemetry/api";
1076
+ import { SpanKind as SpanKind7 } from "@opentelemetry/api";
1006
1077
  function startRpcSpan(tracer, options) {
1007
1078
  const attributes = {
1008
1079
  [RpcAttributes.SYSTEM]: "mcp",
@@ -1026,14 +1097,35 @@ function startRpcSpan(tracer, options) {
1026
1097
  }
1027
1098
  return startSpan(tracer, {
1028
1099
  name: options.method,
1029
- kind: SpanKind3.SERVER,
1100
+ kind: SpanKind7.SERVER,
1030
1101
  attributes,
1031
1102
  parentContext: options.parentContext
1032
1103
  });
1033
1104
  }
1034
1105
 
1106
+ // libs/observability/src/otel/spans/startup.span.ts
1107
+ import { SpanKind as SpanKind8 } from "@opentelemetry/api";
1108
+ function emitStartupReport(tracer, data) {
1109
+ const attributes = {
1110
+ [FrontMcpAttributes.STARTUP_TOOLS_COUNT]: data.toolsCount,
1111
+ [FrontMcpAttributes.STARTUP_RESOURCES_COUNT]: data.resourcesCount,
1112
+ [FrontMcpAttributes.STARTUP_PROMPTS_COUNT]: data.promptsCount,
1113
+ [FrontMcpAttributes.STARTUP_PLUGINS_COUNT]: data.pluginsCount,
1114
+ [FrontMcpAttributes.STARTUP_DURATION_MS]: data.durationMs
1115
+ };
1116
+ if (data.scopeId) {
1117
+ attributes[FrontMcpAttributes.SCOPE_ID] = data.scopeId;
1118
+ }
1119
+ const { span } = startSpan(tracer, {
1120
+ name: "frontmcp.startup",
1121
+ kind: SpanKind8.INTERNAL,
1122
+ attributes
1123
+ });
1124
+ endSpanOk(span);
1125
+ }
1126
+
1035
1127
  // libs/observability/src/otel/spans/tool.span.ts
1036
- import { SpanKind as SpanKind4 } from "@opentelemetry/api";
1128
+ import { SpanKind as SpanKind9 } from "@opentelemetry/api";
1037
1129
  function startToolSpan(tracer, options) {
1038
1130
  const attributes = {
1039
1131
  [FrontMcpAttributes.TOOL_NAME]: options.name,
@@ -1051,49 +1143,14 @@ function startToolSpan(tracer, options) {
1051
1143
  }
1052
1144
  return startSpan(tracer, {
1053
1145
  name: `tool ${options.name}`,
1054
- kind: SpanKind4.INTERNAL,
1055
- attributes,
1056
- parentContext: options.parentContext
1057
- });
1058
- }
1059
-
1060
- // libs/observability/src/otel/spans/resource.span.ts
1061
- import { SpanKind as SpanKind5 } from "@opentelemetry/api";
1062
- function startResourceSpan(tracer, options) {
1063
- const attributes = {
1064
- [FrontMcpAttributes.RESOURCE_URI]: options.uri,
1065
- [McpAttributes.RESOURCE_URI]: options.uri,
1066
- [McpAttributes.COMPONENT_TYPE]: "resource",
1067
- [McpAttributes.COMPONENT_KEY]: `resource:${options.uri}`
1068
- };
1069
- if (options.name) {
1070
- attributes[FrontMcpAttributes.RESOURCE_NAME] = options.name;
1071
- }
1072
- return startSpan(tracer, {
1073
- name: `resource ${options.uri}`,
1074
- kind: SpanKind5.INTERNAL,
1146
+ kind: SpanKind9.INTERNAL,
1075
1147
  attributes,
1076
1148
  parentContext: options.parentContext
1077
1149
  });
1078
1150
  }
1079
1151
 
1080
- // libs/observability/src/otel/spans/prompt.span.ts
1081
- import { SpanKind as SpanKind6 } from "@opentelemetry/api";
1082
- function startPromptSpan(tracer, options) {
1083
- return startSpan(tracer, {
1084
- name: `prompt ${options.name}`,
1085
- kind: SpanKind6.INTERNAL,
1086
- attributes: {
1087
- [FrontMcpAttributes.PROMPT_NAME]: options.name,
1088
- [McpAttributes.COMPONENT_TYPE]: "prompt",
1089
- [McpAttributes.COMPONENT_KEY]: `prompt:${options.name}`
1090
- },
1091
- parentContext: options.parentContext
1092
- });
1093
- }
1094
-
1095
1152
  // libs/observability/src/otel/spans/transport.span.ts
1096
- import { SpanKind as SpanKind7 } from "@opentelemetry/api";
1153
+ import { SpanKind as SpanKind10 } from "@opentelemetry/api";
1097
1154
  function startTransportSpan(tracer, options) {
1098
1155
  const attributes = {
1099
1156
  [FrontMcpAttributes.TRANSPORT_TYPE]: options.type
@@ -1106,7 +1163,7 @@ function startTransportSpan(tracer, options) {
1106
1163
  }
1107
1164
  return startSpan(tracer, {
1108
1165
  name: `transport ${options.type}`,
1109
- kind: SpanKind7.INTERNAL,
1166
+ kind: SpanKind10.INTERNAL,
1110
1167
  attributes,
1111
1168
  parentContext: options.parentContext
1112
1169
  });
@@ -1115,63 +1172,6 @@ function setTransportRequestType(span, requestType) {
1115
1172
  span.setAttribute(FrontMcpAttributes.TRANSPORT_REQUEST_TYPE, requestType);
1116
1173
  }
1117
1174
 
1118
- // libs/observability/src/otel/spans/auth.span.ts
1119
- import { SpanKind as SpanKind8 } from "@opentelemetry/api";
1120
- function startAuthSpan(tracer, options) {
1121
- return startSpan(tracer, {
1122
- name: `auth ${options.flowName}`,
1123
- kind: SpanKind8.INTERNAL,
1124
- attributes: {
1125
- [FrontMcpAttributes.FLOW_NAME]: options.flowName
1126
- },
1127
- parentContext: options.parentContext
1128
- });
1129
- }
1130
- function setAuthMode(span, mode) {
1131
- span.setAttribute(FrontMcpAttributes.AUTH_MODE, mode);
1132
- }
1133
- function setAuthResult(span, result) {
1134
- span.setAttribute(FrontMcpAttributes.AUTH_RESULT, result);
1135
- }
1136
-
1137
- // libs/observability/src/otel/spans/fetch.span.ts
1138
- import { SpanKind as SpanKind9 } from "@opentelemetry/api";
1139
- function startFetchSpan(tracer, options) {
1140
- return startSpan(tracer, {
1141
- name: options.method.toUpperCase(),
1142
- kind: SpanKind9.CLIENT,
1143
- attributes: {
1144
- [HttpAttributes.METHOD]: options.method.toUpperCase(),
1145
- [HttpAttributes.URL_FULL]: options.url
1146
- },
1147
- parentContext: options.parentContext
1148
- });
1149
- }
1150
- function setFetchResponseStatus(span, statusCode) {
1151
- span.setAttribute(HttpAttributes.STATUS_CODE, statusCode);
1152
- }
1153
-
1154
- // libs/observability/src/otel/spans/startup.span.ts
1155
- import { SpanKind as SpanKind10 } from "@opentelemetry/api";
1156
- function emitStartupReport(tracer, data) {
1157
- const attributes = {
1158
- [FrontMcpAttributes.STARTUP_TOOLS_COUNT]: data.toolsCount,
1159
- [FrontMcpAttributes.STARTUP_RESOURCES_COUNT]: data.resourcesCount,
1160
- [FrontMcpAttributes.STARTUP_PROMPTS_COUNT]: data.promptsCount,
1161
- [FrontMcpAttributes.STARTUP_PLUGINS_COUNT]: data.pluginsCount,
1162
- [FrontMcpAttributes.STARTUP_DURATION_MS]: data.durationMs
1163
- };
1164
- if (data.scopeId) {
1165
- attributes[FrontMcpAttributes.SCOPE_ID] = data.scopeId;
1166
- }
1167
- const { span } = startSpan(tracer, {
1168
- name: "frontmcp.startup",
1169
- kind: SpanKind10.INTERNAL,
1170
- attributes
1171
- });
1172
- endSpanOk(span);
1173
- }
1174
-
1175
1175
  // libs/observability/src/plugin/observability.hooks.ts
1176
1176
  var SPAN_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:span");
1177
1177
  var SPAN_CTX_KEY = /* @__PURE__ */ Symbol.for("frontmcp:otel:span-ctx");
@@ -1306,6 +1306,16 @@ function onToolWillCheckAuth(flowCtx) {
1306
1306
  const span = flowCtx.state?.[SPAN_KEY];
1307
1307
  if (span) recordStageEvent(span, "checkToolAuthorization", flowCtx.state);
1308
1308
  }
1309
+ function onEntryWillCheckAuthorities(flowCtx) {
1310
+ const span = flowCtx.state?.[SPAN_KEY];
1311
+ if (span) recordStageEvent(span, "checkEntryAuthorities", flowCtx.state);
1312
+ }
1313
+ function onEntryDidCheckAuthorities(flowCtx) {
1314
+ const span = flowCtx.state?.[SPAN_KEY];
1315
+ if (!span) return;
1316
+ recordStageEvent(span, "checkEntryAuthorities.done", flowCtx.state);
1317
+ span.setAttribute("auth.authorities.result", "granted");
1318
+ }
1309
1319
  function onToolWillCreateContext(flowCtx) {
1310
1320
  const span = flowCtx.state?.[SPAN_KEY];
1311
1321
  if (span) recordStageEvent(span, "createToolCallContext", flowCtx.state);
@@ -1944,6 +1954,12 @@ var ObservabilityPlugin = class extends DynamicPlugin {
1944
1954
  _toolWillCheckAuth(ctx) {
1945
1955
  if (this.tracingEnabled) onToolWillCheckAuth(ctx);
1946
1956
  }
1957
+ _toolWillCheckAuthorities(ctx) {
1958
+ if (this.tracingEnabled) onEntryWillCheckAuthorities(ctx);
1959
+ }
1960
+ _toolDidCheckAuthorities(ctx) {
1961
+ if (this.tracingEnabled) onEntryDidCheckAuthorities(ctx);
1962
+ }
1947
1963
  _toolWillCreateCtx(ctx) {
1948
1964
  if (this.tracingEnabled) onToolWillCreateContext(ctx);
1949
1965
  }
@@ -1971,6 +1987,12 @@ var ObservabilityPlugin = class extends DynamicPlugin {
1971
1987
  _resourceWillFind(ctx) {
1972
1988
  if (this.tracingEnabled) onResourceWillFind(ctx);
1973
1989
  }
1990
+ _resourceWillCheckAuthorities(ctx) {
1991
+ if (this.tracingEnabled) onEntryWillCheckAuthorities(ctx);
1992
+ }
1993
+ _resourceDidCheckAuthorities(ctx) {
1994
+ if (this.tracingEnabled) onEntryDidCheckAuthorities(ctx);
1995
+ }
1974
1996
  _resourceWillExecute(ctx) {
1975
1997
  if (this.tracingEnabled) onResourceWillExecute(this.tracingOpts, ctx);
1976
1998
  }
@@ -1986,6 +2008,12 @@ var ObservabilityPlugin = class extends DynamicPlugin {
1986
2008
  _promptWillFind(ctx) {
1987
2009
  if (this.tracingEnabled) onPromptWillFind(ctx);
1988
2010
  }
2011
+ _promptWillCheckAuthorities(ctx) {
2012
+ if (this.tracingEnabled) onEntryWillCheckAuthorities(ctx);
2013
+ }
2014
+ _promptDidCheckAuthorities(ctx) {
2015
+ if (this.tracingEnabled) onEntryDidCheckAuthorities(ctx);
2016
+ }
1989
2017
  _promptWillExecute(ctx) {
1990
2018
  if (this.tracingEnabled) onPromptWillExecute(this.tracingOpts, ctx);
1991
2019
  }
@@ -2001,6 +2029,12 @@ var ObservabilityPlugin = class extends DynamicPlugin {
2001
2029
  _agentWillFind(ctx) {
2002
2030
  if (this.tracingEnabled) onAgentWillFind(ctx);
2003
2031
  }
2032
+ _agentWillCheckAuthorities(ctx) {
2033
+ if (this.tracingEnabled) onEntryWillCheckAuthorities(ctx);
2034
+ }
2035
+ _agentDidCheckAuthorities(ctx) {
2036
+ if (this.tracingEnabled) onEntryDidCheckAuthorities(ctx);
2037
+ }
2004
2038
  _agentWillExecute(ctx) {
2005
2039
  if (this.tracingEnabled) onAgentWillExecute(this.tracingOpts, ctx);
2006
2040
  }
@@ -2016,24 +2050,36 @@ var ObservabilityPlugin = class extends DynamicPlugin {
2016
2050
  _listToolsDidFind(ctx) {
2017
2051
  if (this.tracingEnabled) onGenericFlowStage("findTools", ctx);
2018
2052
  }
2053
+ _listToolsDidFilter(ctx) {
2054
+ if (this.tracingEnabled) onGenericFlowStage("filterByAuthorities", ctx);
2055
+ }
2019
2056
  _listToolsDone(ctx) {
2020
2057
  if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2021
2058
  }
2022
2059
  _listResourcesWill(ctx) {
2023
2060
  if (this.tracingEnabled) onGenericFlowWillStart("resources/list", this.tracingOpts, ctx);
2024
2061
  }
2062
+ _listResourcesDidFilter(ctx) {
2063
+ if (this.tracingEnabled) onGenericFlowStage("filterByAuthorities", ctx);
2064
+ }
2025
2065
  _listResourcesDone(ctx) {
2026
2066
  if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2027
2067
  }
2028
2068
  _listTemplatesWill(ctx) {
2029
2069
  if (this.tracingEnabled) onGenericFlowWillStart("resources/listTemplates", this.tracingOpts, ctx);
2030
2070
  }
2071
+ _listTemplatesDidFilter(ctx) {
2072
+ if (this.tracingEnabled) onGenericFlowStage("filterByAuthorities", ctx);
2073
+ }
2031
2074
  _listTemplatesDone(ctx) {
2032
2075
  if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2033
2076
  }
2034
2077
  _listPromptsWill(ctx) {
2035
2078
  if (this.tracingEnabled) onGenericFlowWillStart("prompts/list", this.tracingOpts, ctx);
2036
2079
  }
2080
+ _listPromptsDidFilter(ctx) {
2081
+ if (this.tracingEnabled) onGenericFlowStage("filterByAuthorities", ctx);
2082
+ }
2037
2083
  _listPromptsDone(ctx) {
2038
2084
  if (this.tracingEnabled) onGenericFlowDidFinalize(ctx);
2039
2085
  }
@@ -2347,6 +2393,12 @@ __decorateClass([
2347
2393
  __decorateClass([
2348
2394
  ToolHook.Will("checkToolAuthorization", { priority: -1e3 })
2349
2395
  ], ObservabilityPlugin.prototype, "_toolWillCheckAuth", 1);
2396
+ __decorateClass([
2397
+ ToolHook.Will("checkEntryAuthorities", { priority: -1e3 })
2398
+ ], ObservabilityPlugin.prototype, "_toolWillCheckAuthorities", 1);
2399
+ __decorateClass([
2400
+ ToolHook.Did("checkEntryAuthorities", { priority: 1e3 })
2401
+ ], ObservabilityPlugin.prototype, "_toolDidCheckAuthorities", 1);
2350
2402
  __decorateClass([
2351
2403
  ToolHook.Will("createToolCallContext", { priority: -1e3 })
2352
2404
  ], ObservabilityPlugin.prototype, "_toolWillCreateCtx", 1);
@@ -2374,6 +2426,12 @@ __decorateClass([
2374
2426
  __decorateClass([
2375
2427
  ResourceHook.Will("findResource", { priority: -1e3 })
2376
2428
  ], ObservabilityPlugin.prototype, "_resourceWillFind", 1);
2429
+ __decorateClass([
2430
+ ResourceHook.Will("checkEntryAuthorities", { priority: -1e3 })
2431
+ ], ObservabilityPlugin.prototype, "_resourceWillCheckAuthorities", 1);
2432
+ __decorateClass([
2433
+ ResourceHook.Did("checkEntryAuthorities", { priority: 1e3 })
2434
+ ], ObservabilityPlugin.prototype, "_resourceDidCheckAuthorities", 1);
2377
2435
  __decorateClass([
2378
2436
  ResourceHook.Will("execute", { priority: -1e3 })
2379
2437
  ], ObservabilityPlugin.prototype, "_resourceWillExecute", 1);
@@ -2389,6 +2447,12 @@ __decorateClass([
2389
2447
  __decorateClass([
2390
2448
  PromptHook.Will("findPrompt", { priority: -1e3 })
2391
2449
  ], ObservabilityPlugin.prototype, "_promptWillFind", 1);
2450
+ __decorateClass([
2451
+ PromptHook.Will("checkEntryAuthorities", { priority: -1e3 })
2452
+ ], ObservabilityPlugin.prototype, "_promptWillCheckAuthorities", 1);
2453
+ __decorateClass([
2454
+ PromptHook.Did("checkEntryAuthorities", { priority: 1e3 })
2455
+ ], ObservabilityPlugin.prototype, "_promptDidCheckAuthorities", 1);
2392
2456
  __decorateClass([
2393
2457
  PromptHook.Will("execute", { priority: -1e3 })
2394
2458
  ], ObservabilityPlugin.prototype, "_promptWillExecute", 1);
@@ -2404,6 +2468,12 @@ __decorateClass([
2404
2468
  __decorateClass([
2405
2469
  AgentCallHook.Will("findAgent", { priority: -1e3 })
2406
2470
  ], ObservabilityPlugin.prototype, "_agentWillFind", 1);
2471
+ __decorateClass([
2472
+ AgentCallHook.Will("checkEntryAuthorities", { priority: -1e3 })
2473
+ ], ObservabilityPlugin.prototype, "_agentWillCheckAuthorities", 1);
2474
+ __decorateClass([
2475
+ AgentCallHook.Did("checkEntryAuthorities", { priority: 1e3 })
2476
+ ], ObservabilityPlugin.prototype, "_agentDidCheckAuthorities", 1);
2407
2477
  __decorateClass([
2408
2478
  AgentCallHook.Will("execute", { priority: -1e3 })
2409
2479
  ], ObservabilityPlugin.prototype, "_agentWillExecute", 1);
@@ -2419,24 +2489,36 @@ __decorateClass([
2419
2489
  __decorateClass([
2420
2490
  ListToolsHook.Did("findTools", { priority: 1e3 })
2421
2491
  ], ObservabilityPlugin.prototype, "_listToolsDidFind", 1);
2492
+ __decorateClass([
2493
+ ListToolsHook.Did("filterByAuthorities", { priority: 1e3 })
2494
+ ], ObservabilityPlugin.prototype, "_listToolsDidFilter", 1);
2422
2495
  __decorateClass([
2423
2496
  ListToolsHook.Did("parseTools", { priority: 1e3 })
2424
2497
  ], ObservabilityPlugin.prototype, "_listToolsDone", 1);
2425
2498
  __decorateClass([
2426
2499
  ListResourcesHook.Will("parseInput", { priority: -1e3 })
2427
2500
  ], ObservabilityPlugin.prototype, "_listResourcesWill", 1);
2501
+ __decorateClass([
2502
+ ListResourcesHook.Did("filterByAuthorities", { priority: 1e3 })
2503
+ ], ObservabilityPlugin.prototype, "_listResourcesDidFilter", 1);
2428
2504
  __decorateClass([
2429
2505
  ListResourcesHook.Did("parseResources", { priority: 1e3 })
2430
2506
  ], ObservabilityPlugin.prototype, "_listResourcesDone", 1);
2431
2507
  __decorateClass([
2432
2508
  ListResourceTemplatesHook.Will("parseInput", { priority: -1e3 })
2433
2509
  ], ObservabilityPlugin.prototype, "_listTemplatesWill", 1);
2510
+ __decorateClass([
2511
+ ListResourceTemplatesHook.Did("filterByAuthorities", { priority: 1e3 })
2512
+ ], ObservabilityPlugin.prototype, "_listTemplatesDidFilter", 1);
2434
2513
  __decorateClass([
2435
2514
  ListResourceTemplatesHook.Did("parseTemplates", { priority: 1e3 })
2436
2515
  ], ObservabilityPlugin.prototype, "_listTemplatesDone", 1);
2437
2516
  __decorateClass([
2438
2517
  ListPromptsHook.Will("parseInput", { priority: -1e3 })
2439
2518
  ], ObservabilityPlugin.prototype, "_listPromptsWill", 1);
2519
+ __decorateClass([
2520
+ ListPromptsHook.Did("filterByAuthorities", { priority: 1e3 })
2521
+ ], ObservabilityPlugin.prototype, "_listPromptsDidFilter", 1);
2440
2522
  __decorateClass([
2441
2523
  ListPromptsHook.Did("parsePrompts", { priority: 1e3 })
2442
2524
  ], ObservabilityPlugin.prototype, "_listPromptsDone", 1);