mcp: typed tool handler adds zero structuredContent to an IsError result
Los mantenedores suelen responder en 1 día
Ya se ha fusionado un pull request relacionado.
- #1397 de @Ilyuha888 — fusionado
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 74/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- go
- Área
- backend-api-design
Línea de trabajo
Empieza en mcp/server.go, en toolForErr, donde se convierten y validan las salidas tipadas de los handlers; compara su tratamiento de las solicitudes de entrada y los resultados de error. El informe incluye un reproductor y afirma que una prueba ya pasa con el cambio propuesto. Confirma que los resultados IsError omiten el contenido estructurado generado y se saltan la validación de salida, mientras que StructuredContent proporcionado explícitamente sigue estando disponible.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
What did you do?
A typed tool handler reports a tool execution error the way the spec describes: it returns a result with IsError: true and text content, the zero Out, and a nil error. (Returning a Go error avoids the problem below, but then the SDK discards the handler's own result.)
type Out struct {
Items []string `json:"items"`
}
func search(ctx context.Context, _ *mcp.CallToolRequest, in In) (*mcp.CallToolResult, Out, error) {
return &mcp.CallToolResult{
IsError: true,
Content: []mcp.Content{&mcp.TextContent{Text: "no shop with this id"}},
}, Out{}, nil
}
What did you see?
The result carries a zero structuredContent next to the error:
{"content":[{"type":"text","text":"no shop with this id"}],"structuredContent":{"items":null},"isError":true}
A client that reads structuredContent first gets {"items":null}, which looks like an empty successful result.
When the output schema rejects the zero value, the call fails with a protocol error instead of returning the tool error. With an OutputSchema whose required status property has "enum": ["ok", "partial"]:
calling "tools/call": validating tool output: validating root: validating /properties/status: enum: does not equal any of: [ok partial]
What did you expect to see?
The error result as the handler built it: no structuredContent and no output validation, as in the spec's tool execution error example. The err != nil path already behaves this way.
Versions
go-sdk v1.8.0; same code on main at 452ac5a. Go 1.27.1, darwin/arm64.
Possible fix
In toolForErr (mcp/server.go), skip the output step for an error result, the same way it is skipped when the handler asks for input:
if asksForInput(res) || res.IsError {
outval = nil
}
A handler that wants structured data on an error result can still set res.StructuredContent itself. I have this change with a test (go test ./... passes) and can send a PR if the approach works for you.
Full reproduction
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/google/jsonschema-go/jsonschema"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type In struct {
Query string `json:"query"`
}
type Out struct {
Items []string `json:"items"`
}
type Report struct {
Status string `json:"status"`
}
func failing[O any](ctx context.Context, _ *mcp.CallToolRequest, _ In) (*mcp.CallToolResult, O, error) {
var zero O
return &mcp.CallToolResult{
IsError: true,
Content: []mcp.Content{&mcp.TextContent{Text: "no shop with this id"}},
}, zero, nil
}
func main() {
ctx := context.Background()
server := mcp.NewServer(&mcp.Implementation{Name: "repro", Version: "v0"}, nil)
mcp.AddTool(server, &mcp.Tool{Name: "search"}, failing[Out])
mcp.AddTool(server, &mcp.Tool{
Name: "report",
OutputSchema: &jsonschema.Schema{
Type: "object",
Required: []string{"status"},
Properties: map[string]*jsonschema.Schema{"status": {Type: "string", Enum: []any{"ok", "partial"}}},
},
}, failing[Report])
ct, st := mcp.NewInMemoryTransports()
if _, err := server.Connect(ctx, st, nil); err != nil {
panic(err)
}
cs, err := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0"}, nil).Connect(ctx, ct, nil)
if err != nil {
panic(err)
}
defer cs.Close()
for _, name := range []string{"search", "report"} {
res, err := cs.CallTool(ctx, &mcp.CallToolParams{Name: name, Arguments: map[string]any{"query": "x"}})
if err != nil {
fmt.Printf("%s: error: %v\n", name, err)
continue
}
b, _ := json.Marshal(res)
fmt.Printf("%s: %s\n", name, b)
}
}
Output on v1.8.0 (_meta and resultType trimmed from the first line):
search: {"content":[{"type":"text","text":"no shop with this id"}],"structuredContent":{"items":null},"isError":true}
report: error: calling "tools/call": validating tool output: validating root: validating /properties/status: enum: does not equal any of: [ok partial]
- Lenguaje dominante
- Go
- Estrellas
- 5.2k
- Forks
- 583
- Merge medio
- 1 d 12 h
- PR fusionados (30 d)
- 52
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de modelcontextprotocol/go-sdk
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
modelcontextprotocol/go-sdk#1372 ·
Los mantenedores suelen responder en 1 día
-
Session-lifecycle bookkeeping logs at info, spamming multiple log lines per request on stateless streamable HTTPPosiblemente ocupada @anneheartrecord la tomó hace 47 días. AbiertoP3
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
modelcontextprotocol/go-sdk#1204 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Expose generic `SendNotification` on `ServerSession` for custom protocol extensionsPosiblemente ocupada @ajuijas la tomó hace 213 días. Abiertoneeds investigation
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
modelcontextprotocol/go-sdk#745 · 13 comentarios · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
modelcontextprotocol/go-sdk#1394 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
mcp: rejected request IDs receive no JSON-RPC error envelopePosiblemente ocupada @skosovsky la tomó hace 2 días. Abierto
Dificultad 4/5 1-2 días Aptitud para principiantes 68/100
modelcontextprotocol/go-sdk#1391 ·
Los mantenedores suelen responder en 1 día
Todos los issues de modelcontextprotocol/go-sdk
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
praetorian-inc/augustus#334 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
TestTOMLBigFileParsesInLinearTime: a 1s wall-clock bound on a 3 MB parse fails under load (1.27s)Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 80/100
peasant-labs/village#293 ·
Los mantenedores suelen responder en 1 día