mcp: preserve existing Content in SetError (#864)

SetError now only populates the Content field when it has not already
been populated. This allows callers to provide a user-friendly message
while still recording the underlying error for middleware inspection
via GetError.
The len check (rather than nil check) ensures both nil and empty-slice
Content are treated as "not yet populated."
  Fixes #858
This commit is contained in:
Ravish Gupta 2026-04-03 11:15:24 -07:00 • committed by GitHub
commit 34a19dff46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -10,6 +10,7 @@ import (
"maps"
internaljson "github.com/modelcontextprotocol/go-sdk/internal/json"
"github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug"
)
// Optional annotations for the client. The client can use annotations to inform
@ -113,10 +114,25 @@ type CallToolResult struct {
err error
}
// SetError sets the error for the tool result and populates the Content field
// with the error text. It also sets IsError to true.
// seterroroverwrite is a compatibility parameter that restores the pre-1.6.0
// behavior of [CallToolResult.SetError], where Content was always overwritten
// with the error text. See the documentation for the mcpgodebug package for
// instructions on how to enable it.
// The option will be removed in the 1.8.0 version of the SDK.
var seterroroverwrite = mcpgodebug.Value("seterroroverwrite")
// SetError sets the error for the tool result and sets IsError to true.
// If Content has not already been populated, it is set to the error text.
// If Content has already been populated, it is left unchanged, allowing callers
// to provide a user-friendly message while still recording the underlying error
// for inspection via [GetError] in server middleware.
//
// To restore the previous behavior where Content was always overwritten,
// set MCPGODEBUG=seterroroverwrite=1.
func (r *CallToolResult) SetError(err error) {
r.Content = []Content{&TextContent{Text: err.Error()}}
if len(r.Content) == 0 || seterroroverwrite == "1" {
r.Content = []Content{&TextContent{Text: err.Error()}}
}
r.IsError = true
r.err = err
}