mcp: typed tool handler adds zero structuredContent to an IsError result
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
- Ambito
- backend-api-design
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
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di modelcontextprotocol/go-sdk
-
auth: resource metadata lookup accepts URLs from non-Bearer challengesForse già presa Una pull request collegata a questa issue è aperta o già unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
modelcontextprotocol/go-sdk#1379 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
modelcontextprotocol/go-sdk#1372 ·
I maintainer di solito rispondono entro 1 giorno
-
bug: a request sent before initialize is answered with JSON-RPC error code 0 instead of -32600Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
modelcontextprotocol/go-sdk#1367 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Session-lifecycle bookkeeping logs at info, spamming multiple log lines per request on stateless streamable HTTPForse già presa @anneheartrecord l’ha presa 46 giorni fa. ApertaP3
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
modelcontextprotocol/go-sdk#1204 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
Expose generic `SendNotification` on `ServerSession` for custom protocol extensionsForse già presa @ajuijas l’ha presa 211 giorni fa. Apertaneeds investigation
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
modelcontextprotocol/go-sdk#745 · 13 commenti · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di modelcontextprotocol/go-sdk
Issue simili
-
unbounded value for n in `/v1/logs` can panic/OOMForse già presa Una pull request collegata a questa issue è aperta o già unita. Apertasmall item
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
canonical/pebble#1127 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
[schema-coverage] elasticstack_elasticsearch_synonym_set (data source)Forse già presa @github-actions l’ha presa oggi. Apertaacceptance-tests phase-coding schema-coverage testing triaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 81/100
elastic/terraform-provider-elasticstack#5211 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 89/100
open-policy-agent/opa#9366 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
defect
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
nats-io/nats-server#8752 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement needs-acceptance wg/router-models-inference-runtime
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
vllm-project/semantic-router#5015 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno