mcp: typed tool handlers lose wrapped JSON-RPC errors

オープン 初心者向け
#1,529 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

  • #1528 @ktsoator による — マージされずにクローズ

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
85/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
go

調査の方向性

MCPパッケージのtoolForErrと、ClientSession.CallToolが使用するJSON-RPCエラー処理から始めてください。*jsonrpc.Errorを直接扱う場合と、ラップされたエラーを扱う場合を比較してください。提供されているインメモリのクライアント/サーバー再現を実行し、その後errors.AsがJSON-RPCのコード、メッセージ、データを保持していること、そして結果が誤って実行エラーとしてマークされていないことを確認してください。ラップされたプロトコルエラーとラップされていないプロトコルエラーに対する、焦点を絞ったテストを追加または更新してください。

索引モデルが issue の本文から書いたものです。

説明

Checklist
  • I searched the existing issues, and this has not been reported before.
  • This is a real problem that I ran into myself, using the latest release of the SDK.
  • I ran into it in a production system, not in a toy example, a benchmark, or an automated or AI-driven scan of the code.
  • I (a human) examined the relevant SDK code, and wrote or reviewed every line of this report. It is not unreviewed AI output.
  • This report is brief and concise, and sticks to the facts needed to understand the problem.
What happened?

A typed tool handler returning a wrapped *jsonrpc.Error is treated as a tool execution error. ClientSession.CallTool returns a nil Go error and a result with IsError: true, so the JSON-RPC error code and data are lost. Returning the same protocol error directly works.

toolForErr checks err.(*jsonrpc.Error) instead of searching the error chain. The expected result is a JSON-RPC error with the underlying code, message, and data preserved when wrapped with %w.

How to reproduce

Run this program with github.com/modelcontextprotocol/go-sdk v1.8.0:


package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/modelcontextprotocol/go-sdk/jsonrpc"
	"github.com/modelcontextprotocol/go-sdk/mcp"
)

func main() {
	ctx := context.Background()
	s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "1"}, nil)
	mcp.AddTool(s, &mcp.Tool{Name: "demo"}, func(context.Context, *mcp.CallToolRequest, map[string]any) (*mcp.CallToolResult, any, error) {
		return nil, nil, fmt.Errorf("backend: %w", &jsonrpc.Error{
			Code:    jsonrpc.CodeInvalidParams,
			Message: "bad input",
		})
	})

	st, ct := mcp.NewInMemoryTransports()
	ss, err := s.Connect(ctx, st, nil)
	if err != nil {
		panic(err)
	}
	defer ss.Close()

	c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "1"}, nil)
	cs, err := c.Connect(ctx, ct, nil)
	if err != nil {
		panic(err)
	}
	defer cs.Close()

	result, err := cs.CallTool(ctx, &mcp.CallToolParams{Name: "demo"})
	var rpcErr *jsonrpc.Error
	fmt.Printf("protocolError=%v, err=%v\n", errors.As(err, &rpcErr), err)
	if result != nil {
		fmt.Printf("isError=%v\n", result.IsError)
	}
}

Observed:

protocolError=false, err=<nil>
isError=true

Expected: protocolError=true, with JSON-RPC code -32602.

Where did you hit this?

Found during local code inspection and reproduced with an in-memory client and server.

Go MCP SDK version

v1.8.0

Go version

go1.26.10 darwin/arm64, also reproduced on main at 0fa5e8407aa3fda65166e4207156c03d084bfd44.

Proposed fix

Use errors.As and return the underlying protocol error.

主要言語
Go
スター
5.3k
フォーク
614
平均マージ
23時間 55分
マージ済み PR(30日)
62

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

modelcontextprotocol/go-sdk のほかの issue

modelcontextprotocol/go-sdk の issue をすべて見る

似ている issue

Go の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。