Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

mcp: typed tool handler adds zero structuredContent to an IsError result

Aperta Adatta ai principianti
#1,387 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
74/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
go

Direzione di ricerca

Inizia in mcp/server.go, in toolForErr, dove gli output tipizzati degli handler vengono convertiti e convalidati; confronta il trattamento delle richieste di input e dei risultati di errore. Il report include un riproduttore e afferma che un test passa già con la modifica proposta. Conferma che i risultati IsError omettono il contenuto strutturato generato e saltano la convalida dell’output, mentre StructuredContent fornito esplicitamente resta disponibile.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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]
Lingua principale
Go
Stelle
5.2k
Fork
583
Merge medio
1g 11h
PR unite (30g)
47

Preparare l'ambiente

Apri in Codespaces

Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di modelcontextprotocol/go-sdk

Tutte le issue di modelcontextprotocol/go-sdk

Issue simili

Altre issue su Go

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.