refactor: remove legacy MCPGODEBUG compatibility for new protocol release (#1237)
This commit is contained in:
parent
830f0b76e7
commit
3f3b699b2b
5 changed files with 41 additions and 42 deletions
|
|
@ -44,6 +44,23 @@ Options listed below were added and will be removed in the 1.9.0 version of the
|
|||
soon as its context is cancelled and cannot be delayed by a slow or
|
||||
unresponsive peer. See issue #1150.
|
||||
|
||||
Options below were removed, according to plan:
|
||||
|
||||
- `seterroroverwrite`. `SetError` now always preserves existing `Content`.
|
||||
|
||||
- `enableoriginverification`. A nil
|
||||
`StreamableHTTPOptions.CrossOriginProtection` now always means no
|
||||
cross-origin protection. Wrap the handler with cross-origin protection
|
||||
middleware instead.
|
||||
|
||||
- `disablecontenttypecheck`. Content-Type validation on HTTP POST requests can
|
||||
no longer be disabled.
|
||||
|
||||
- `disablelocalhostprotection`, whose removal had been postponed to this
|
||||
release. Set the `DisableLocalhostProtection` field in
|
||||
`StreamableHTTPOptions` or `SSEOptions` to opt out of DNS rebinding
|
||||
protection.
|
||||
|
||||
### 1.7.0
|
||||
|
||||
Options listed below were added and will be removed in the 1.9.0 version of the SDK.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,23 @@ Options listed below were added and will be removed in the 1.9.0 version of the
|
|||
soon as its context is cancelled and cannot be delayed by a slow or
|
||||
unresponsive peer. See issue #1150.
|
||||
|
||||
Options below were removed, according to plan:
|
||||
|
||||
- `seterroroverwrite`. `SetError` now always preserves existing `Content`.
|
||||
|
||||
- `enableoriginverification`. A nil
|
||||
`StreamableHTTPOptions.CrossOriginProtection` now always means no
|
||||
cross-origin protection. Wrap the handler with cross-origin protection
|
||||
middleware instead.
|
||||
|
||||
- `disablecontenttypecheck`. Content-Type validation on HTTP POST requests can
|
||||
no longer be disabled.
|
||||
|
||||
- `disablelocalhostprotection`, whose removal had been postponed to this
|
||||
release. Set the `DisableLocalhostProtection` field in
|
||||
`StreamableHTTPOptions` or `SSEOptions` to opt out of DNS rebinding
|
||||
protection.
|
||||
|
||||
### 1.7.0
|
||||
|
||||
Options listed below were added and will be removed in the 1.9.0 version of the SDK.
|
||||
|
|
|
|||
|
|
@ -329,23 +329,13 @@ type CallToolResult struct {
|
|||
err error
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if len(r.Content) == 0 || seterroroverwrite == "1" {
|
||||
if len(r.Content) == 0 {
|
||||
r.Content = []Content{&TextContent{Text: err.Error()}}
|
||||
}
|
||||
r.IsError = true
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ func (t *SSEServerTransport) SupportsProtocolVersion(version string) bool {
|
|||
func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// DNS rebinding protection: auto-enabled for localhost servers.
|
||||
// See: https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices#local-mcp-server-compromise
|
||||
if !h.opts.DisableLocalhostProtection && disablelocalhostprotection != "1" {
|
||||
if !h.opts.DisableLocalhostProtection {
|
||||
if localAddr, ok := req.Context().Value(http.LocalAddrContextKey).(net.Addr); ok && localAddr != nil {
|
||||
if util.IsLoopback(localAddr.String()) && !util.IsLoopback(req.Host) {
|
||||
http.Error(w, fmt.Sprintf("Forbidden: invalid Host header %q", req.Host), http.StatusForbidden)
|
||||
|
|
@ -235,7 +235,7 @@ func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
// Validate 'Content-Type' header.
|
||||
if disablecontenttypecheck != "1" && req.Method == http.MethodPost {
|
||||
if req.Method == http.MethodPost {
|
||||
mediaType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type"))
|
||||
if err != nil || mediaType != "application/json" {
|
||||
http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
|
||||
|
|
|
|||
|
|
@ -184,8 +184,7 @@ type StreamableHTTPOptions struct {
|
|||
// CrossOriginProtection allows to customize cross-origin protection.
|
||||
// The deny handler set in the CrossOriginProtection through SetDenyHandler
|
||||
// is ignored.
|
||||
// If nil, no cross-origin protection is applied. Use the `enableoriginverification`
|
||||
// MCPGODEBUG compatibility parameter to enable the default protection until v1.8.0.
|
||||
// If nil, no cross-origin protection is applied.
|
||||
//
|
||||
// Deprecated: wrap the handler with cross-origin protection middleware
|
||||
// instead. For example:
|
||||
|
|
@ -240,10 +239,6 @@ func NewStreamableHTTPHandler(getServer func(*http.Request) *Server, opts *Strea
|
|||
|
||||
h.opts.Logger = ensureLogger(h.opts.Logger)
|
||||
|
||||
if h.opts.CrossOriginProtection == nil && enableoriginverification == "1" {
|
||||
h.opts.CrossOriginProtection = &http.CrossOriginProtection{}
|
||||
}
|
||||
|
||||
if h.opts.MaxRequestBodyBytes == 0 {
|
||||
h.opts.MaxRequestBodyBytes = DefaultMaxRequestBodyBytes
|
||||
}
|
||||
|
|
@ -274,20 +269,6 @@ func (h *StreamableHTTPHandler) closeAll() {
|
|||
}
|
||||
}
|
||||
|
||||
// disablelocalhostprotection is a compatibility parameter that allows to disable
|
||||
// DNS rebinding protection, which was added in the 1.4.0 version of the SDK.
|
||||
// See the documentation for the mcpgodebug package for instructions how to enable it.
|
||||
// The option will be removed in the 1.8.0 version of the SDK.
|
||||
var disablelocalhostprotection = mcpgodebug.Value("disablelocalhostprotection")
|
||||
|
||||
// enableoriginverification is a compatibility parameter that restores the
|
||||
// default cross-origin protection behavior from v1.4.1-v1.5.0. When set to
|
||||
// "1", a zero-value CrossOriginProtection will be applied if none is
|
||||
// explicitly provided in StreamableHTTPOptions.
|
||||
// See the documentation for the mcpgodebug package for instructions how to enable it.
|
||||
// The option will be removed in the 1.8.0 version of the SDK.
|
||||
var enableoriginverification = mcpgodebug.Value("enableoriginverification")
|
||||
|
||||
// allowsessionsinstateless is a compatibility parameter that restores the old
|
||||
// behavior of reading and using Mcp-Session-Id headers in stateless mode. When
|
||||
// set to "1", stateless servers will read the session ID from the request
|
||||
|
|
@ -308,12 +289,6 @@ var allowsessionsinstateless = mcpgodebug.Value("allowsessionsinstateless")
|
|||
// permanently fails the connection.
|
||||
var noprotocolerrorbody = mcpgodebug.Value("noprotocolerrorbody")
|
||||
|
||||
// disablecontenttypecheck is a compatibility parameter that allows to disable
|
||||
// Content-Type validation on POST requests.
|
||||
// See the documentation for the mcpgodebug package for instructions how to enable it.
|
||||
// The option will be removed in the 1.8.0 version of the SDK.
|
||||
var disablecontenttypecheck = mcpgodebug.Value("disablecontenttypecheck")
|
||||
|
||||
// plaintextstatefulrejection is a compatibility parameter that restores the
|
||||
// previous behavior of a stateful [StreamableHTTPHandler] when it receives a
|
||||
// request carrying SEP-2575 per-request metadata (i.e. an
|
||||
|
|
@ -341,7 +316,7 @@ func writeJSONRPCError(w http.ResponseWriter, status int, id jsonrpc.ID, jerr *j
|
|||
func (h *StreamableHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// DNS rebinding protection: auto-enabled for localhost servers.
|
||||
// See: https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices#local-mcp-server-compromise
|
||||
if !h.opts.DisableLocalhostProtection && disablelocalhostprotection != "1" {
|
||||
if !h.opts.DisableLocalhostProtection {
|
||||
if localAddr, ok := req.Context().Value(http.LocalAddrContextKey).(net.Addr); ok && localAddr != nil {
|
||||
if util.IsLoopback(localAddr.String()) && !util.IsLoopback(req.Host) {
|
||||
http.Error(w, fmt.Sprintf("Forbidden: invalid Host header %q", req.Host), http.StatusForbidden)
|
||||
|
|
@ -410,7 +385,7 @@ func (h *StreamableHTTPHandler) serveStateless(w http.ResponseWriter, req *http.
|
|||
return
|
||||
}
|
||||
|
||||
if disablecontenttypecheck != "1" && baseMediaType(req.Header.Get("Content-Type")) != "application/json" {
|
||||
if baseMediaType(req.Header.Get("Content-Type")) != "application/json" {
|
||||
http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
|
|
@ -644,7 +619,7 @@ func (h *StreamableHTTPHandler) serveStatefulDELETE(w http.ResponseWriter, req *
|
|||
// ID, a new session is created (this is the normal path for the first
|
||||
// initialize request).
|
||||
func (h *StreamableHTTPHandler) serveStatefulPOST(w http.ResponseWriter, req *http.Request) {
|
||||
if disablecontenttypecheck != "1" && baseMediaType(req.Header.Get("Content-Type")) != "application/json" {
|
||||
if baseMediaType(req.Header.Get("Content-Type")) != "application/json" {
|
||||
http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue