Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

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

Đã đóng Phù hợp với người mới
#1,387 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Một pull request liên quan đã được merge.

  • #1397 của @Ilyuha888 — đã merge

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
74/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
go
Lĩnh vực
backend-api-design

Hướng nghiên cứu

Bắt đầu tại mcp/server.go, ở toolForErr, nơi đầu ra có kiểu của handler được chuyển đổi và xác thực; so sánh cách xử lý các yêu cầu đầu vào và kết quả lỗi. Báo cáo có kèm một đoạn mã tái hiện lỗi và cho biết một bài kiểm thử đã chạy thành công với thay đổi được đề xuất. Xác nhận rằng các kết quả IsError bỏ qua nội dung có cấu trúc được tạo ra và bỏ qua bước xác thực đầu ra, trong khi StructuredContent được cung cấp tường minh vẫn khả dụng.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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]
Ngôn ngữ chính
Go
Star
5.3k
Fork
606
Merge trung bình
1 ngày 8 giờ
Pull request đã merge (30 ngày)
70

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của modelcontextprotocol/go-sdk

Tất cả issue của modelcontextprotocol/go-sdk

Issue tương tự

Thêm issue về Go

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.