ExMCP.Telemetry (ex_mcp v0.9.2)
View SourceTelemetry integration for ExMCP.
This module defines telemetry events emitted by ExMCP components and provides convenience functions for attaching handlers.
Events
All events follow the naming convention [:ex_mcp, :component, :action, :status].
Client Events
Connection
[:ex_mcp, :client, :connected]- Client connection established- Metadata:
%{transport: module()}
- Metadata:
[:ex_mcp, :client, :disconnected]- Client disconnected- Metadata:
%{}
- Metadata:
Request Lifecycle
[:ex_mcp, :client, :request, :sent]- Request sent to server- Metadata:
%{method: String.t()}
- Metadata:
[:ex_mcp, :client, :request, :completed]- Response matched to pending requestMetadata:
%{method: String.t() | nil, request_id: integer()}
Receiver
[:ex_mcp, :client, :receiver, :started]- Receiver task startedMetadata:
%{mode: :push | :pull}
[:ex_mcp, :client, :receiver, :message]- Message received in receive loop- Metadata:
%{}
- Metadata:
State & Progress (via span/3)
[:ex_mcp, :request, :start]- Request processing starts- Measurements:
%{system_time: integer()} - Metadata:
%{request_id: String.t(), method: String.t(), server: atom()}
- Measurements:
[:ex_mcp, :request, :stop]- Request processing completes- Measurements:
%{duration: integer()} Metadata:
%{request_id: String.t(), method: String.t(), server: atom(), status: :ok | :error}
- Measurements:
[:ex_mcp, :request, :exception]- Request processing fails- Measurements:
%{duration: integer()} - Metadata:
%{request_id: String.t(), method: String.t(), server: atom(), kind: atom(), error: term(), stacktrace: list()}
- Measurements:
Server Events
Request Processing
[:ex_mcp, :server, :request, :received]- Transport message arrives (Legacy server)- Metadata:
%{method: String.t()}
- Metadata:
[:ex_mcp, :server, :request, :completed]- Response sent back (Legacy server)- Metadata:
%{method: String.t()}
- Metadata:
[:ex_mcp, :server, :request, :processed]- MessageProcessor.process/2 completes- Metadata:
%{method: String.t(), has_response: boolean()}
- Metadata:
[:ex_mcp, :server, :initialize, :completed]- Server initialization completes- Metadata:
%{server_name: String.t()}
- Metadata:
Tool Execution
[:ex_mcp, :server, :tool, :called]- Tool call dispatchedMetadata:
%{tool_name: String.t(), mode: :direct | :genserver | :handler}
[:ex_mcp, :tool, :start]- Tool execution starts (viaspan/3)- Measurements:
%{system_time: integer()} - Metadata:
%{tool_name: String.t(), request_id: String.t()}
- Measurements:
[:ex_mcp, :tool, :stop]- Tool execution completes (viaspan/3)- Measurements:
%{duration: integer()} Metadata:
%{tool_name: String.t(), request_id: String.t(), status: :ok | :error}
- Measurements:
Resource Operations
[:ex_mcp, :server, :resource, :read]- Resource read dispatchedMetadata:
%{uri: String.t(), mode: :direct | :genserver | :handler}
[:ex_mcp, :resource, :read, :start]- Resource read starts (viaspan/3)- Measurements:
%{system_time: integer()} - Metadata:
%{uri: String.t(), request_id: String.t()}
- Measurements:
[:ex_mcp, :resource, :read, :stop]- Resource read completes (viaspan/3)Measurements:
%{duration: integer(), bytes: integer() | nil}Metadata:
%{uri: String.t(), request_id: String.t(), status: :ok | :error}
Prompt Rendering
[:ex_mcp, :server, :prompt, :rendered]- Prompt get dispatchedMetadata:
%{name: String.t(), mode: :direct | :genserver | :handler}
HTTP Transport
[:ex_mcp, :server, :http, :request]- HTTP request received- Metadata:
%{method: String.t(), path: String.t()}
- Metadata:
[:ex_mcp, :server, :http, :response]- HTTP response sent- Metadata:
%{status: integer()}
- Metadata:
Transport Events (via span/3)
[:ex_mcp, :connection, :established]- Connection established- Measurements:
%{system_time: integer()} - Metadata:
%{transport: atom(), server: atom()}
- Measurements:
[:ex_mcp, :connection, :lost]- Connection lost- Measurements:
%{system_time: integer(), uptime: integer()} - Metadata:
%{transport: atom(), server: atom(), reason: term()}
- Measurements:
Authorization Events
Authorization events are emitted by the OAuth 2.1 subsystem:
[:ex_mcp, :authorization, :flow, :start | :stop]- OAuth flow lifecycle[:ex_mcp, :authorization, :discovery, :start | :stop]- Metadata discovery[:ex_mcp, :authorization, :token, :start | :stop]- Token exchange[:ex_mcp, :authorization, :authorize, :start | :stop]- Authorization request
ACP Events
Agent Communication Protocol events:
[:ex_mcp, :acp, :session, :start | :stop]- ACP session lifecycle[:ex_mcp, :acp, :prompt, :start | :stop]- ACP prompt processing[:ex_mcp, :acp, :transport, :start | :stop]- ACP transport operations
Usage
# Attach a simple logger
ExMCP.Telemetry.attach_default_logger()
# Attach custom handlers
:telemetry.attach(
"my-handler",
[:ex_mcp, :server, :tool, :called],
&MyApp.handle_event/4,
nil
)
Summary
Functions
Attaches a default logger that logs all ExMCP events.
Detaches the default logger.
Executes a function and emits telemetry events.
Functions
Attaches a default logger that logs all ExMCP events.
This is useful for debugging and development.
Detaches the default logger.
Executes a function and emits telemetry events.
This is a convenience function for wrapping operations with telemetry.
Examples
ExMCP.Telemetry.span([:ex_mcp, :custom, :operation], %{id: "123"}, fn ->
# Do some work
{:ok, result}
end)