Documentation
¶
Overview ¶
Package mcpreplay records the requests an MCP server built on github.com/modelcontextprotocol/go-sdk handles as LogRocket sessions.
Call Instrument on an *mcp.Server to record every request it handles, and Recorder.Shutdown before the process exits to upload the final batch. On HTTP transports, wrap the handler with HTTPMiddleware to also record the server URL and client peer address.
Index ¶
- Constants
- func ClampString(value string, maxLength int) string
- func HTTPMiddleware(next http.Handler) http.Handler
- func MakeIngestPath(appID string) string
- func NewMiddleware(recorder *Recorder, opts Options) mcp.Middleware
- func ParseAppID(apiKey string) string
- func TruncateValue(value any, maxLength int) any
- type EventBatch
- type Options
- type RecordedClient
- type RecordedResult
- type RecordedUser
- type Recorder
- type RequestEvent
- type SDKInfo
Constants ¶
const ( SDKName = "logrocket-mcp-replay-go" SDKVersion = "0.1.0" )
SDKName and SDKVersion are reported to LogRocket with every batch. SDKVersion must match the module's release tag (without the leading v).
const TruncatedMarker = "[truncated by " + SDKName + "]"
TruncatedMarker is appended to captured values that exceeded MaxValueLength.
Variables ¶
This section is empty.
Functions ¶
func ClampString ¶
ClampString returns value cut to at most maxLength bytes.
func HTTPMiddleware ¶
HTTPMiddleware wraps the HTTP handler serving your MCP server (e.g., an *mcp.StreamableHTTPHandler) so recorded requests include the server URL and the client's peer address. Without it, the client IP is available only from proxy headers (X-Forwarded-For and similar) and the server URL is omitted.
func MakeIngestPath ¶
MakeIngestPath returns the ingest endpoint path for an app ID ("org/app").
func NewMiddleware ¶
func NewMiddleware(recorder *Recorder, opts Options) mcp.Middleware
NewMiddleware returns receiving middleware that records every request to the given recorder. Instrument installs it for you; use it directly with server.AddReceivingMiddleware to control ordering relative to your own middleware.
func ParseAppID ¶
ParseAppID extracts "org/app" from a LogRocket API key, or returns "" if the key is not in a recognized format.
func TruncateValue ¶
TruncateValue returns value unchanged if its JSON serialization fits in maxLength bytes, and a truncated string representation otherwise.
Types ¶
type EventBatch ¶
type EventBatch struct {
AppID string `json:"appID"`
SDK SDKInfo `json:"sdk"`
Release string `json:"release,omitempty"`
Events []*RequestEvent `json:"events"`
}
EventBatch is the payload uploaded to the LogRocket ingest server.
type Options ¶
type Options struct {
// APIKey is a LogRocket API key ("pat:org:app:secret", or the legacy
// "org:app:secret" format). Authenticates with the ingest server and
// identifies the app recorded to.
APIKey string
// ServerURL is the ingest server origin. Defaults to the production LogRocket ingest server.
ServerURL string
// Release is your MCP server's release identifier (e.g., a version or git
// SHA). Shown on sessions and used by LogRocket's release filtering and comparison.
Release string
// DisableParamCapture skips capturing request params.
DisableParamCapture bool
// DisableResultCapture skips capturing request results.
DisableResultCapture bool
// DisableHeaderCapture skips capturing HTTP request headers. When
// captured, sensitive values are always redacted.
DisableHeaderCapture bool
// RedactHeaders lists header names (case-insensitive) to redact in
// addition to the built-in denylist.
RedactHeaders []string
// MaxValueLength is the maximum JSON-serialized length for captured
// params/results. Defaults to 100000.
MaxValueLength int
// SanitizeEvent transforms or drops (by returning nil) an event before it is buffered.
SanitizeEvent func(event *RequestEvent) *RequestEvent
// MaxBatchSize flushes the buffer whenever it reaches this many events. Defaults to 25.
MaxBatchSize int
// FlushInterval flushes the buffer on this interval. Defaults to 5s.
FlushInterval time.Duration
// UploadTimeout aborts an ingest upload after this long. Defaults to 10s.
UploadTimeout time.Duration
// HTTPClient is used for ingest uploads. Defaults to http.DefaultClient.
HTTPClient *http.Client
// OnError is called with upload/serialization errors. These never
// propagate to the host server.
OnError func(err error)
// Recorder shares one recorder (and its upload batching) across
// Instrument calls. Used by Instrument only.
Recorder *Recorder
// GetUser resolves the LogRocket user for a request. req.GetExtra()
// carries the HTTP headers and validated bearer token info on HTTP
// transports (nil on stdio). Used by Instrument only.
GetUser func(ctx context.Context, req mcp.Request) *RecordedUser
}
Options configure recording. The zero value of every field except APIKey selects the default.
type RecordedClient ¶
type RecordedClient struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
}
RecordedClient identifies the MCP client application that sent a request.
type RecordedResult ¶
type RecordedResult struct {
// IsError is true when the handler returned an isError result (e.g., a failed tool call).
IsError bool `json:"isError,omitempty"`
// Value is the handler's result, truncated to MaxValueLength.
Value any `json:"value,omitempty"`
}
RecordedResult is the outcome of a request that returned a result.
type RecordedUser ¶
type RecordedUser struct {
ID string `json:"id"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
Anonymous bool `json:"anonymous,omitempty"`
Traits map[string]string `json:"traits,omitempty"`
}
RecordedUser identifies the LogRocket user a request belongs to.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder buffers events and uploads them from a background goroutine so the host server's request handling is never blocked.
func Instrument ¶
Instrument records every request the server handles (tool calls, resource reads, prompt gets, listings, etc.) to LogRocket, including handlers registered afterwards. Instrumenting the same server twice is a no-op.
The returned Recorder is the one events are buffered in; call its Shutdown before the process exits so the final batch is uploaded.
func NewRecorder ¶
NewRecorder creates a recorder. Recording is disabled (and OnError called) when an app ID cannot be parsed from opts.APIKey.
func (*Recorder) AppID ¶
AppID is the "org/app" parsed from the API key, or "" if recording is disabled.
func (*Recorder) Enqueue ¶
func (r *Recorder) Enqueue(event *RequestEvent)
Enqueue buffers an event, flushing when the buffer reaches MaxBatchSize or scheduling a timer-based flush otherwise.
func (*Recorder) Flush ¶
func (r *Recorder) Flush()
Flush queues buffered events for upload in the background and returns immediately. Use Shutdown to wait for uploads to finish.
func (*Recorder) InstanceID ¶
InstanceID is the random ID stamped on every event this recorder buffers.
type RequestEvent ¶
type RequestEvent struct {
Type string `json:"type"`
// StartTime is epoch milliseconds when handling of the request started.
StartTime int64 `json:"startTime"`
DurationMs int64 `json:"durationMs"`
// Method is the JSON-RPC method (e.g., "tools/call", "resources/read", "initialize").
Method string `json:"method"`
// Target is the tool/prompt name or resource URI the request addressed, when applicable.
Target string `json:"target,omitempty"`
// RequestID is the JSON-RPC request ID. The Go SDK does not expose it to
// middleware, so it is left unset.
RequestID any `json:"requestID,omitempty"`
// Params holds the request params (minus _meta), truncated to MaxValueLength.
Params any `json:"params,omitempty"`
Result *RecordedResult `json:"result,omitempty"`
// ErrorMessage is set when the handler returned an error rather than a result.
ErrorMessage string `json:"errorMessage,omitempty"`
// ErrorName is the error's Go type (e.g., "jsonrpc2.WireError"), used for issue grouping.
ErrorName string `json:"errorName,omitempty"`
// ErrorCode is the JSON-RPC error code carried by the returned error
// (e.g., -32602 invalid params). Distinguishes client mistakes from server bugs.
ErrorCode int64 `json:"errorCode,omitempty"`
User *RecordedUser `json:"user,omitempty"`
Client *RecordedClient `json:"client,omitempty"`
// UserAgent is the raw User-Agent header from the MCP client's HTTP request.
UserAgent string `json:"userAgent,omitempty"`
// Headers are the HTTP request headers, with sensitive values redacted.
Headers map[string]string `json:"headers,omitempty"`
// ServerURL is the URL of the MCP server endpoint that handled the request,
// without query string. Requires HTTPMiddleware.
ServerURL string `json:"serverUrl,omitempty"`
// IPAddress is the client IP from standard proxy headers (or the peer
// address when HTTPMiddleware is used), used for geo enrichment.
IPAddress string `json:"ipAddress,omitempty"`
ProtocolVersion string `json:"protocolVersion,omitempty"`
Traceparent string `json:"traceparent,omitempty"`
Tracestate string `json:"tracestate,omitempty"`
Baggage string `json:"baggage,omitempty"`
// OAuthClientID is the OAuth client ID from the validated access token, when available.
OAuthClientID string `json:"oauthClientID,omitempty"`
// AuthHash is the SHA-256 hex digest of the bearer token, when the request
// was authenticated. Used server-side to group requests into per-user
// sessions when GetUser is not configured. The token itself is never sent.
AuthHash string `json:"authHash,omitempty"`
// InstanceID is a random ID generated once per recorder (i.e., per server
// process). Last-resort sessionization key for transports with no HTTP
// context where one process serves one user (e.g., stdio).
InstanceID string `json:"instanceID,omitempty"`
Seq int64 `json:"seq"`
}
RequestEvent is one recorded request. Field names match the LogRocket ingest schema.