mcp: log out-of-band errors instead of dropping them#887
Open
ravyg wants to merge 2 commits intomodelcontextprotocol:mainfrom
Open
mcp: log out-of-band errors instead of dropping them#887ravyg wants to merge 2 commits intomodelcontextprotocol:mainfrom
ravyg wants to merge 2 commits intomodelcontextprotocol:mainfrom
Conversation
jba
requested changes
Apr 10, 2026
mcp/mcp_test.go
Outdated
| } | ||
|
|
||
| func (b *syncBuffer) Write(p []byte) (int, error) { | ||
| b.mu.Lock() |
Contributor
There was a problem hiding this comment.
slog already has a mutex around Write, so I don't think you need this lock, or this type.
Two errors that occur outside the request/response path were previously
unobservable:
- Keepalive ping failures (mcp/shared.go startKeepalive) silently
closed the session with no record of why.
- jsonrpc2 internal errors (mcp/transport.go connect) were printed
via the global log.Printf, bypassing the configured slog.Logger.
Both sites now report through the existing *slog.Logger that Server
and Client already guarantee non-nil via ensureLogger. No new public
API surface; the logger is threaded into the unexported helpers as a
parameter.
Includes a regression test (TestKeepAliveFailure_Logged) that asserts
the keepalive failure produces a log line on the configured logger,
and was verified to fail when the new log call is removed.
Per @jba's suggestion on modelcontextprotocol#865, this is the smaller no-new-API
alternative to the ErrorHandler callback proposal. modelcontextprotocol#865 remains open
pending community input on whether a structured callback is also
wanted.
Refs modelcontextprotocol#218
slog already serializes Write calls internally, so the mutex wrapper is unnecessary.
cf4b382 to
0586871
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two error sites in the MCP runtime were previously unobservable:
mcp/shared.gostartKeepalive— when a keepalive ping failed, the session was closed silently with no indication of why.mcp/transport.goconnect—jsonrpc2.OnInternalErrorprinted via the package-levellog.Printf, bypassing the*slog.Loggerconfigured onServerOptions/ClientOptions.Both sites now report through the existing
*slog.LoggerthatServerandClientalready guarantee non-nil viaensureLogger. The logger is threaded into the unexportedstartKeepaliveandconnecthelpers as a parameter — no new public API surface.Context
Per @jba's suggestion on #865:
This PR is that smaller alternative. It addresses the concrete observability gap in #218 without expanding
ServerOptions. PR #865 (theErrorHandlercallback proposal) remains open pending community input on whether a structured callback API is also wanted on top of logging.notifySessionsalready logs atWarnlevel on delivery errors and is intentionally left untouched.Test plan
TestKeepAliveFailure_Loggedasserts the keepalive failure produces a log line on the configured logger.logger.Error(...)call is removed (sanity check that it pins the behavior).go test ./mcp/... -count=1passes.go vet ./...clean.go build ./...clean.Refs #218